Example #1
0
def nvdaController_setPitch(nPitch):
    from synthDriverHandler import getSynth
    try:
        getSynth()._set_pitch(nPitch)
    except:
        pass
    return 0
Example #2
0
def nvdaController_setRate(nRate):
    from synthDriverHandler import getSynth
    try:
        getSynth()._set_rate(nRate)
    except:
        pass
    return 0
Example #3
0
 def speak(self, speechSequence: SpeechSequence, priority: Spri):
     log._speechManagerUnitTest("speak (priority %r): %r", priority,
                                speechSequence)
     interrupt = self._queueSpeechSequence(speechSequence, priority)
     self._doRemoveCancelledSpeechCommands()
     # If speech isn't already in progress, we need to push the first speech.
     push = self._hasNoMoreSpeech() or not self._synthStillSpeaking()
     log._speechManagerDebug(
         f"Will interrupt: {interrupt}"
         f" Will push: {push}"
         f" | _indexesSpeaking: {self._indexesSpeaking!r}"
         f" | _curPriQueue valid: {not self._hasNoMoreSpeech()}"
         f" | _shouldPushWhenDoneSpeaking: {self._shouldPushWhenDoneSpeaking}"
         f" | _cancelledLastSpeechWithSynth {self._cancelledLastSpeechWithSynth}"
     )
     if interrupt:
         log._speechManagerDebug("Interrupting speech")
         getSynth().cancel()
         self._indexesSpeaking.clear()
         self._cancelCommandsForUtteranceBeingSpokenBySynth.clear()
         push = True
     if push:
         log._speechManagerDebug("Pushing next speech")
         self._pushNextSpeech(True)
     else:
         log._speechManagerDebug("Not pushing speech")
Example #4
0
    def update(self) -> Profile:
        """Stores all data of the current voice synthesizer in the profile.
		@return: updated voice synthesizer profile
		@rtype: Profile
		"""
        self._name = getSynth().name
        self._conf = dict(config.conf['speech'][getSynth().name].items())
        self._lang = self._lang or ''
        return self
Example #5
0
 def speak(self, speechSequence: SpeechSequence, priority: Spri):
     # If speech isn't already in progress, we need to push the first speech.
     push = self._curPriQueue is None
     interrupt = self._queueSpeechSequence(speechSequence, priority)
     if interrupt:
         getSynth().cancel()
         push = True
     if push:
         self._pushNextSpeech(True)
Example #6
0
 def _pushNextSpeech(self, doneSpeaking: bool):
     log._speechManagerDebug(
         f"pushNextSpeech - doneSpeaking: {doneSpeaking}")
     queue = self._getNextPriority()
     if not queue:
         # No more speech.
         log._speechManagerDebug("No more speech")
         self._curPriQueue = None
         return
     if self._hasNoMoreSpeech():
         # First utterance after no speech.
         self._curPriQueue = queue
     elif queue.priority > self._curPriQueue.priority:
         # Preempted by higher priority speech.
         if self._curPriQueue.enteredProfileTriggers:
             if not doneSpeaking:
                 # Wait for the synth to finish speaking.
                 # _handleDoneSpeaking will call us again.
                 self._shouldPushWhenDoneSpeaking = True
                 return
             self._exitProfileTriggers(
                 self._curPriQueue.enteredProfileTriggers)
         self._curPriQueue = queue
     elif queue.priority < self._curPriQueue.priority:
         # Resuming a preempted, lower priority queue.
         if queue.enteredProfileTriggers:
             if not doneSpeaking:
                 # Wait for the synth to finish speaking.
                 # _handleDoneSpeaking will call us again.
                 self._shouldPushWhenDoneSpeaking = True
                 return
             self._restoreProfileTriggers(queue.enteredProfileTriggers)
         self._curPriQueue = queue
     while queue.pendingSequences and isinstance(
             queue.pendingSequences[0][0], ConfigProfileTriggerCommand):
         if not doneSpeaking:
             # Wait for the synth to finish speaking.
             # _handleDoneSpeaking will call us again.
             self._shouldPushWhenDoneSpeaking = True
             return
         self._switchProfile()
     if not queue.pendingSequences:
         # The last commands in this queue were profile switches.
         # Call this method again in case other queues are waiting.
         return self._pushNextSpeech(True)
     seq = self._buildNextUtterance()
     if seq:
         # So that we can handle any accidentally skipped indexes.
         for item in seq:
             if isinstance(item, IndexCommand):
                 self._indexesSpeaking.append(item.index)
         self._cancelledLastSpeechWithSynth = False
         log._speechManagerUnitTest(f"Synth Gets: {seq}")
         getSynth().speak(seq)
