sound.speech

index ยท sound

Overview

English text-to-speech: text in, a mono sample buffer out.

phonemize turns text into phoneme events. synth renders events into a buffer. say does both. An event is { ph, stress, dur, f0 }:

fielddescription
phan ARPAbet phoneme from sound.speech.phonemes, or "SIL" for a pause
stress0, 1 or 2
durduration, ms
f0pitch, Hz

Edit events between phonemize and synth to change timing or pitch, to fix a pronunciation, or to write chants and alarms by hand. The prosody pass fills only the dur and f0 an event lacks; it never rescales a value set by hand.

opts.voice is a preset name from speech.voices (default "narrator") or a knob table. A knob set directly in opts overrides the voice: { voice = "computer", f0 = 70 }. sound.speech.voices lists the knobs.

The synthesizer renders at 16 kHz (speech.RATE). opts.rate resamples the result; pass dev:rate(). The same text and opts always give the same samples.

Submodules

ModuleDescription
sound.speech.g2pEnglish grapheme-to-phoneme for sound.speech.
sound.speech.klattA cascade/parallel formant synthesizer, simplified from Klatt (1980).
sound.speech.phonemesThe phoneme table for sound.speech: about 40 English phonemes in ARPAbet, with the acoustic targets the synthesizer renders.
sound.speech.prosodyProsody for sound.speech.
sound.speech.textText normalization for sound.speech.
sound.speech.voicesVoice presets for sound.speech: named sets of the synthesis knobs.

Functions

NameSignature
phonemizephonemize(s, opts) -> events, err
synthsynth(events, opts) -> buf, info/err
saysay(s, opts) -> buf, info/err
say_jobsay_job(s, opts) -> job, err

phonemize(s, opts) -> events, err

Transcribe text into editable phoneme events

Runs text normalization, grapheme-to-phoneme and prosody with the voice opts resolves. Every returned event has ph, stress, dur and f0. Returns nil and an error for an unknown voice, or for text with no words.

synth(events, opts) -> buf, info/err

Render phoneme events into a sample buffer

Renders a list from phonemize or written by hand. The prosody pass fills a missing dur or f0 in place. opts takes voice, the knobs and rate, as say does.

info is { rate, dur, frames, events }; dur is in seconds. Returns nil and an error for an unknown voice or an empty list.

say(s, opts) -> buf, info/err

Speak: text in, sample buffer out

synth(phonemize(s, opts), opts).

opts fielddefaultdescription
voice"narrator"preset name or knob table
rate16000output sample rate; pass dev:rate()
any knobthe voice'soverrides that knob of the voice

say_job(s, opts) -> job, err

Speak incrementally: a sliced render job

say in slices, for a caller inside an event loop. A long line takes tens of milliseconds to render. One say call holds the thread that long, so an audio writer starves and a frame stalls. A job does the same work a slice at a time.

Each job.step() renders opts.yield_every parameter frames, default 40: about 200 ms of speech for about 1 ms of work. The knob is the job's alone; say and synth render whole and ignore it. step returns:

A step after the end returns the same result again. job.done() reports the end without stepping. The output is the same bytes say(s, opts) gives.