Skip to content

Text to speech (TTS)

Text to speech generates spoken audio for a dialogue's lines automatically, so you can hear a dialogue play before any voice actor is recorded. It is not a replacement for recorded voice — it is a fast, cheap placeholder that lets you review timing, staging and cameras with real audio in the sequence.

TTS runs as an asset generator during generation: asset generators run before the track generators, and the audio they produce is then consumed by the LBRAudioTrackGenerator when it fills the audio track. See the generation overview for where TTS sits in the pipeline and where the audio is written.

What gets a voice

TTS is generated for Text lines only, and only when the line has a Speaker. In code the generator skips any line whose type is not Text or that has no speaker (Dialogue->Types[Index] != ELBRLineType::Text || !Dialogue->Speakers[Index]).

Voicing the player

Player responses are authored as Reply lines, and Replies get no TTS. To voice the player, add real Text lines spoken by the player character (for example inside a Choice, or after it) — those are the only player lines that produce audio.

Already-generated audio is not rebuilt on a normal run; set the Force flag on asset generation to overwrite stale audio after editing dialogue text (see Running generation).

Mount-aware output

Where the audio lands is handled by the generation pipeline, not by the providers: output is mount-aware, so a dialogue delivered inside a plugin generates its TTS next to its sequences inside that plugin instead of /Game. See the mount-aware output note rather than repeating it here.

Providers at a glance

Libretto ships with two working providers.

Provider Where it runs Network Cost Voice quality Setup
MSVoice Local (Windows speech API, SAPI) None Free Basic, robotic None — ships wired in the plugin .ini
ElevenLabs Cloud (ElevenLabs API) Required Paid (API quota) High, natural API token + a character→voice DataTable

The active provider is simply whichever TTS asset generator you tick in the Generate Assets wizard. Both LBRMSVoiceGenerator and LBRElevenLabsGenerator are registered by default in the Asset Generators list.

Settings

All TTS configuration lives in Project Settings ▸ Libretto – Text To Speech (ULBRTextToSpeechSettings):

Setting Section Purpose
Text To Speech Subsystem Config Name of the TTS subsystem to use (chosen from the installed options).
ElevenLabs API Token ElevenLabs Token for the ElevenLabs API — required to spend your own character quota.
Character Voices Table ElevenLabs DataTable mapping each character to an ElevenLabs voice.
Default TTS Culture MSVoice Default language / locale (e.g. en-US) used when a character row does not specify one — drives both voice pick and spoken language. Defaults to en-US.
MSVoice Character Table MSVoice DataTable (rows of FLBRMSVoiceCharacterDesc) mapping each character to a Windows voice / language / prosody.

The Text To Speech project settings

Defaults ship in the plugin .ini

ULBRTextToSpeechSettings uses Config = "Libretto", so its shipped defaults live in the plugin's DefaultLibretto.ini (Unreal only merges that one config file for a plugin, so a TextToSpeech-named config would never load). The plugin ships:

[/Script/LBRTextToSpeechEditor.LBRTextToSpeechSettings]
DefaultTTSCulture=en-US
MSVoiceCharacterTable=/Libretto/Examples/Characters/DT_MSVoices.DT_MSVoices

The MSVoiceCharacterTable points at example content shipped with the plugin as a soft reference. API tokens stay empty in the .ini — set them per project through Project Settings.

MSVoice — local Windows voices

ULBRMSVoiceGenerator produces audio with the Windows speech API (SAPI 5, called in process). It is local and free, needs no network, and works out of the box — which makes it the natural default for day-to-day iteration.

How a voice is picked

For each Text line, MSVoice resolves the speaker's voice, language and prosody, then builds an SSML document and synthesises it:

  1. If the speaker has a row in the MSVoice Character Table, that row's voice / culture / prosody is used.
  2. Otherwise the generator auto-picks a voice by the character's gender — read from the LBRDialogueCharacter interface via ILBRDialogueCharacter::LBRGetCharacterGender — combined with the culture. This is still fully valid: the language is correct, just without an explicit voice or prosody.

The SSML it builds looks like this (a gendered auto-pick, then an explicit voice by name):

<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="en-US">
  <voice gender="male" xml:lang="en-US">
    <prosody pitch="-20%" rate="-6%">Your line text here.</prosody>
  </voice>
</speak>

The character table (DT_MSVoices)

Each row of the MSVoice table is a FLBRMSVoiceCharacterDesc:

Field Purpose
Character Class The dialogue character this row applies to.
Voice Name An explicit installed Windows voice (e.g. Microsoft David Desktop). Leave empty to auto-pick the best installed voice for the character's gender + culture — portable across machines.
Culture Voice language / locale (e.g. en-US, fr-FR). Empty falls back to Default TTS Culture.
Pitch Percent Relative pitch offset, percent (e.g. -20 = lower). Clamped to −100…100.
Rate Percent Speaking-rate offset, percent (e.g. -6 = slower). Clamped to −90…200.

The DT_MSVoices character DataTable

Let the culture follow the generation culture

Leave a row's Culture empty so the voice follows the generation culture (via Default TTS Culture). Filling it pins that character to a specific language regardless of the culture you generate — useful for a foreign-speaking character, unhelpful otherwise.

Two characters, one voice, told apart by prosody

A typical machine has only two English (en-US) SAPI voices installed (David and Zira). Two male en-US characters therefore both map to David. Differentiate them with Pitch Percent and Rate Percent: give one a lower pitch and/or a different rate so the two are audibly distinct even though they share the underlying voice.

Installing more voices

Voice availability depends on the machine's installed Windows language / speech packs. If you only have two voices, install additional SAPI voices via Windows Settings ▸ Time & Language ▸ Speech to widen the pool the auto-pick can draw from.

ElevenLabs — cloud, high quality

ULBRElevenLabsGenerator calls the ElevenLabs cloud API. It produces the most natural audio of the three, at the cost of a network connection and a paid quota.

To use it:

  1. Put your ElevenLabs API Token in the TTS settings.
  2. Set the Character Voices Table — a DataTable mapping each character to an ElevenLabs voice and its voice settings (stability, similarity, speed, style, speaker boost).

The ElevenLabs Character Voices DataTable

ElevenLabs row type

The Character Voices Table is a DataTable whose row struct is FLBRElevenLabsCharacterDesc — it maps a character class to a name, a voice id, and an embedded FLBRElevenLabsVoiceSettings (the voice parameters). Create your table with that row type.

Quota and cost

Every generated line spends ElevenLabs quota. Because a full dialogue regenerates many lines, prefer generating only what you need (per-subdialogue selection, and rely on the skip already-generated behaviour rather than Force). TTS also makes generation noticeably slower — see the warning on the overview page.