17.2. dasLLAMA text to speech: models, voices, synthesis
Text to speech in pure daslang: load a converted StyleTTS2-lineage GGUF (KittenTTS nano and
mini, Kokoro-82M), run text through the das-native front end (normalizer, part-of-speech tagger,
grapheme-to-phoneme), and synthesize mono f32 PCM per sentence chunk, timed per model stage.
Run with -jit; utils/dasllama-server/txt2wav.das is the canonical program shape, and
the server’s /v1/audio/speech route serves the same facade.
The front-end packs tts_g2p.bin and tts_postag.bin load from the GGUF’s directory. A
model’s voices and sample rate come from caps; the rows GEMMs serve as Q8_0 by default, and
set_tts_q8 pins the lane for the loads that follow.
Hands-on: the text to speech tutorial.
17.2.1. Constants
- TTS_CHUNK_CHARS = 400
TTS_CHUNK_CHARS:int const
17.2.2. Enumerations
- TtsKind
enum TtsKind
17.2.3. Structures
- TtsModel
A loaded TTS model: the shared assembly, the family’s driver data, and the front-end packs
read beside the GGUF. Load with load_tts_model; delete frees every plane and pack.
- Fields:
kind : TtsKind - the family the GGUF’s architecture named
model : StyleTts2Model = StyleTts2Model() - the shared StyleTTS2-lineage assembly and its voices
scratch : St2Scratch = St2Scratch() - the activation carrier every synthesis reuses
kitten : KittenFamily - the KittenTTS driver data (symbol table, aliases, speed priors)
kokoro : KokoroFamily - the Kokoro driver data (vocabulary)
g2p : G2pModel -
tts_g2p.bin: lexicons, rules and the fallback chaintagger : PosTagger -
tts_postag.bin: the tokenizer and part-of-speech tagger
- TtsCaps
What a loaded TTS model can do: its voices (canonical names; aliases resolve in the family file), the PCM rate it emits, the languages it speaks, whether it clones a voice from audio (none of the first families do).
- Fields:
voices : array<string> - canonical voice names, in the model’s order
voice_langs : array<string> - the language each voice speaks, by index into
voicessample_rate : int - PCM samples per second the model emits
langs : array<string> - the languages it speaks, as codes
cloning : bool - whether a voice can be cloned from audio
- TtsTimings
Where a synthesis spent its time, in microseconds of wall clock, model loading excluded:
the text front end, then each model stage. total_us covers front end through waveform.
- Fields:
front_end_us : int64 - normalize, tag, phonemize, map into the family’s symbols
bert_us : int64 - the PL-BERT pass
text_enc_us : int64 - the text encoder
duration_us : int64 - the duration encoder and the alignment
prosody_us : int64 - F0 and energy
decoder_us : int64 - the decoder
source_us : int64 - the harmonic-plus-noise source
generator_us : int64 - the iSTFTNet generator
total_us : int64 - front end through waveform
samples : int64 - PCM samples produced
- TtsAudio
Synthesized speech: mono f32 PCM at sample_rate, with the time it took.
- Fields:
pcm : array<float> - mono samples in [-1, 1]
sample_rate : int - samples per second
timings : TtsTimings - where the synthesis spent its time
- TtsNoise
The source noise a synthesis consumed - captured from the oracle for a parity run, or drawn from the session’s own generator into a carrier every synthesis reuses.
- Fields:
uniform : array<float> - one initial phase per harmonic; drawn per synthesis into a reused carrier
normal : array<float> - [samples x harmonics], sample-major
captured : bool - supplied by an oracle dump: a synthesis reads it as is and never redraws
17.2.4. Loading and capabilities
- caps(m: TtsModel ): TtsCaps
What the loaded model offers: the canonical voice names the front end can drive, each with its language (a voice whose language it does not phonemize is left out; a family’s aliases resolve at synthesis), the PCM sample rate, the languages, and whether it clones a voice.
- Arguments:
m : TtsModel
- finalize(m: TtsModel )
Free the model’s planes, the carrier and both packs; delete m runs it.
- Arguments:
m : TtsModel
- load_tts_model(path: string ): TtsModel
Load a TTS GGUF (KittenTTS or Kokoro, picked from its architecture); tts_g2p.bin and
tts_postag.bin come from the same directory. The rows GEMMs serve as the lane
tts_serves_q8 names at the time of the load.
- Arguments:
path : string
- tts_voice_lang(m: TtsModel; voice: string ): string
The language the front end reads voice in - a canonical name from caps or a family
alias, resolved the way synthesize resolves it. A voice this model cannot drive panics
here with the message a synthesis would give, rather than making the caller speak a line.
- Arguments:
m : TtsModel
voice : string
17.2.5. Text front end
17.2.5.1. tts_chunks
- tts_chunks(m: TtsModel; norm: string ): array<string>
The chunks a synthesis on this model takes: the family’s own driver rule - Kitten’s appends a comma to a chunk the split left bare, Kokoro’s pipeline sends the text as it is, and its voices render an added mark as an audible breath.
- Arguments:
m : TtsModel
norm : string
- tts_chunks(norm: string; max_len: int = TTS_CHUNK_CHARS; ensure_punct: bool = true ): array<string>
- tts_normalize(text: string ): string
The spoken form of text: the normalization pass every synthesis runs first (rules
alone - it reads no pack), where “Dr.” reads “Doctor”, “3.5” reads “three point five” and
“$12” reads “twelve dollars”.
- Arguments:
text : string
17.2.5.2. tts_phonemize
- tts_phonemize(m: TtsModel; text: string ): string
The phonemes one already-normalized sentence becomes, in the front end’s own American
inventory: the tagger of tts_postag.bin labels the tokens, the grapheme-to-phoneme pass
of tts_g2p.bin reads them. A family wanting other symbols rewrites this string into them.
- Arguments:
m : TtsModel
text : string
- tts_phonemize(m: TtsModel; text: string; lang: string ): string
17.2.6. Synthesis
- synthesize(m: TtsModel; text: string; voice: string; speed: float = 1f ): TtsAudio
Text -> speech: normalize, chunk by sentence, phonemize, map into the family’s symbols,
synthesize; the chunks concatenate, the timings sum. Sample-identical to
synthesize_stream over the same text.
- Arguments:
m : TtsModel
text : string
voice : string
speed : float
- synthesize_stream(m: TtsModel; text: string; voice: string; speed: float; blk: block<(chunk:TtsAudio):auto> ): auto
Text -> speech, one sentence-sized chunk at a time: the block receives each chunk’s audio as
soon as it exists, in order. Normalization runs once over the whole text; voice is a
name from caps or a family alias, and an unknown one panics.
17.2.7. The served lane
- reset_tts_q8()
Drop the set_tts_q8 pin: the next load follows the policy default again.
- set_tts_q8(on: bool )
Pin the rows GEMMs’ format for subsequent TTS loads: Q8_0 quants (their own prepared image
beside the GGUF) or the file’s f32 planes; reset_tts_q8 returns to the policy default.
The pin is per context: a worker thread pins for itself.
- Arguments:
on : bool
- tts_serves_q8(): bool
Would the next TTS load serve its rows GEMMs as q8 - the pin when set, the policy otherwise.
17.2.8. Timings
- rtf(t: TtsTimings; sample_rate: int ): double
Real-time factor: generation seconds per second of audio produced.
- Arguments:
t : TtsTimings
sample_rate : int
- timings_line(t: TtsTimings; sample_rate: int ): string
One line for the log: seconds of audio, wall time, RTF and the per-stage split in ms.
- Arguments:
t : TtsTimings
sample_rate : int