Add config.tts_substitutions.
This allows words to be replaced with their pronuncations, for the purpose of self-voicing.
This commit is contained in:
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 @@
|
||||
{"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"}
|
||||
Reference in New Issue
Block a user