Example #7
0
	def test_setSynth_auto_fallback_ifOneCoreDoesntSupportDefaultLanguage(self):
		"""
		Ensures that if oneCore doesn't support the current language, setSynth("auto") falls back to the
		current synth, or espeak if there is no current synth.
		"""
		globalVars.appArgs.language = "bar"  # set the lang so it is not supported
		synthDriverHandler.setSynth("auto")
		self.assertEqual(synthDriverHandler.getSynth().name, FAKE_DEFAULT_SYNTH_NAME)
		synthDriverHandler.setSynth(None)  # reset the synth so there is no fallback
		synthDriverHandler.setSynth("auto")
		self.assertEqual(synthDriverHandler.getSynth().name, "espeak")
 def finish(synthName, synthspeechConfig, msg):
     # stop previous synth because oneCore voice switch don't work without it
     config.conf[SCT_Speech] = synthSpeechConfig.copy()
     setSynth(synthName)
     config.conf[SCT_Speech][synthName] = synthSpeechConfig[
         synthName].copy()
     getSynth().loadSettings()
     # Reinitialize the tones module to update the audio device
     import tones
     tones.terminate()
     tones.initialize()
     if msg:
         ui.message(msg)
Example #9
0
	def resetSynth(self) -> None:
		"""If the synthesizer is not initialized - repeat attempts to initialize it."""
		if not synthDriverHandler.getSynth():
			synthDriverHandler.initialize()
			i = 0
			while not synthDriverHandler.getSynth() and i <= config.conf[ADDON_NAME]['retries']:
				synthDriverHandler.setSynth(config.conf['speech']['synth'])
				sleep(1)
				if config.conf[ADDON_NAME]['retries'] != 0:
					i += 1
			else:
				if config.conf[ADDON_NAME]['playsound']:
					self.audioEnabledSound()
def _processMpSpeech(text, language):
	# MathPlayer's default rate is 180 wpm.
	# Assume that 0% is 80 wpm and 100% is 450 wpm and scale accordingly.
	synth = getSynth()
	wpm = synth._percentToParam(synth.rate, 80, 450)
	breakMulti = 180.0 / wpm
	out = []
	if language:
		out.append(speech.LangChangeCommand(language))
	resetProsody = set()
	for m in RE_MP_SPEECH.finditer(text):
		if m.lastgroup == "break":
			out.append(speech.BreakCommand(time=int(m.group("break")) * breakMulti))
		elif m.lastgroup == "char":
			out.extend((speech.CharacterModeCommand(True),
				m.group("char"), speech.CharacterModeCommand(False)))
		elif m.lastgroup == "comma":
			out.append(speech.BreakCommand(time=100))
		elif m.lastgroup in PROSODY_COMMANDS:
			command = PROSODY_COMMANDS[m.lastgroup]
			out.append(command(multiplier=int(m.group(m.lastgroup)) / 100.0))
			resetProsody.add(command)
		elif m.lastgroup == "prosodyReset":
			for command in resetProsody:
				out.append(command(multiplier=1))
			resetProsody.clear()
		elif m.lastgroup == "phonemeText":
			out.append(speech.PhonemeCommand(m.group("ipa"),
				text=m.group("phonemeText")))
		elif m.lastgroup == "content":
			out.append(m.group(0))
	if language:
		out.append(speech.LangChangeCommand(None))
	return out
