TTS voices: Difference between revisions
Document upcoming 0.1.7: optional server TTS, 33 functions, 4 events, English voice/setup guides and NPC meleeSkillTier; not a release |
Clarify all supported TTS languages; neutral voice-profile examples and separate Ukrainian backend note |
||
| Line 5: | Line 5: | ||
== Voice and preset configuration == | == Voice and preset configuration == | ||
Chatterbox languages: <code>ar da | Chatterbox Multilingual V3 supports 23 languages: Arabic (<code>ar</code>), Danish (<code>da</code>), Dutch (<code>nl</code>), English (<code>en</code>), Finnish (<code>fi</code>), French (<code>fr</code>), German (<code>de</code>), Greek (<code>el</code>), Hebrew (<code>he</code>), Hindi (<code>hi</code>), Italian (<code>it</code>), Japanese (<code>ja</code>), Korean (<code>ko</code>), Malay (<code>ms</code>), Norwegian (<code>no</code>), Polish (<code>pl</code>), Portuguese (<code>pt</code>), Russian (<code>ru</code>), Spanish (<code>es</code>), Swahili (<code>sw</code>), Swedish (<code>sv</code>), Turkish (<code>tr</code>) and Chinese (<code>zh</code>). Select any supported language in a voice or preset; use <code>getTtsLanguages("chatterbox_v3")</code> to read the available codes. | ||
'''Ukrainian backend note:''' Ukrainian (<code>uk</code>) is supported through the separate StyleTTS2 engine: <code>engine="styletts2_uk", language="uk"</code>. It requires that engine to be installed/enabled and an authorized reference sample. It is not a Chatterbox language; its engine-specific parameters are listed below. | |||
Both engines support a server-owned reference sample. Place it under the worker's <code>voices</code> directory, not under game resources. Use WAV, FLAC or OGG, 1–30 seconds, mono/stereo, 8–96 kHz, at most 8 MiB. Supply its lowercase SHA-256. Use recordings you are authorized to use. Ukrainian requires a reference; Chatterbox can use its built-in voice. | Both engines support a server-owned reference sample. Place it under the worker's <code>voices</code> directory, not under game resources. Use WAV, FLAC or OGG, 1–30 seconds, mono/stereo, 8–96 kHz, at most 8 MiB. Supply its lowercase SHA-256. Use recordings you are authorized to use. Ukrainian requires a reference; Chatterbox can use its built-in voice. | ||
| Line 14: | Line 16: | ||
'''Step 2.''' Prefer clean speech from one speaker, without music, overlapping voices or long silence. A practical starting point is 5–15 seconds; the accepted range remains 1–30 seconds. Voice similarity and accent are not guaranteed. For Ukrainian, start with a clearly spoken Ukrainian reference. | '''Step 2.''' Prefer clean speech from one speaker, without music, overlapping voices or long silence. A practical starting point is 5–15 seconds; the accepted range remains 1–30 seconds. Voice similarity and accent are not guaranteed. For Ukrainian, start with a clearly spoken Ukrainian reference. | ||
'''Step 3.''' If necessary, convert the actual audio to WAV/OGG/FLAC in an audio editor. Renaming <code>.mp3</code> to <code>.wav</code> does not convert it. For a simple interoperable sample, use mono PCM WAV. Keep it within the limits above. | '''Step 3.''' If necessary, convert the actual audio to WAV/OGG/FLAC in an audio editor. Renaming <code>.mp3</code> to <code>.wav</code> does not convert it. For a simple interoperable sample, use mono PCM WAV. Keep it within the limits above. | ||
'''Step 4.''' Choose a simple ASCII filename with a '''lowercase extension''', e.g. <code> | '''Step 4.''' Choose a simple ASCII filename with a '''lowercase extension''', e.g. <code>guard.wav</code> or <code>guards/voice.ogg</code>. Avoid spaces, accented filenames, absolute paths, <code>..</code>, symlinks and URLs. Copy it into <code>tts/voices</code> on the machine running the worker. An external worker needs its own identical copy, not just a file on the game server. | ||
'''Step 5.''' Calculate the hash of the '''final file after conversion/copying''': | '''Step 5.''' Calculate the hash of the '''final file after conversion/copying''': | ||
<syntaxhighlight lang="powershell"> | <syntaxhighlight lang="powershell"> | ||
(Get-FileHash -Algorithm SHA256 .\tts\voices\ | (Get-FileHash -Algorithm SHA256 .\tts\voices\guard.wav).Hash.ToLowerInvariant() | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<syntaxhighlight lang="bash"> | <syntaxhighlight lang="bash"> | ||
sha256sum tts/voices/ | sha256sum tts/voices/guard.wav | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 32: | Line 34: | ||
A ready-made spoken recording that you want to play '''unchanged''' is different again: add it as a normal audio asset to a resource and use the existing client resource-audio API. Do not pass it through TTS just to play it, and do not manually insert it into <code>tts/data</code>; that directory contains generated clips with validated metadata. [[loadTtsAudio]] loads a name previously created by <code>saveAs</code>, not an arbitrary file path or internet URL. | A ready-made spoken recording that you want to play '''unchanged''' is different again: add it as a normal audio asset to a resource and use the existing client resource-audio API. Do not pass it through TTS just to play it, and do not manually insert it into <code>tts/data</code>; that directory contains generated clips with validated metadata. [[loadTtsAudio]] loads a name previously created by <code>saveAs</code>, not an arbitrary file path or internet URL. | ||
=== | === Voice profiles and language selection === | ||
These are | These are examples in a '''server-side''' Lua resource. The first profile works with any language listed for Chatterbox: change <code>language</code> to the supported code you need (<code>en</code> below is only an example). Replace each hash with the hash of the corresponding private sample. [[createTtsVoice]] does not train a model or render a recording: it stores a validated reusable configuration. | ||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
local voice, why = createTtsVoice(" | local voice, why = createTtsVoice("guard", { | ||
engine = "chatterbox_v3", language = " | engine = "chatterbox_v3", language = "en", seed = 12345, | ||
reference = " | reference = "guard.wav", referenceHash = "REPLACE_WITH_64_LOWERCASE_HEX_CHARACTERS", | ||
parameters = {exaggeration=0.5, cfgWeight=0.5, temperature=0.8} | parameters = {exaggeration=0.5, cfgWeight=0.5, temperature=0.8} | ||
}) | }) | ||
if not voice then outputDebugString("TTS profile rejected: " .. tostring(why)) end | if not voice then outputDebugString("TTS profile rejected: " .. tostring(why)) end | ||
</syntaxhighlight> | </syntaxhighlight> | ||
For Ukrainian only, select the separate backend and its parameters instead: | |||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
| Line 54: | Line 58: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Then select <code>{voice=" | Then select <code>{voice="guard"}</code> or the corresponding preset in generation options. Use [[updateTtsVoice]] / [[updateTtsPreset]] when the name already exists. Multiple profiles can point to one reference with different languages/parameters; changing those options creates a different cache request. Switching profiles never changes a player's game voice-language setting. | ||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
createTtsPreset(" | createTtsPreset("guard", { | ||
engine = "chatterbox_v3", language = " | engine = "chatterbox_v3", language = "en", seed = 12345, | ||
reference = "guard.ogg", referenceHash = "REPLACE_WITH_64_LOWERCASE_HEX_CHARACTERS", | reference = "guard.ogg", referenceHash = "REPLACE_WITH_64_LOWERCASE_HEX_CHARACTERS", | ||
parameters = {exaggeration=0.5, cfgWeight=0.5, temperature=0.8} | parameters = {exaggeration=0.5, cfgWeight=0.5, temperature=0.8} | ||
}) | }) | ||
local job = renderTts(" | local job = renderTts("Stop!", {preset="guard", saveAs="guard_stop"}) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Revision as of 06:54, 9 October 2026
Coming in 0.1.7 — not released yet. Not included in public 0.1.6. Use matching TTS-capable server and clients.
See TTS configuration for installation and Server TTS for rendering, persistent audio and remote playback.
Voice and preset configuration
Chatterbox Multilingual V3 supports 23 languages: Arabic (ar), Danish (da), Dutch (nl), English (en), Finnish (fi), French (fr), German (de), Greek (el), Hebrew (he), Hindi (hi), Italian (it), Japanese (ja), Korean (ko), Malay (ms), Norwegian (no), Polish (pl), Portuguese (pt), Russian (ru), Spanish (es), Swahili (sw), Swedish (sv), Turkish (tr) and Chinese (zh). Select any supported language in a voice or preset; use getTtsLanguages("chatterbox_v3") to read the available codes.
Ukrainian backend note: Ukrainian (uk) is supported through the separate StyleTTS2 engine: engine="styletts2_uk", language="uk". It requires that engine to be installed/enabled and an authorized reference sample. It is not a Chatterbox language; its engine-specific parameters are listed below.
Both engines support a server-owned reference sample. Place it under the worker's voices directory, not under game resources. Use WAV, FLAC or OGG, 1–30 seconds, mono/stereo, 8–96 kHz, at most 8 MiB. Supply its lowercase SHA-256. Use recordings you are authorized to use. Ukrainian requires a reference; Chatterbox can use its built-in voice.
Adding a downloaded or recorded voice
Step 1. Obtain an audio sample that you have permission to use for synthesized speech, for example a speaker's explicitly permitted sample or your own recording. Being publicly downloadable does not itself grant that permission. Keep the source and permission information in your operator records. Do not impersonate a person without their consent.
Step 2. Prefer clean speech from one speaker, without music, overlapping voices or long silence. A practical starting point is 5–15 seconds; the accepted range remains 1–30 seconds. Voice similarity and accent are not guaranteed. For Ukrainian, start with a clearly spoken Ukrainian reference.
Step 3. If necessary, convert the actual audio to WAV/OGG/FLAC in an audio editor. Renaming .mp3 to .wav does not convert it. For a simple interoperable sample, use mono PCM WAV. Keep it within the limits above.
Step 4. Choose a simple ASCII filename with a lowercase extension, e.g. guard.wav or guards/voice.ogg. Avoid spaces, accented filenames, absolute paths, .., symlinks and URLs. Copy it into tts/voices on the machine running the worker. An external worker needs its own identical copy, not just a file on the game server.
Step 5. Calculate the hash of the final file after conversion/copying:
(Get-FileHash -Algorithm SHA256 .\tts\voices\guard.wav).Hash.ToLowerInvariant()
sha256sum tts/voices/guard.wav
Step 6. Put the relative filename and the 64-character lowercase hash in a server-side voice/preset below, or use the private /ttstest voice commands. The owner provisions the file; the game client never uploads a voice through this API. A new filename under the existing voice directory can be used by the next request; changing startup configuration requires restarting the server.
Step 7. Render a short sentence and listen before rendering a whole dialogue library. Replacing the sample requires updating its hash. For a changed permanently named clip, also choose a new saveAs name.
A voice sample is not a downloadable TTS model. Arbitrary .pt, .pth, .safetensors, .onnx, Python scripts or executables are not accepted by the voice API. Do not install a downloaded “voice pack” into tts/runtime: the supported engine weights are provisioned separately. ZIPs must not be passed as references; if an authorized archive contains audio, extract and inspect the actual audio sample outside the server first.
A ready-made spoken recording that you want to play unchanged is different again: add it as a normal audio asset to a resource and use the existing client resource-audio API. Do not pass it through TTS just to play it, and do not manually insert it into tts/data; that directory contains generated clips with validated metadata. loadTtsAudio loads a name previously created by saveAs, not an arbitrary file path or internet URL.
Voice profiles and language selection
These are examples in a server-side Lua resource. The first profile works with any language listed for Chatterbox: change language to the supported code you need (en below is only an example). Replace each hash with the hash of the corresponding private sample. createTtsVoice does not train a model or render a recording: it stores a validated reusable configuration.
local voice, why = createTtsVoice("guard", {
engine = "chatterbox_v3", language = "en", seed = 12345,
reference = "guard.wav", referenceHash = "REPLACE_WITH_64_LOWERCASE_HEX_CHARACTERS",
parameters = {exaggeration=0.5, cfgWeight=0.5, temperature=0.8}
})
if not voice then outputDebugString("TTS profile rejected: " .. tostring(why)) end
For Ukrainian only, select the separate backend and its parameters instead:
local preset, why = createTtsPreset("guard_uk", {
engine = "styletts2_uk", language = "uk", seed = 12345,
reference = "guards/guard_uk.ogg", referenceHash = "REPLACE_WITH_64_LOWERCASE_HEX_CHARACTERS",
parameters = {speed=1.0, alpha=0.0, beta=0.0, embeddingScale=1.0, diffusionSteps=10}
})
if not preset then outputDebugString("TTS preset rejected: " .. tostring(why)) end
Then select {voice="guard"} or the corresponding preset in generation options. Use updateTtsVoice / updateTtsPreset when the name already exists. Multiple profiles can point to one reference with different languages/parameters; changing those options creates a different cache request. Switching profiles never changes a player's game voice-language setting.
createTtsPreset("guard", {
engine = "chatterbox_v3", language = "en", seed = 12345,
reference = "guard.ogg", referenceHash = "REPLACE_WITH_64_LOWERCASE_HEX_CHARACTERS",
parameters = {exaggeration=0.5, cfgWeight=0.5, temperature=0.8}
})
local job = renderTts("Stop!", {preset="guard", saveAs="guard_stop"})
Presets and voices store a complete generation configuration, not engine pointers. Request overrides replace top-level fields. Use either voice or preset, not both. Replacing the parameters table uses defaults for omitted values. getTtsCapabilities().engines[engine].parameters[name] returns a three-element array: [1] default, [2] minimum, [3] maximum (not named fields):
| Engine | Parameter | Default | Allowed range |
|---|---|---|---|
| Chatterbox V3 | exaggeration |
0.5 | 0–2 |
| Chatterbox V3 | cfgWeight |
0.5 | 0–1 |
| Chatterbox V3 | temperature |
0.8 | 0.05–5 |
| Chatterbox V3 | repetitionPenalty |
1.2 | 1–3 |
| Chatterbox V3 | minP |
0.05 | 0–1 |
| Chatterbox V3 | topP |
1.0 | 0.01–1 |
| Ukrainian StyleTTS2 | speed |
1.0 | 0.5–2 |
| Ukrainian StyleTTS2 | alpha, beta |
0.0 each | 0–1 |
| Ukrainian StyleTTS2 | embeddingScale |
1.0 | 0.1–3 |
| Ukrainian StyleTTS2 | diffusionSteps |
10 | integer 1–50 |
seed is an integer 0–4294967295 (default 0). Start with defaults and change one setting at a time. There is no separate pitch, gender, emotion-name or universal speed control in this API; in particular, speed is not a Chatterbox parameter. Select a different authorized voice sample for a different speaker, rather than passing unsupported keys.
Only actual engine parameters are accepted. Unsupported keys fail instead of being silently ignored. Voices/presets live in the resource VM session. Persist them with the existing resource storage API:
writeResourceData("tts_profiles", toJSON(exportTtsPresets()))
local text = readResourceData("tts_profiles")
if type(text) == "string" then
local profiles = fromJSON(text)
local ok, why = importTtsPresets(profiles)
if not ok then outputDebugString(why) end
end
Import validates the entire document before replacing that resource's collections. It never installs Python, loads a URL, or accepts executable model files from Lua.