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 }:
| field | description |
|---|---|
ph | an ARPAbet phoneme from sound.speech.phonemes, or "SIL" for a pause |
stress | 0, 1 or 2 |
dur | duration, ms |
f0 | pitch, 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.
| Module | Description |
|---|---|
| sound.speech.g2p | English grapheme-to-phoneme for sound.speech. |
| sound.speech.klatt | A cascade/parallel formant synthesizer, simplified from Klatt (1980). |
| sound.speech.phonemes | The phoneme table for sound.speech: about 40 English phonemes in ARPAbet, with the acoustic targets the synthesizer renders. |
| sound.speech.prosody | Prosody for sound.speech. |
| sound.speech.text | Text normalization for sound.speech. |
| sound.speech.voices | Voice presets for sound.speech: named sets of the synthesis knobs. |
| Name | Signature |
|---|---|
| phonemize | phonemize(s, opts) -> events, err |
| synth | synth(events, opts) -> buf, info/err |
| say | say(s, opts) -> buf, info/err |
| say_job | say_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 field | default | description |
|---|---|---|
voice | "narrator" | preset name or knob table |
rate | 16000 | output sample rate; pass dev:rate() |
| any knob | the voice's | overrides 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:
buf, info: done. The final step resamples to opts.rate.false, err: failed. The job is dead.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.