Example #11
0
	def _doRemoveCancelledSpeechCommands(self):
		if not _shouldCancelExpiredFocusEvents():
			return
		# Don't delete commands while iterating over _cancelCommandsForUtteranceBeingSpokenBySynth.
		latestCancelledUtteranceIndex = self._getMostRecentlyCancelledUtterance()
		log._speechManagerDebug(f"Last index: {latestCancelledUtteranceIndex}")
		if latestCancelledUtteranceIndex is not None:
			log._speechManagerDebug(f"Cancel and push speech")
			# Minimise the number of calls to _removeCompletedFromQueue by using the most recently cancelled
			# utterance index. This will remove all older queued speech also.
			self._removeCompletedFromQueue(latestCancelledUtteranceIndex)
			getSynth().cancel()
			self._cancelledLastSpeechWithSynth = True
			self._cancelCommandsForUtteranceBeingSpokenBySynth.clear()
			self._indexesSpeaking.clear()
			self._pushNextSpeech(True)
def setTemporaryAudioOutputDevice(outputDevice):
	global _temporaryOutputDevice
	curSynth = getSynth()
	prevOutputDevice = config.conf["speech"]["outputDevice"]
	ret = setOutputDevice(curSynth, outputDevice)
	if not ret:
		return

	def confirm(synth, prevOutputDevice):
		global _temporaryOutputDevice
		from ..settings import _addonConfigManager
		timeToLive = _addonConfigManager.getConfirmAudioDeviceChangeTimeOut()
		from ..utils import PutWindowOnForeground
		dialog = ConfirmOutputDevice(None, timeToLive)
		with dialog as d:
			PutWindowOnForeground(d.GetHandle(), 10, 0.5)
			res = d.ShowModal()
			d.Destroy()
		if res == wx.ID_OK:
			_temporaryOutputDevice = outputDevice
		else:
			# return to previous output device
			setOutputDevice(synth, prevOutputDevice)
	from ..settings import toggleConfirmAudioDeviceChangeAdvancedOption
	if toggleConfirmAudioDeviceChangeAdvancedOption(False):
		wx.CallLater(50, confirm, curSynth, prevOutputDevice)
	else:
		_temporaryOutputDevice = outputDevice
		obj = api.getFocusObject()
		speech.speakObject(obj)
Example #13
0
    def getCurrentSynthVoiceAndVariant(self):
        def getCurrentSettingName(setting):
            try:
                cur = getattr(synth, setting.name)
                tempList = list(
                    getattr(synth, "available%ss" %
                            setting.name.capitalize()).values())
                try:
                    # for nvda >= 2019.3
                    i = [x.id for x in tempList].index(cur)
                    return tempList[i].displayName
                except:  # noqa:E722
                    i = [x.ID for x in tempList].index(cur)
                    return tempList[i].name
            except:  # noqa:E722
                return ""

        synth = getSynth()
        voice = ""
        variant = ""
        for s in synth.supportedSettings:
            if s.name == "voice":
                voice = getCurrentSettingName(s)
            elif s.name == "variant":
                variant = getCurrentSettingName(s)
        return (voice, variant)
Example #14
0
	def test_setSynth_auto_fallbackMode(self):
		"""
		Ensures setSynth("auto") successfully sets a synth in defaultSynthPriorityList, and config is unchanged.
		"""
		synthDriverHandler.setSynth("auto", isFallback=True)
		self.assertIn(synthDriverHandler.getSynth().name, synthDriverHandler.defaultSynthPriorityList)
		self.assertEqual(FAKE_DEFAULT_LANG, config.conf["speech"]["synth"])
