diff --git a/src/cthulhu/cthulhu_gui_prefs.py b/src/cthulhu/cthulhu_gui_prefs.py index 843b694..2771d10 100644 --- a/src/cthulhu/cthulhu_gui_prefs.py +++ b/src/cthulhu/cthulhu_gui_prefs.py @@ -183,6 +183,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper): self.soundThemeCombo = None self.roleSoundPresentationCombo = None self._isInitialSetup = False + self._updatingSpeechFamilies = False self.selectedFamilyChoices = {} self.selectedLanguageChoices = {} self.profilesCombo = None @@ -1271,7 +1272,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper): for familyChoice in self.speechFamiliesChoices: name = familyChoice[speechserver.VoiceFamily.NAME] if name == familyName: - self.get_widget("speechFamilies").set_active(i) + self._setSpeechFamiliesActive(i) self.speechFamiliesChoice = self.speechFamiliesChoices[i] familySet = True break @@ -1295,13 +1296,22 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper): if not familySet: tokens = ["PREFERENCES DIALOG: Could not find speech family match for", familyName] debug.printTokens(debug.LEVEL_INFO, tokens, True) - self.get_widget("speechFamilies").set_active(0) + self._setSpeechFamiliesActive(0) self.speechFamiliesChoice = self.speechFamiliesChoices[0] if familySet: self.selectedFamilyChoices[self.speechServersChoice, self.speechLanguagesChoice] = i + def _setSpeechFamiliesActive(self, index): + """Sets speechFamilies active index while suppressing preview chatter.""" + + self._updatingSpeechFamilies = True + try: + self.get_widget("speechFamilies").set_active(index) + finally: + self._updatingSpeechFamilies = False + def _setupFamilies(self): """Gets the list of voice variants for the current speech server and current language. @@ -1353,7 +1363,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper): selectedIndex = self.selectedFamilyChoices[self.speechServersChoice, self.speechLanguagesChoice] - self.get_widget("speechFamilies").set_active(selectedIndex) + self._setSpeechFamiliesActive(selectedIndex) def _setSpeechLanguagesChoice(self, languageName): """Sets the active item in the languages ("Language:") combo box @@ -2899,21 +2909,51 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper): self.get_widget("enableDiacriticalKeysCheckButton").set_sensitive( \ enable) - def _presentMessage(self, text, interrupt=False): + def _presentMessage(self, text, interrupt=False, voice=None): """If the text field is not None, presents the given text, optionally interrupting anything currently being spoken. Arguments: - text: the text to present - interrupt: if True, interrupt any speech currently being spoken + - voice: the voice to use; if None, use the default system voice """ - self.script.speakMessage(text, interrupt=interrupt) + self.script.speakMessage(text, voice=voice, interrupt=interrupt) try: self.script.displayBrailleMessage(text, flashTime=-1) except Exception: pass + def _previewVoiceSelection(self, voiceType, name): + """Present a short preview in the currently selected voice.""" + + if not name: + return + + voice = self._getACSSForVoiceType(voiceType) + if not voice: + return + + previewVoice = acss.ACSS(voice) + if self.speechSystemsChoice \ + and self.speechSystemsChoice.SpeechServer.getFactoryName() == guilabels.SPEECH_DISPATCHER: + previewMessage = messages.SPEECH_VOICE_VALUE % name + else: + previewMessage = messages.SPEECH_VOICE_VALUE_GENERIC % name + + # Speak through the currently-selected preferences speech server so + # preview uses the chosen module/voice, not the globally-active one. + server = self.speechServersChoice + if server and hasattr(server, "speak"): + try: + server.speak(previewMessage, previewVoice, interrupt=True) + return + except Exception: + debug.printException(debug.LEVEL_WARNING) + + self._presentMessage(previewMessage, interrupt=True, voice=previewVoice) + def _createNode(self, appName): """Create a new root node in the TreeStore model with the name of the application. @@ -3316,6 +3356,8 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper): variant = family[speechserver.VoiceFamily.VARIANT] voiceType = self.get_widget("voiceTypesCombo").get_active() self._setFamilyNameForVoiceType(voiceType, name, language, dialect, variant) + if not self._updatingSpeechFamilies: + self._previewVoiceSelection(voiceType, name) except Exception: debug.printException(debug.LEVEL_SEVERE) diff --git a/src/cthulhu/speech_and_verbosity_manager.py b/src/cthulhu/speech_and_verbosity_manager.py index 3feb57a..5ff8a6d 100644 --- a/src/cthulhu/speech_and_verbosity_manager.py +++ b/src/cthulhu/speech_and_verbosity_manager.py @@ -368,7 +368,11 @@ class SpeechAndVerbosityManager: if family is None: default_voice.pop(acss.ACSS.FAMILY, None) else: - default_voice[acss.ACSS.FAMILY] = dict(family) + family_dict = { + key: value for key, value in dict(family).items() + if value is not None + } + default_voice[acss.ACSS.FAMILY] = family_dict default_voice['established'] = True def _get_current_speech_setting(self): @@ -581,7 +585,7 @@ class SpeechAndVerbosityManager: message = "" if message: - voice = self._get_default_voice() if setting == "voice" else None + voice = self._get_default_voice() if setting in ("voice", "module") else None self._present_message(script, message, voice=voice) @dbus_service.command @@ -698,7 +702,11 @@ class SpeechAndVerbosityManager: else: self._set_default_voice_family({}) - self._present_message(script, messages.SPEECH_MODULE_VALUE % new_module) + self._present_message( + script, + messages.SPEECH_MODULE_VALUE % new_module, + voice=self._get_default_voice(), + ) return True def _adjust_voice(self, script, decrease):