Add config.tts_substitutions.

This allows words to be replaced with their pronuncations, for
the purpose of self-voicing.
This commit is contained in:
Tom Rothamel
2023-01-31 00:18:00 -05:00
parent d764a100a6
commit a474006d40
7 changed files with 114 additions and 8 deletions
+3
View File
@@ -1343,6 +1343,9 @@ after_default_callbacks = [ ]
# A list of extra save directories. Strings giving the full paths.
extra_savedirs = [ ]
# The text-to-speech dictionary. A list of [ (RegeEx|String, String) ] pairs.
tts_substitutions = [ ]
del os
del collections
+52 -6
View File
@@ -26,6 +26,7 @@ from renpy.compat import PY2, basestring, bchr, bord, chr, open, pystr, range, r
import sys
import os
import re
import subprocess
import pygame_sdl2 as pygame
@@ -53,6 +54,9 @@ root = None
# The text of the last displayable.
last = ""
# The text of the last displayable, before config.tts_dictionary was applied.
last_raw = ""
# The speech synthesis process.
process = None
@@ -143,21 +147,59 @@ def default_tts_function(s):
except Exception:
pass
# A List of (regex, string) pairs.
tts_substitutions = [ ]
def init():
"""
Initializes the TTS system. This is called automatically by ts, below.
"""
for pattern, replacement in renpy.config.tts_substitutions:
if isinstance(pattern, basestring):
pattern = r'\b' + re.escape(pattern) + r'\b'
pattern = re.compile(pattern, re.IGNORECASE)
replacement = re.escape(replacement)
tts_substitutions.append((pattern, replacement))
def apply_substitutions(s):
"""
Applies the TTS dictionary to `s`, returning the result.
"""
def replace(m):
old = m.group(0)
if old.title() == old:
template = replacement.title()
elif old.upper() == old:
template = replacement.upper()
elif old.lower() == old:
template = replacement.lower()
else:
template = replacement
return m.expand(template)
for pattern, replacement in tts_substitutions:
s = pattern.sub(replace, s)
return s
def tts(s):
"""
Speaks the queued messages using the specified function.
Causes `s` to be spoken.
"""
global queue
try:
renpy.config.tts_function(s)
except Exception:
pass
queue = [ ]
def speak(s, translate=True, force=False):
"""
@@ -189,6 +231,7 @@ def displayable(d):
global old_self_voicing
global last
global last_raw
self_voicing = renpy.game.preferences.self_voicing
@@ -228,6 +271,9 @@ def displayable(d):
else:
d = root
if s != last:
if s != last_raw:
last_raw = s
s = apply_substitutions(s)
last = s
tts(prefix + s)
+4
View File
@@ -687,6 +687,9 @@ def change_language(language, force=False):
# Rebuild the styles.
renpy.style.rebuild() # @UndefinedVariable
# Re-init tts.
renpy.display.tts.init()
for i in renpy.config.translate_clean_stores:
renpy.python.reset_store_changes(i)
@@ -699,6 +702,7 @@ def change_language(language, force=False):
old_language = language
def check_language():
"""
Checks to see if the language has changed. If it has, jump to the start
+17
View File
@@ -199,6 +199,23 @@ ruby text. For example::
e "【【This is not | ruby text.】"
Accessibility
-------------
The new :var:`config.tts_substitutions` variable allows the game to
provide substitution rules for self-voicing. That is meant to allow
the creator to control pronunciation of words that might be mispronounced
by the text to speech engine.
For example::
define config.tts_substitutions = [
("Ren'Py", "Ren Pie"),
]
Will cause the word "Ren'Py" to be pronounced as "Ren Pie" whenever
self-voicing speaks it.
Save Token Security
-------------------
+31
View File
@@ -1035,6 +1035,37 @@ Occasionally Used
platform specific, and so this should be set in a platform-specific
manner. (It may make sense to change this in translations, as well.)
.. var:: config.tts_substitutions = [ ]
This is a list of (pattern, replacement) pairs that are used to perform
substitutions on text before it is passed to the text-to-speech engine,
so that the text-to-speech engine can pronounce it correctly.
Patterns may be either strings or regular expressions, and replacements
must be strings.
If the pattern is a string, it is escaped, then prefixed
and suffixed with 'r\b' (to indicate it must begin and end at a word
boundary), and then compiled into a regular expression. When pattern
is a string, the replacement is also escaped.
If pattern is a regular expression, it is used as-is, and the replacement
is not escaped.
The substitutions are performed in the order they are given. If a substution
matches the string, the match is checed to see if the match is in title case,
upper case, or lower case, and if so the corresponding casing is performed
on the replacement. Once this is done, the replacement is applied.
For example::
define config.tts_substitutions = [
("Ren'Py", "Ren Pie"),
]
Will cause the string "Ren'Py is pronunced ren'py." to be voices as if
it were "Ren Pie is pronounced ren pie."
.. var:: config.webaudio_required_types = [ "audio/ogg", "audio/mpeg", ... ]
When running on the web platform, Ren'Py will check the browser to
+6 -1
View File
@@ -63,7 +63,7 @@ Creator Concerns
----------------
Ren'Py's self-voicing works by extracting text from displayables and
reading it to the player. Ren'Py extracts this text from two places.
reading it to the player. Ren'Py extracts this text from multiple places.
Text displayables
Ren'Py will extract text from a Text displayable, and make it
@@ -132,6 +132,11 @@ Descriptive Text
If not None, this should be a character object that is used to
display the descriptive text, instead of the narrator.
The :var:`config.tts_substitutions` variable can be used to substitute
words in the text being spoken, to better control pronunciation. The
:var:`config.tts_voice` variable can be used to select the voice used
to speak text from the voices on a platform.
A self-voicing debug mode can be enabled by typing Shift+Alt+V. This will
display the text that would be voiced on the screen for development
purposes.
+1 -1
View File
@@ -1 +1 @@
{"display_name": "The Question", "android_build": "Release", "type": "hidden", "renamed_all": true, "renamed_steam": true, "force_recompile": true, "build_update": true, "packages": ["mac", "pc", "linux"], "add_from": true}
{"display_name": "The Question", "android_build": "Release", "add_from": true, "renamed_all": true, "renamed_steam": true, "force_recompile": true, "build_update": true, "packages": ["mac", "pc", "linux", "market"], "type": "hidden"}