Example #15
0
def _getVoiceDictionary(profile):
    from synthDriverHandler import getSynth
    synth = getSynth()
    dictionaryFilename = _getVoiceDictionaryFileName(synth)
    # if we are om default profile or the specific dictionary profile is already loaded
    if not profile.name or _hasVoiceDictionaryProfile(profile.name, synth.name,
                                                      dictionaryFilename):
        # we are with the correct dictionary loaded. Just return it.
        log.debug(
            f"Voice dictionary, backed by {dictionaries['voice'].fileName} was requested"
        )
        return dictionaries["voice"]
    # we are on a user profile for which there is no dictionary created for the current voice.
    # The current loaded dictionary is the default profile one.
    # As we have beem called to get the profile dictionary for the current voice and it still does not exist,
    # We will create it now and pass the new, empty dictionary to the caller, but won't save it.
    # This is a task the caller should do when and if they wish
    dic = speechDictHandler.SpeechDict()
    dic.create(
        os.path.join(getProfileVoiceDictsPath(), synth.name,
                     dictionaryFilename))
    log.debug(
        f"voice dictionary was requested for profile {profile.name}, but the backing file does not exist."
        f" A New dictionary was created, set to be backed by {dic.fileName} if it is ever saved."
    )
    return dic
Example #16
0
    def set(self) -> bool:
        """Sets the profile as the current voice synthesizer.
		@return: an indication of whether the synthesizer has been successfully switched on
		@rtype: bool
		"""
        state = False
        try:
            config.conf.profiles[0]['speech'][self._name].clear()
            config.conf.profiles[0]['speech'][self._name].update(self._conf)
            config.conf['speech'][self._name]._cache.clear()
            state = setSynth(self._name)
            getSynth().saveSettings()
        except KeyError:
            pass
        self._status = state
        return state
Example #17
0
 def _onSynthIndexReached(self, synth=None, index=None):
     log._speechManagerUnitTest(
         f"synthReachedIndex: {index}, synth: {synth}")
     if synth != getSynth():
         return
     # This needs to be handled in the main thread.
     queueHandler.queueFunction(queueHandler.eventQueue, self._handleIndex,
                                index)
Example #18
0
	def test_setSynth_auto_usesOneCore_ifSupportsDefaultLanguage(self):
		"""
		Ensures that if oneCore supports the current language, setSynth("auto") uses "oneCore".
		"""
		# test setup ensures current NVDA language is supported for oneCore
		synthDriverHandler.setSynth(None)  # reset the synth so there is no fallback
		synthDriverHandler.setSynth("auto")
		self.assertEqual(synthDriverHandler.getSynth().name, "oneCore")
Example #19
0
 def script_review_sayAll(self, gesture):
     synthInstance = getSynth()
     if synthInstance.name == 'WorldVoiceXVED2':
         SayAllHandler = sayAll._SayAllHandler(
             SpeechWithoutPauses(speakFunc=synthInstance.patchedSpeak))
         SayAllHandler.readText(sayAll.CURSOR.REVIEW)
     else:
         sayAll.SayAllHandler.readText(sayAll.CURSOR.REVIEW)
Example #20
0
def reloadDictionaries():
    from synthDriverHandler import getSynth
    synth = getSynth()
    loadProfileDict()
    loadVoiceDict(synth)
    log.debug(
        f"loaded dictionaries for profile {config.conf.getActiveProfile().name or 'default'}"
    )
Example #21
0
 def _onSynthDoneSpeaking(self,
                          synth: Optional[
                              synthDriverHandler.SynthDriver] = None):
     if synth != getSynth():
         return
     # This needs to be handled in the main thread.
     queueHandler.queueFunction(queueHandler.eventQueue,
                                self._handleDoneSpeaking)
Example #22
0
	def test_setSynth_auto(self):
		"""
		Ensures setSynth("auto") successfully sets a synth in defaultSynthPriorityList, and saves it to config.
		"""
		synthDriverHandler.setSynth("auto")
		autoSynthName = synthDriverHandler.getSynth().name
		self.assertIn(autoSynthName, synthDriverHandler.defaultSynthPriorityList)
		self.assertEqual(config.conf["speech"]["synth"], autoSynthName)
