Overview
PollyVoice gives your game a voice for any text known only at runtime: player names, procedural quests, AI-generated dialogue, accessibility narration, or simply thousands of lines you do not want to record. Requests run on background worker threads with automatic retries; every result arrives on the game thread.
- Synthesize Speech: text or SSML to a
UPollyVoiceSoundWave (16-bit PCM, 8 or 16 kHz) that plays like any sound: Standard, Neural, Long-Form and Generative engines, language codes, lexicons.
- Synthesize With Speech Marks: the sound plus viseme, word, sentence and SSML marks; Get Speech Marks for timings only.
- Synthesize And Play 2D / At Location, Synthesize To File (MP3, Ogg Vorbis, PCM, WAV), Preload Phrases.
UPollyVoiceLipSyncComponent: plays speech, drives viseme morph targets with smooth blending and fires On Viseme, On Word, On Sentence, On SSML Mark and On Finished.
- 17 pure SSML builder nodes: breaks, emphasis, prosody, max duration, say-as, phonemes, aliases, languages, marks, whisper, newscaster style and more.
- Memory + disk cache keyed by text and voice settings: a line is paid for once, then plays instantly, even after a restart.
- Voices, lexicons and asynchronous S3 synthesis tasks; Amazon Cognito identity pools, static keys or the default AWS chain.
Requirements
| Requirement | Details |
| Unreal Engine | 4.27 and 5.8 |
| Platforms | Win64, Linux and Android |
| Modules | PollyVoice (Runtime), PollyVoiceSdk (prebuilt AWS SDK for C++ 1.11.916 in Source/ThirdParty) |
| Dependencies | No other plugins. On Linux and Android the SDK uses the engine's libcurl, OpenSSL and certificate store. |
| AWS | An AWS account. Polly bills per character synthesized (speech marks are billed like audio); cached lines cost nothing. |
Installation
- Install PollyVoice from Fab into your engine, or copy the
PollyVoice folder into your project's Plugins folder.
- Enable PollyVoice in Edit > Plugins and restart the editor.
- Open Project Settings > Plugins > PollyVoice: set Region, Identity Pool Id and a Default Voice.
- C++ only: add
PublicDependencyModuleNames.Add("PollyVoice"); to your Build.cs.
Several AWS plugins in one projectEach Alpha XP cloud plugin carries its own copy of the SDK under a plugin-specific name, so they install side by side without conflicts.
Setting up AWS
- Pick a region where Polly offers the voices you need (Neural and Generative voices are not in every region).
- In Amazon Cognito create an identity pool. Enable guest access if players may hear speech before signing in.
- Give the pool's player role (guest and/or authenticated) only what the game client needs — synthesis, voices and reading lexicons:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PollyVoicePlayers",
"Effect": "Allow",
"Action": ["polly:SynthesizeSpeech", "polly:DescribeVoices"],
"Resource": "*"
},
{
"Sid": "PollyVoiceReadLexicons",
"Effect": "Allow",
"Action": ["polly:GetLexicon", "polly:ListLexicons"],
"Resource": "arn:aws:polly:us-east-1:123456789012:lexicon/*"
}
]
}
To limit players to your own lexicons, replace lexicon/* with names such as lexicon/MyGame* (a request that names a lexicon is checked against that lexicon's ARN).
Admin and tool nodes
Put Lexicon, Delete Lexicon and the three synthesis-task nodes are meant for editor tools, build pipelines and servers. Give them a separate role or user, never the player role:
{
"Version": "2012-10-17",
"Statement": [
{ "Effect": "Allow", "Action": ["polly:PutLexicon", "polly:DeleteLexicon"],
"Resource": "arn:aws:polly:us-east-1:123456789012:lexicon/MyGame*" },
{ "Effect": "Allow", "Action": ["polly:StartSpeechSynthesisTask", "polly:GetSpeechSynthesisTask", "polly:ListSpeechSynthesisTasks"],
"Resource": "*" },
{ "Effect": "Allow", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::my-voice-bucket/voice/*" },
{ "Effect": "Allow", "Action": "sns:Publish", "Resource": "arn:aws:sns:us-east-1:123456789012:voice-done" }
]
}
Polly writes task output with the caller's permissions, so the caller needs s3:PutObject on the output bucket (and sns:Publish when a topic is given).
Never ship access keysStatic keys in the settings end up in DefaultGame.ini and in packaged games. Use them only for development, editor tools and servers; players should use the identity pool. Shipping builds refuse settings keys unless Allow Static Keys In Shipping is enabled.
Quick start
1. Say something
- Add Synthesize And Play 2D to Begin Play. Text
Welcome back, commander., Options empty (uses the Default Voice).
- From On Failure print Error > Message. Done: the line plays; the second time it plays straight from the cache.
2. A talking character
- Add a Poly Voice Lip Sync component to your character. In its details set Viseme Map from Make Default Viseme Map (or type your own morph target names).
- Call Synthesize With Speech Marks with the line and Options.Voice =
Matthew.
- On Success: Play Speech on the component with Speech > Sound (leave Marks empty — they are stored in the sound).
- Bind On Word to highlight subtitle words and On Finished to continue the dialogue.
3. Expressive lines with SSML
Build Make SSML Document( SSML Prosody( "Get down", Rate 120 ) + SSML Break(Strong) + SSML Amazon Effect( "they can hear us", Whispered ) ) and pass it as Text — Text Type Auto recognises the <speak> document.
4. Loading screen
Call Preload Phrases with every line of the level. During gameplay use Get Cached Sound (instant, no network) or Synthesize Speech (also instant for cached lines).
Lip sync
Polly reports a viseme (mouth shape) code with a start time for every sound of the speech: p t S T f k i r s u @ a e E o O sil (codes are case-sensitive). Build Timeline adds end times; Evaluate Morph Weights turns the timeline into morph-target weights at any time, blending each shape into the next over Blend Time. The lip-sync component does this every frame and applies the weights to the owner's first skeletal mesh (or the mesh given to Set Target Mesh).
- Sync Offset (default 0.05 s) moves the mouth slightly ahead of the audio to hide output latency.
- Use Build Viseme Curves to bake float curves (time → weight) for Sequencer, Timelines or an Animation Blueprint instead of the component.
- Lip sync without playing audio: Play Timeline, for example for audio from a synthesis task with marks from Get Speech Marks.
- Export Subtitles SRT writes SRT subtitles from the sentence (or word) marks.
SSML builder
Every builder node wraps a fragment in one tag, so builders chain. Send player-typed text through Escape Text For SSML first. Neural and Generative voices ignore some tags (emphasis, pitch, whisper); Polly rejects invalid SSML with InvalidSsmlException.
Cache
Every synthesized line is stored under a key made from the text, voice, engine, language, lexicons, sample rate and text type. The memory cache (default 32 MB, least recently used lines dropped first) makes repeats instant; the disk cache (default 256 MB in Saved/PollyVoice) keeps lines across sessions as <key>.wav + <key>.json (speech marks). Speech marks are cached per type, so asking for visemes after words only requests the visemes. Set Bypass Cache in the options for one-off lines.
Shipping pre-baked voiceRun your lines once with the disk cache enabled and ship the cache folder, or bake files with Synthesize To File.
Node reference
85 nodes. Call = executable, Pure = no exec pins, Latent = async node with output pins (each fires exactly once on the game thread; Cancel on its return value stops it).
Synthesis
| Node | Kind | Inputs | Outputs | Purpose |
| Synthesize Speech | Latent | Text, Options | On Success / On Failure (Speech, Error) | Text or SSML to a playable sound, from the cache when possible. |
| Synthesize With Speech Marks | Latent | Text, Options, Mark Types | On Success / On Failure (Speech, Error) | Sound plus speech marks (empty Mark Types = visemes, words, sentences and SSML marks). |
| Get Speech Marks | Latent | Text, Options, Mark Types | On Success / On Failure (Marks, Error) | Timings only, no audio. |
| Synthesize To File | Latent | Text, Options, Format, File Path | On Success / On Failure (File Path, Billed Characters, Error) | MP3, Ogg Vorbis, raw PCM or WAV on disk (relative paths below Saved). |
| Synthesize And Play 2D | Latent | Text, Options, Volume, Pitch | On Started / On Failure (Audio Component, Speech, Error) | Synthesizes and plays a 2D line. |
| Synthesize And Play At Location | Latent | Text, Options, Location, Attenuation, Volume, Pitch | On Started / On Failure (Audio Component, Speech, Error) | Synthesizes and plays a line in the world. |
| Count Billable Characters | Pure | Text | Integer | Characters Polly bills (SSML tags are free). |
Cache
| Node | Kind | Inputs | Outputs | Purpose |
| Preload Phrases | Latent | Texts, Options, With Speech Marks, Max Concurrency | On Progress (Done, Total), On Completed (Loaded Count, Failed Texts, First Error) | Fills the cache in parallel; cached lines are skipped. |
| Get Cached Sound | Call | Text, Options | Sound or None | The cached sound without any network access. |
| Is Cached | Pure | Text, Options | Boolean | True when the line is in the memory or disk cache. |
| Remove From Cache | Call | Text, Options | – | Forgets one line (memory and disk). |
| Clear Cache | Call | Memory, Disk | – | Empties one or both caches. |
| Set Cache Directory | Call | Directory | – | Moves the disk cache (relative = below Saved). |
| Set Cache Limits | Call | Memory MB, Disk MB | – | Changes the budgets (0 keeps a value). |
| Get Cache Stats | Pure | – | Cache Stats | Entries, bytes and limits of both caches, folder path. |
Lip sync component (UPollyVoiceLipSyncComponent)
| Node | Kind | Inputs | Outputs | Purpose |
| Play Speech | Call | Sound, Marks | Audio Component | Plays a sound (3D attached to the owner, or 2D) and lip-syncs it; empty Marks = the marks stored in a PollyVoice sound. |
| Play Timeline | Call | Timeline | – | Lip sync and events without audio. |
| Stop | Call | – | – | Stops audio and lip sync, resets the mouth, fires On Finished. |
| Is Playing | Pure | – | Boolean | True while speech or a timeline runs. |
| Get Current Viseme | Pure | – | String | Viseme code shown now ("sil" when silent). |
| Get Current Word | Pure | – | String, Word Index | Word spoken now. |
| Get Playback Time | Pure | – | Float | Seconds since the speech started. |
| Set Target Mesh | Call | Mesh | – | Drives another skeletal mesh (for example a head). |
| Set Viseme Map | Call | New Map | – | Replaces the viseme map and resets old morph targets. |
| Get Morph Weights | Pure | – | Morph Weights | Weights applied this frame (to drive an Animation Blueprint yourself). |
| On Viseme / On Word / On Sentence / On SSML Mark / On Finished | Event | – | Viseme + Duration / Word + Index / Text / Mark Name / – | Component events (not counted as nodes). |
Lip sync and timing helpers
| Node | Kind | Inputs | Outputs | Purpose |
| Build Timeline | Pure | Marks, Duration | Timeline | Viseme / word / sentence / mark lists with start and end times. |
| Get Viseme At Time | Pure | Timeline, Time | Boolean, Viseme, Progress | Active viseme and progress through it. |
| Get Word At Time | Pure | Timeline, Time | Boolean, Word, Word Index | Word spoken at a time. |
| Get Sentence At Time | Pure | Timeline, Time | Boolean, Sentence | Sentence spoken at a time (subtitle line). |
| Parse Speech Marks | Pure | JSON Lines | Boolean, Marks | Reads Polly's JSON-lines mark format (task output files). |
| Make Default Viseme Map | Pure | Prefix | Viseme Map | Maps Polly visemes to PP, FF, TH, DD, kk, CH, SS, RR, aa, E, ih, oh, ou morph names. |
| Map Viseme To Morph Targets | Pure | Viseme, Viseme Map | Morph Weights | Morph targets one viseme drives. |
| Evaluate Morph Weights | Pure | Timeline, Viseme Map, Time, Blend Time, Intensity | Morph Weights | Blended weights of every morph of the map at a time. |
| Build Viseme Curves | Call | Outer, Timeline, Viseme Map, Blend Time | Morph Curves | One float curve per morph target. |
| Apply Morph Weights | Call | Mesh, Weights | – | Sets the morph targets on a skeletal mesh. |
| Export Subtitles SRT | Pure | Timeline, Max Characters | String | SRT subtitles from sentence (or word) marks. |
SSML builder
| Node | Kind | Inputs | Outputs | Purpose |
| Make SSML Document | Pure | Body | String | Wraps a fragment in <speak>. |
| SSML Break | Pure | Strength, Time Ms | String | A pause of a strength or an exact length. |
| SSML Emphasis | Pure | Text, Level | String | Stressed words (standard voices). |
| SSML Prosody | Pure | Text, Rate %, Pitch %, Volume dB | String | Speed, pitch and loudness. |
| SSML Max Duration | Pure | Text, Seconds | String | Fits a line into a time slot. |
| SSML Say As | Pure | Text, Interpret As, Format | String | Characters, numbers, dates, times, addresses, phone numbers, bleeps. |
| SSML Phoneme | Pure | Text, Phonetic, X-SAMPA | String | Exact pronunciation in IPA or X-SAMPA. |
| SSML Sub | Pure | Text, Alias | String | Speaks an alias instead of the text. |
| SSML Language | Pure | Text, Language Code | String | Foreign phrase with the current voice. |
| SSML Paragraph | Pure | Text | String | Paragraph with its pause. |
| SSML Sentence | Pure | Text | String | Sentence with its pause and sentence mark. |
| SSML Mark | Pure | Name | String | Named point reported as an SSML speech mark. |
| SSML Amazon Effect | Pure | Text, Effect | String | Whispered, soft phonation or dynamic range compression. |
| SSML Speaking Style | Pure | Text, Style | String | Newscaster or conversational (supported neural voices). |
| Escape Text For SSML | Pure | Text | String | Makes any text safe inside SSML. |
| Append SSML | Pure | Document, Fragment | String | Adds a fragment inside a document's </speak>. |
| Strip SSML Tags | Pure | SSML | String | Spoken text without tags (subtitles). |
Sounds and audio files
| Node | Kind | Inputs | Outputs | Purpose |
| Create Sound Wave From Pcm | Call | PCM, Sample Rate, Num Channels | Sound | A playable sound from your own 16-bit samples. |
| Save PCM As WAV | Call | PCM, Sample Rate, Num Channels, File Path | Boolean | Writes a WAV file. |
| Load WAV As Sound Wave | Call | File Path | Sound, Problem | Plays WAV files from disk at runtime (8/16/24/32-bit PCM, float). |
| Get Pcm Data | Pure | Target: PollyVoice Sound | Bytes | The sound's 16-bit PCM. |
| Get Sound Speech Marks | Pure | Target: PollyVoice Sound | Marks | Speech marks stored in the sound. |
| Get Timeline | Pure | Target: PollyVoice Sound | Timeline | The sound's marks as a timeline. |
| Get Spoken Text | Pure | Target: PollyVoice Sound | String, Voice Id | Text and voice the sound was made from. |
Voices
| Node | Kind | Inputs | Outputs | Purpose |
| Describe Voices | Latent | Language Code, Engine, Include Additional Languages | On Success / On Failure (Voices, Error) | Voices of the region, filtered. |
| Get Voice Info | Latent | Voice Id | On Success / On Failure (Voice, Error) | One voice's gender, languages and engines ("VoiceNotFound" when unknown). |
| Find Voices For Language | Pure | Voices, Language Code, Engine, Gender, Include Bilingual | Voices | Filters a voice list locally, for example for a voice picker. |
Lexicons
| Node | Kind | Inputs | Outputs | Purpose |
| Put Lexicon | Latent | Name, PLS Content | On Success / On Failure (Error) | Stores a pronunciation lexicon (admin). |
| Get Lexicon | Latent | Name | On Success / On Failure (Lexicon, Content, Error) | Downloads a lexicon. |
| List Lexicons | Latent | – | On Success / On Failure (Lexicons, Error) | All lexicons of the region. |
| Delete Lexicon | Latent | Name | On Success / On Failure (Error) | Deletes a lexicon (admin). |
Synthesis tasks (S3)
| Node | Kind | Inputs | Outputs | Purpose |
| Start Speech Synthesis Task | Latent | Text, Options, Format, Output Bucket, Key Prefix, SNS Topic Arn, Mark Types | On Success / On Failure (Task, Error) | Long text (up to 100,000 characters) to an S3 file (admin). |
| Get Speech Synthesis Task | Latent | Task Id | On Success / On Failure (Task, Error) | Status and output URI of a task. |
| List Speech Synthesis Tasks | Latent | Status, Max Results, Next Token | On Success / On Failure (Tasks, Next Token, Error) | One page of tasks. |
Config and identity
| Node | Kind | Inputs | Outputs | Purpose |
| Set Region | Call | Region | – | Region for every following request. |
| Set Credential Mode | Call | Mode | – | Overrides the credential mode at runtime. |
| Set Login Token | Call | Provider, Token | – | Signs the player in to the identity pool. |
| Clear Login Tokens | Call | – | – | Back to a guest identity. |
| Set Static Credentials | Call | Access Key Id, Secret Access Key, Session Token | – | Keys from your backend (Static Keys mode). |
| Get Identity Id | Pure | – | String | The player's Cognito identity id. |
| Make User Pool Provider Name | Pure | Region, User Pool Id | String | Login key of a Cognito user pool. |
| Is Configured | Pure | – | Boolean, Problem | False with a reason when settings are incomplete. |
| Resolve Identity | Latent | Force Refresh | On Success / On Failure (Identity Id, Error) | Fetches credentials ahead of the first request. |
| Set Default Voice | Call | Voice Id | – | Runtime default voice. |
| Set Default Engine | Call | Engine | – | Runtime default engine. |
| Set Default Language | Call | Language Code | – | Runtime default language code. |
| Set Default Sample Rate | Call | Sample Rate | – | Runtime default sample rate. |
| Cancel | Call | Target: latent node | – | None of the node's pins fire any more. |
| Is Finished | Pure | Target: latent node | Boolean | True after the node finished or was cancelled. |
Credentials
| Mode | Use for | How |
| Cognito Identity Pool | Game clients | Guests get unauthenticated credentials; after Set Login Token the player gets the authenticated role. Credentials refresh automatically. |
| Static Keys | Development, editor tools, servers | Settings keys or Set Static Credentials. |
| Default Credential Chain | Servers and build tools | Environment variables, the ~/.aws profile, ECS and EC2 roles. |
C++ API
// Build.cs: PublicDependencyModuleNames.Add("PollyVoice");
#include "PollyVoiceLibrary.h"
#include "PollyVoiceSoundWave.h"
FPollyVoiceSynthesisOptions Options;
Options.Voice = TEXT("Amy");
UPollyVoiceLibrary::SynthesizeNative(TEXT("Hello there."), Options, /*bWithSpeechMarks*/ true,
FPollyVoiceNativeDelegate::CreateLambda([this](const FPollyVoiceSpeech& Speech, const FPollyVoiceError& Error)
{
// game thread; keep Speech.Sound referenced (UPROPERTY) or play it now
if (Speech.Sound) { LipSync->PlaySpeech(Speech.Sound, Speech.Marks); }
}));
The latent node classes (UPollyVoiceSynthesizeAction and the others) can also be created from C++ through their static factory functions; bind the delegates, then call Activate().
Types
| Type | Kind | Members |
| FPollyVoiceSynthesisOptions | Struct | Voice, Engine, Language Code, Lexicons, Sample Rate, Text Type, Bypass Cache (all optional) |
| FPollyVoiceSpeech | Struct | Sound, Marks, Duration, Sample Rate, Billed Characters, From Cache, Cache Key, Voice |
| FPollyVoiceSpeechMark | Struct | Type, Time (s), Start / End Offset, Value |
| FPollyVoiceTimeline / FPollyVoiceTimedItem | Struct | Visemes, Words, Sentences, SSML Marks, Duration / Start, End, Value, offsets |
| FPollyVoiceVisemeMapping / MorphWeight / MorphCurve | Struct | Viseme, Morph Target, Weight / Morph Target, Weight / Morph Target, Curve |
| FPollyVoiceVoiceInfo | Struct | Id, Name, Gender, Language Code, Language Name, Additional Language Codes, Supported Engines |
| FPollyVoiceLexiconInfo | Struct | Name, Alphabet, Language Code, Last Modified, Arn, Lexeme Count, Size |
| FPollyVoiceTask | Struct | Task Id, Status, Status Reason, Output Uri, Creation Time, Request Characters, SNS Topic, format, voice, engine, language, lexicons, mark types |
| FPollyVoiceCacheStats | Struct | Memory / disk entries, bytes and limits, directory |
| FPollyVoiceError | Struct | Code, Message, Http Status, Retryable |
| UPollyVoiceSoundWave | Class | Runtime sound wave from PCM; keeps marks, text and voice |
| Enums | Enum | Engine, Text Type, File Format, Mark Type, Gender, Task Status, Break Strength, Emphasis, Say As, Effect, Speaking Style, Credential Mode |
Settings
Project Settings > Plugins > PollyVoice (saved to DefaultGame.ini). Changes apply to the next request.
| Setting | Default | Description |
| Region | us-east-1 | Region of Polly and the identity pool. |
| Credential Mode / Identity Pool Id / Allow Guest Access | Cognito / (empty) / On | Where credentials come from. |
| Access Key Id / Secret Access Key / Allow Static Keys In Shipping | (empty) / Off | Static Keys mode, development and servers only. |
| Endpoint Override, timeouts, Max Retries, Worker Threads, Verify SSL, Log Sdk Warnings | – / 30000 / 5000 / 3 / 4 / On / On | Connection. |
| Default Voice | Joanna | Voice when a request leaves Voice empty. |
| Default Engine | Neural | Engine for "Project Default". |
| Default Language Code | (empty) | For bilingual voices. |
| Default Sample Rate | 16000 | 8000 or 16000 for sounds; MP3 / Ogg files also 22050, 24000. |
| Memory Cache / Max Memory Cache MB | On / 32 | In-memory line cache. |
| Disk Cache / Cache Directory / Max Disk Cache MB | On / PollyVoice / 256 | Disk cache below Saved. |
Engine notes
- UE 4.27: PollyVoice sounds play from in-memory PCM (like editor previews). Looping, attenuation, concurrency and sound classes work as usual.
- UE 5.8: PollyVoice sounds stream through a sound generator, one per playing instance, so the same sound can play several times at once.
- Sounds are created at runtime and are not assets: keep them in a variable (or a UPROPERTY in C++) as long as you want to replay them; the cache recreates them cheaply.
- Polly returns mono 16-bit PCM at 8 or 16 kHz for playable sounds; use Synthesize To File with MP3 / Ogg at 22050 or 24000 Hz for higher fidelity assets.
- Text limits per request: 3,000 billed characters (6,000 total with SSML tags). Use a synthesis task for longer text.
Troubleshooting
| Error code | Cause and fix |
NotConfigured | Set the Identity Pool Id in Project Settings > Plugins > PollyVoice, or switch the credential mode. |
AccessDeniedException | The role lacks polly:SynthesizeSpeech (or the lexicon / task permission). See Setting up AWS. |
ValidationException / EngineNotSupportedException | The voice does not support the engine (for example a Standard-only voice with Neural) or the region lacks it. Check with Get Voice Info. |
InvalidSsmlException | Broken SSML. Escape player text with Escape Text For SSML; check that tags are supported by the voice's engine. |
TextLengthExceededException | Over 3,000 billed characters: split the text or use Start Speech Synthesis Task. |
LexiconNotFoundException | A lexicon named in Options does not exist in this region. |
InvalidSampleRateException | Use 8000 or 16000 for sounds and PCM / WAV, or up to 24000 for MP3 / Ogg files. |
NoAudio | Synthesize And Play could not play: no world, no audio device (dedicated server) or audio disabled. |
CacheDisabled | Preload Phrases needs the memory or the disk cache. |
Unavailable | The SDK library could not be loaded or the engine is shutting down. Check the Output Log for LogPollyVoice errors. |
Credits
© 2026 Alpha XP — alphaxp.net · Support: support@alphaxp.net.
Includes the AWS SDK for C++ and the AWS Common Runtime (Apache License 2.0). Amazon Polly is a service of Amazon Web Services. Built for Unreal Engine 4.27 and 5.8.