Skip to content

Commit 6b11603

Browse files
authored
Merge 4038b84 into bd12c88
2 parents bd12c88 + 4038b84 commit 6b11603

2 files changed

Lines changed: 421 additions & 26 deletions

File tree

source/speech/__init__.py

Lines changed: 95 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -211,14 +211,70 @@ def speakSpelling(
211211
speak(seq, priority=priority)
212212

213213

214-
# C901 'getSpellingSpeech' is too complex
215-
# Note: when working on getSpellingSpeech, look for opportunities to simplify
216-
# and move logic out into smaller helper functions.
217-
def getSpellingSpeech( # noqa: C901
214+
def _getSpellingSpeechAddCharMode(
215+
seq: Generator[SequenceItemT, None, None],
216+
) -> Generator[SequenceItemT, None, None]:
217+
"""Inserts CharacterMode commands in a speech sequence generator to ensure any single character
218+
is spelt by the synthesizer.
219+
@param seq: The speech sequence to be spelt.
220+
"""
221+
charMode = False
222+
for item in seq:
223+
if isinstance(item, str):
224+
if len(item) == 1:
225+
if not charMode:
226+
yield CharacterModeCommand(True)
227+
charMode = True
228+
elif charMode:
229+
yield CharacterModeCommand(False)
230+
charMode = False
231+
yield item
232+
233+
234+
def _getSpellingCharAddCapNotification(
235+
speakCharAs: str,
236+
sayCapForCapitals: bool,
237+
capPitchChange: int,
238+
beepForCapitals: bool,
239+
) -> Generator[SequenceItemT, None, None]:
240+
"""This function produces a speech sequence containing a character to be spelt as well as commands
241+
to indicate that this character is uppercase if applicable.
242+
@param speakCharAs: The character as it will be spoken by the synthesizer.
243+
@param sayCapForCapitals: indicates if 'cap' should be reported along with the currently spelt character.
244+
@param capPitchChange: pitch offset to apply while spelling the currently spelt character.
245+
@param beepForCapitals: indicates if a cap notification beep should be produced while spelling the currently
246+
spellt character.
247+
"""
248+
if sayCapForCapitals:
249+
# Translators: cap will be spoken before the given letter when it is capitalized.
250+
capMsg = _("cap %s")
251+
(capMsgBefore, capMsgAfter) = capMsg.split('%s')
252+
else:
253+
capMsgBefore = ''
254+
capMsgAfter = ''
255+
256+
if capPitchChange:
257+
yield PitchCommand(offset=capPitchChange)
258+
if beepForCapitals:
259+
yield BeepCommand(2000, 50)
260+
if capMsgBefore:
261+
yield capMsgBefore
262+
yield speakCharAs
263+
if capMsgAfter:
264+
yield capMsgAfter
265+
if capPitchChange:
266+
yield PitchCommand()
267+
268+
269+
def _getSpellingSpeechWithoutCharMode(
218270
text: str,
219-
locale: Optional[str] = None,
220-
useCharacterDescriptions: bool = False
271+
locale: str,
272+
useCharacterDescriptions: bool,
273+
sayCapForCapitals: bool,
274+
capPitchChange: int,
275+
beepForCapitals: bool,
221276
) -> Generator[SequenceItemT, None, None]:
277+
222278
defaultLanguage=getCurrentLanguage()
223279
if not locale or (not config.conf['speech']['autoDialectSwitching'] and locale.split('_')[0]==defaultLanguage.split('_')[0]):
224280
locale=defaultLanguage
@@ -230,9 +286,6 @@ def getSpellingSpeech( # noqa: C901
230286
if not text.isspace():
231287
text=text.rstrip()
232288

233-
synth = getSynth()
234-
synthConfig=config.conf["speech"][synth.name]
235-
charMode = False
236289
textLength=len(text)
237290
count = 0
238291
localeHasConjuncts = True if locale.split('_',1)[0] in LANGS_WITH_CONJUNCT_CHARS else False
@@ -253,27 +306,43 @@ def getSpellingSpeech( # noqa: C901
253306
speakCharAs=charDesc[0] if textLength>1 else IDEOGRAPHIC_COMMA.join(charDesc)
254307
else:
255308
speakCharAs=characterProcessing.processSpeechSymbol(locale,speakCharAs)
256-
if uppercase and synthConfig["sayCapForCapitals"]:
257-
# Translators: cap will be spoken before the given letter when it is capitalized.
258-
speakCharAs=_("cap %s")%speakCharAs
259-
if uppercase and synth.isSupported("pitch") and synthConfig["capPitchChange"]:
260-
yield PitchCommand(offset=synthConfig["capPitchChange"])
261309
if config.conf['speech']['autoLanguageSwitching']:
262310
yield LangChangeCommand(locale)
263-
if len(speakCharAs) == 1 and synthConfig["useSpellingFunctionality"]:
264-
if not charMode:
265-
yield CharacterModeCommand(True)
266-
charMode = True
267-
elif charMode:
268-
yield CharacterModeCommand(False)
269-
charMode = False
270-
if uppercase and synthConfig["beepForCapitals"]:
271-
yield BeepCommand(2000, 50)
272-
yield speakCharAs
273-
if uppercase and synth.isSupported("pitch") and synthConfig["capPitchChange"]:
274-
yield PitchCommand()
311+
yield from _getSpellingCharAddCapNotification(
312+
speakCharAs,
313+
uppercase and sayCapForCapitals,
314+
capPitchChange if uppercase else 0,
315+
uppercase and beepForCapitals,
316+
)
275317
yield EndUtteranceCommand()
276318

319+
320+
def getSpellingSpeech(
321+
text: str,
322+
locale: Optional[str] = None,
323+
useCharacterDescriptions: bool = False
324+
) -> Generator[SequenceItemT, None, None]:
325+
326+
synth = getSynth()
327+
synthConfig = config.conf["speech"][synth.name]
328+
329+
if synth.isSupported("pitch"):
330+
capPitchChange = synthConfig["capPitchChange"]
331+
else:
332+
capPitchChange = 0
333+
seq = _getSpellingSpeechWithoutCharMode(
334+
text,
335+
locale,
336+
useCharacterDescriptions,
337+
sayCapForCapitals=synthConfig["sayCapForCapitals"],
338+
capPitchChange=capPitchChange,
339+
beepForCapitals=synthConfig["beepForCapitals"],
340+
)
341+
if synthConfig["useSpellingFunctionality"]:
342+
seq = _getSpellingSpeechAddCharMode(seq)
343+
yield from seq
344+
345+
277346
def getCharDescListFromText(text,locale):
278347
"""This method prepares a list, which contains character and its description for all characters the text is made up of, by checking the presence of character descriptions in characterDescriptions.dic of that locale for all possible combination of consecutive characters in the text.
279348
This is done to take care of conjunct characters present in several languages such as Hindi, Urdu, etc.

0 commit comments

Comments
 (0)