Example #23
0
 def _onSynthDoneSpeaking(self,
                          synth: Optional[
                              synthDriverHandler.SynthDriver] = None):
     log._speechManagerUnitTest(f"synthDoneSpeaking synth:{synth}")
     if synth != getSynth():
         return
     # This needs to be handled in the main thread.
     queueHandler.queueFunction(queueHandler.eventQueue,
                                self._handleDoneSpeaking)
Example #24
0
def checkForUpdate(auto=False):
	"""Check for an updated version of NVDA.
	This will block, so it generally shouldn't be called from the main thread.
	@param auto: Whether this is an automatic check for updates.
	@type auto: bool
	@return: Information about the update or C{None} if there is no update.
	@rtype: dict
	@raise RuntimeError: If there is an error checking for an update.
	"""
	allowUsageStats=config.conf["update"]['allowUsageStats']
	params = {
		"autoCheck": auto,
		"allowUsageStats":allowUsageStats,
		"version": versionInfo.version,
		"versionType": versionInfo.updateVersionType,
		"osVersion": winVersion.winVersionText,
		"x64": os.environ.get("PROCESSOR_ARCHITEW6432") == "AMD64",
	}
	if auto and allowUsageStats:
		synthDriverClass = synthDriverHandler.getSynth().__class__
		brailleDisplayClass = braille.handler.display.__class__ if braille.handler else None
		# Following are parameters sent purely for stats gathering.
		#  If new parameters are added here, they must be documented in the userGuide for transparency.
		extraParams={
			"language": languageHandler.getLanguage(),
			"installed": config.isInstalledCopy(),
			"synthDriver":getQualifiedDriverClassNameForStats(synthDriverClass) if synthDriverClass else None,
			"brailleDisplay":getQualifiedDriverClassNameForStats(brailleDisplayClass) if brailleDisplayClass else None,
			"outputBrailleTable":config.conf['braille']['translationTable'] if brailleDisplayClass else None,
		}
		params.update(extraParams)
	url = "%s?%s" % (CHECK_URL, urllib.parse.urlencode(params))
	try:
		res = urllib.request.urlopen(url)
	except IOError as e:
		if isinstance(e.strerror, ssl.SSLError) and e.strerror.reason == "CERTIFICATE_VERIFY_FAILED":
			# #4803: Windows fetches trusted root certificates on demand.
			# Python doesn't trigger this fetch (PythonIssue:20916), so try it ourselves
			_updateWindowsRootCertificates()
			# and then retry the update check.
			res = urllib.request.urlopen(url)
		else:
			raise
	if res.code != 200:
		raise RuntimeError("Checking for update failed with code %d" % res.code)
	info = {}
	for line in res:
		# #9819: update description resource returns bytes, so make it Unicode.
		line = line.decode("utf-8").rstrip()
		try:
			key, val = line.split(": ", 1)
		except ValueError:
			raise RuntimeError("Error in update check output")
		info[key] = val
	if not info:
		return None
	return info
Example #25
0
    def test_setSynth_defaultSynths_fallbackMode(self):
        """
		For each synth in the synthDriverHandler.defaultSynthPriorityList, ensure they can be successfully set
		and the config is unchanged.
		"""
        for synthName in synthDriverHandler.defaultSynthPriorityList:
            synthDriverHandler.setSynth(synthName, isFallback=True)
            self.assertEqual(synthName, synthDriverHandler.getSynth().name)
            self.assertEqual(FAKE_DEFAULT_LANG, config.conf["speech"]["synth"])
Example #26
0
    def test_setSynth_defaultSynths(self):
        """
		For each synth in the synthDriverHandler.defaultSynthPriorityList, ensure they can be successfully set
		and saved to config.
		"""
        for synthName in synthDriverHandler.defaultSynthPriorityList:
            synthDriverHandler.setSynth(synthName)
            self.assertEqual(synthName, synthDriverHandler.getSynth().name)
            self.assertEqual(synthName, config.conf["speech"]["synth"])
