Candy Logo Copyright © 2025-2026 Candy Arts

TTS
Spoken Lines can be voiced by Text-To-Speech (TTS): audio generated from their text, instead of recorded voice files. TTS works in every Dialogue Mode, and is played by the same Voice Players as voice files (see Voice). Implementation TTS Engine Candy Dialogue Engine doesn't generate speech itself: your game must, through a TTS library, plugin or online API. Once it does, the Engine requests the voice of Spoken Lines through your code. Basic Method For a Line that uses TTS, the Engine chooses the text to read, calls the tts() function of the Tts.gd script (User_Data/Functions, a 'safe' file: updates never overwrite it), waits for it to return, and plays the audio it returns. tts() is only called for Lines that are voiced (enable_voice) and whose TTS mode isn't "Off". Detailed Method tts() contains one case per TTS mode (see TTS Modes below). Where it says #TODO: Hook to your TTS implementation, the function must: 1. Send the text to read (text) to your TTS engine, along with any other data it requires, such as the speaker's voice. 2. Wait for the generated audio. 3. Return the audio to the Engine. Return Value tts() can return: • An AudioStream: it's played as-is. • The path of an audio file, in res:// or user://: the file is loaded and played. Generated audio is usually saved in user://, which is writable in an exported game. • null: TTS didn't run, and the Line's voice file is played instead, if it has one. A path to a file that can't be loaded is treated like null. Arguments Like every hook function, tts() receives three arguments: candy_args, user_args and custom_data (see Hook Functions). candy_args contains the Engine's own values: • "caller": the Engine running the Line. • "mode": the name of the Line's TTS mode ("Simple", "Advanced" or one of your own), resolved from the Engine, UI Element, Actor and Line settings. When "Advanced" falls back (see Fallback below), it's the fallback mode. • "text": the text to read. In "Advanced" mode, the Line's TTS Variation. In any other mode, the Line's text as it's displayed, without its BBCode tags. • "speaker_ref": the Actor Reference of the speaker (e.g. "Alice"). Use it to assign each Actor a voice of their own. • "raw_dialogue": the Line's text, as it's displayed: Variation chosen, variables, Word Substitution, Lexicon and LLM applied. BBCode tags remain present. • "tts_variation_text": the text of the Line's TTS Variation, variables and Word Substitution applied, or "" if it has none. Useful in your own TTS modes. • "line_data": the whole Line, as written in the dialogue file: every data field, every Variation and their Meta. • "variation": the name of the Variation chosen for the Line (e.g. "Default" or "French"). Use it to pick the language to speak. user_args contains your own values: the entries of "tts" in the hook_arguments dictionary (Hook_Arguments.gd): anything else your TTS engine requires, such as a speech rate or an API key. custom_data contains the Custom Data written in the Line and in its chosen Variation: [[line values], [Variation values]]. Per-Line instructions for the TTS engine, such as an emotion or a pitch, can be written there. Other data can be read directly from the function, such as the speaker's entry in candy_de.actors (for example, a voice name you add to each Actor). TTS Modes The TTS mode decides whether a Line uses TTS, and which text is read:
ModeText read
"Off"None: TTS isn't used, and the Line plays its voice file.
"Simple"The Line's text as it's displayed, without its BBCode tags.
"Advanced"The text of the Line's TTS Variation (see below).
TTS Variations The text displayed to players isn't always the best text to read out loud: names may be mispronounced, and TTS engines may need punctuation, phonetic spellings or markup (such as SSML) for the right tone. In "Advanced" mode, TTS reads a Variation written for it instead. It's named like the displayed Variation, followed by _TTS: "Default_TTS" is read when "Default" is displayed, "French_TTS" when "French" is displayed, and so on. TTS Variations are never displayed, and are never chosen as the displayed Variation. Variables and Word Substitution are applied to a TTS Variation's text, as they are to the displayed text. Fallback When a Line in "Advanced" mode has no TTS Variation, the mode set by tts_advanced_fallback is used instead: "Simple" (the default) reads the displayed text, and "Off" plays the voice file. It can also be one of your own TTS modes. "Advanced" can't be its own fallback: since there's no TTS Variation to read, it's treated as "Off". Your Own TTS Modes TTS modes are names: besides "Off", "Simple" and "Advanced", any other name is a TTS mode of your own. A "Whisper" mode, for example, for Lines your TTS engine whispers. To create one, add a case for its name to the match in tts() (Tts.gd), then use the name in any TTS setting: on the Engine, a UI Element, an Actor or a Line. Your mode receives the same arguments as the others, and its "text" is the displayed text without its BBCode tags; "tts_variation_text" holds the TTS Variation, if the Line has one. A mode name that tts() has no case for is reported in the Output. Mode names aren't case-sensitive for "Off", "Simple" and "Advanced". Your own modes are passed to tts() exactly as written. Lexicon In "Simple" mode, Lexicon keywords are read as they're displayed (see Lexicon). Voice mode displays no text: there, the Engine's lexicon_voice_mode setting decides whether keywords are read as their "Display" value or their "Disabled" one. In "Advanced" mode, the _TTS Variation is read as written: the Lexicon never applies to it. TTS and Voice Files When a Line uses TTS, TTS takes precedence: the voice file is only played when tts() returns nothing usable. Both can therefore be mixed: return null for the Actors whose voices are recorded, or set TTS for some Actors only (see Actor Overrides below). TTS audio is played like a voice file: enable_voice, await_voice_playback, sync_write_speed_voice, suspension and the Voice Player hook functions apply to it too (see Voice). Configuration Engine Settings In the Inspector, under the Voice category:
SettingPurpose
text_to_speechThe TTS mode: "Off" (the default), "Simple", "Advanced" or one of your own.
tts_advanced_fallbackThe mode used instead of "Advanced" when a Line has no TTS Variation: "Simple" (the default), "Off" or one of your own.
Both are text fields: the Inspector suggests the built-in modes, and accepts the name of one of your own. TTS only runs for voiced Lines: when enable_voice (in the same category) is off for a Line, tts() isn't called. UI Overrides A UI Element can override the Engine settings. In the Inspector, under the Text-To-Speech category: 1. Set enable_text_to_speech (or enable_tts_advanced_fallback) to true, so that the UI Element overrides the Engine. 2. Set text_to_speech (or tts_advanced_fallback) to the mode of the Lines this UI Element displays. Actor Overrides An Actor overrides the Engine and UI settings through the TTS and TTSAdvancedFallback properties (in the actors dictionary): • "Off", "Simple", "Advanced" or one of your own modes: the mode of every Line the Actor speaks. • null, or no property: the decision is left to the Engine or the UI Element. Line Overrides A Spoken Line overrides the Engine, UI and Actor settings through its TTS and TTS_Advanced_Fallback data fields: • Off, Simple, Advanced or one of your own modes: the mode of this Line. • null: the decision is left to the Engine, the UI Element or the Actor. Godot TTS Godot's built-in Text-To-Speech (DisplayServer.tts_speak()) isn't compatible with Candy Dialogue Engine: it speaks the text through the operating system and never returns audio, so the Engine isn't aware of it. tts() can still call Godot's TTS, but Candy Dialogue Engine then treats the Line as having no TTS voice, which affects several features: • A Line that has a voice file plays it at the same time as the TTS voice, instead of playing the TTS voice alone. • The typewriter speed and the portrait animations aren't synchronized with the TTS voice. • The Dialogue advance isn't blocked until the TTS voice has finished. • The TTS voice isn't stopped when the Dialogue advances (the x_speech_advance() hook function can stop it). Godot's TTS feature also speaks with the voices installed on each player's device, so voices may sound different on every machine. To ensure compatibility with Candy Dialogue Engine, use a TTS engine that returns its audio, as an AudioStream or an audio file.