Example #27
0
	def switchToDefaultOutputDevice(self) -> None:
		"""Switch NVDA audio output to the default audio device."""
		device: str = self.getDefaultDeviceName()
		if config.conf['speech']['outputDevice'] not in ("Microsoft Sound Mapper", device,):
			config.conf['speech']['outputDevice'] = device
			if synthDriverHandler.setSynth(synthDriverHandler.getSynth().name):
				tones.terminate()
				tones.initialize()
				if config.conf[ADDON_NAME]['playsound']:
					self.audioEnabledSound()
Example #28
0
 def speak(self, speechSequence: SpeechSequence, priority: Spri):
     log._speechManagerDebug(
         "Speak called: %r",
         speechSequence)  # expensive string to build - defer
     interrupt = self._queueSpeechSequence(speechSequence, priority)
     self.removeCancelledSpeechCommands()
     # If speech isn't already in progress, we need to push the first speech.
     push = self._curPriQueue is None or 1 > len(self._indexesSpeaking)
     if interrupt:
         log._speechManagerDebug("Interrupting speech")
         getSynth().cancel()
         self._indexesSpeaking.clear()
         self._cancelCommandsForUtteranceBeingSpokenBySynth.clear()
         push = True
     if push:
         log._speechManagerDebug("Pushing next speech")
         self._pushNextSpeech(True)
     else:
         log._speechManagerDebug("Not pushing speech")
Example #29
0
    def _processSpeechSequence(self, inSeq: SpeechSequence):
        paramTracker = ParamChangeTracker()
        enteredTriggers = []
        outSeqs = []
        paramsToReplay = []
        currentSynth = getSynth()

        outSeq = []
        for command in inSeq:
            if isinstance(command, BaseCallbackCommand):
                # When the synth reaches this point, we want to call the callback.
                speechIndex = next(self._indexCounter)
                outSeq.append(IndexCommand(speechIndex))
                self._indexesToCallbacks[speechIndex] = command
                # We split at indexes so we easily know what has completed speaking.
                outSeqs.append(paramsToReplay + outSeq)
                paramsToReplay.clear()
                outSeq.clear()
                continue
            if isinstance(command, ConfigProfileTriggerCommand):
                if not command.trigger.hasProfile:
                    # Ignore triggers that have no associated profile.
                    continue
                if command.enter and command.trigger in enteredTriggers:
                    log.debugWarning(
                        "Request to enter trigger which has already been entered: %r"
                        % command.trigger.spec)
                    continue
                if not command.enter and command.trigger not in enteredTriggers:
                    log.debugWarning(
                        "Request to exit trigger which wasn't entered: %r" %
                        command.trigger.spec)
                    continue
                self._ensureEndUtterance(outSeq, outSeqs, paramsToReplay,
                                         paramTracker)
                outSeqs.append([command])
                if command.enter:
                    enteredTriggers.append(command.trigger)
                else:
                    enteredTriggers.remove(command.trigger)
                continue
            if isinstance(command, EndUtteranceCommand):
                self._ensureEndUtterance(outSeq, outSeqs, paramsToReplay,
                                         paramTracker)
                continue
            if isinstance(command, SynthParamCommand):
                paramTracker.update(command)
            outSeq.append(command)
        # Add the last sequence and make sure the sequence ends the utterance.
        self._ensureEndUtterance(outSeq, outSeqs, paramsToReplay, paramTracker)
        # Exit any profile triggers the caller didn't exit.
        for trigger in reversed(enteredTriggers):
            command = ConfigProfileTriggerCommand(trigger, False)
            outSeqs.append([command])
        return outSeqs
	def setOutputDevice(self, name: str) -> None:
		"""Switche the NVDA output to the audio device with the specified name.
		@param name: name of the audio output device
		@type name: str
		"""
		config.conf['speech']['outputDevice'] = name
		status: bool = setSynth(getSynth().name)
		if status:
			tones.terminate()
			tones.initialize()
		ui.message(name)