def getPreInitSettings(cls) -> SupportedSettingType: """Get settings that can be configured before the provider is initialized. This is a class method because it does not rely on any instance state in this class. """ return [ BooleanDriverSetting( "shouldDoX", # value stored in matching property name on class "Should Do X", defaultVal=True), BooleanDriverSetting( "shouldDoY", # value stored in matching property name on class "Should Do Y", defaultVal=False), NumericDriverSetting( "amountOfZ", # value stored in matching property name on class "Amount of Z", defaultVal=11), DriverSetting( # options for this come from a property with name generated by # f"available{settingID.capitalize()}s" # Note: # First letter of Id becomes capital, the rest lowercase. # the 's' character on the end. # result: 'availableNameofsomethings' "nameOfSomething", # value stored in matching property name on class "Name of something", ) ]
def _getAvailableRuntimeSettings(self) -> SupportedSettingType: settings = [] if self._hasFeature("runtimeOnlySetting_externalValueLoad"): settings.extend([ NumericDriverSetting( "runtimeOnlySetting_externalValueLoad", # value stored in matching property name on class "Runtime Only amount, external value load", # no GUI default ), ]) if self._hasFeature("runtimeOnlySetting_localDefault"): settings.extend([ NumericDriverSetting( "runtimeOnlySetting_localDefault", # value stored in matching property name on class "Runtime Only amount, local default", defaultVal=50, ), ]) return settings
def InflectionSetting(cls, minStep=1): """Factory function for creating inflection setting.""" return NumericDriverSetting( "inflection", # Translators: Label for a setting in voice settings dialog. _("&Inflection"), minStep=minStep, availableInSettingsRing=True, # Translators: Label for a setting in synth settings ring. displayName=pgettext('synth setting', 'Inflection'), )
def VolumeSetting(cls, minStep=1): """Factory function for creating volume setting.""" return NumericDriverSetting( "volume", # Translators: Label for a setting in voice settings dialog. _("V&olume"), minStep=minStep, normalStep=5, availableInSettingsRing=True, # Translators: Label for a setting in synth settings ring. displayName=pgettext('synth setting', 'Volume'), )
def __init__(self): if self.exposeExtraParams: self._extraParamNames = [x[0] for x in speechPlayer.Frame._fields_] self.supportedSettings = SynthDriver.supportedSettings + tuple( NumericDriverSetting( "speechPlayer_%s" % x, "frame.%s" % x, normalStep=1) for x in self._extraParamNames) for x in self._extraParamNames: setattr(self, "speechPlayer_%s" % x, 50) self.player = speechPlayer.SpeechPlayer(16000) _espeak.initialize() _espeak.setVoiceByLanguage('en') self.pitch = 50 self.rate = 50 self.volume = 90 self.inflection = 60 self.audioThread = AudioThread(self, self.player, 16000)
class SynthDriver(synthDriverHandler.SynthDriver): supportedSettings=(SynthDriver.VoiceSetting(), SynthDriver.VariantSetting(), SynthDriver.RateSetting(), BooleanDriverSetting("rateBoost", _("Rate boos&t"), True), SynthDriver.PitchSetting(), SynthDriver.InflectionSetting(), SynthDriver.VolumeSetting(), NumericDriverSetting("hsz", _("Head size"), False), NumericDriverSetting("rgh", _("Roughness"), False), NumericDriverSetting("bth", _("Breathiness"), False), BooleanDriverSetting("backquoteVoiceTags", _("Enable backquote voice &tags"), False), BooleanDriverSetting("ABRDICT", _("Enable &abbreviation dictionary"), False), BooleanDriverSetting("phrasePrediction", _("Enable phrase prediction"), False), BooleanDriverSetting("shortpause", _("&Shorten pauses"), False), BooleanDriverSetting("sendParams", _("Always Send Current Speech Settings (enable to prevent some tags from sticking, disable for viavoice binary compatibility)"), False)) supportedCommands = { IndexCommand, CharacterModeCommand, LangChangeCommand, BreakCommand, PitchCommand, RateCommand, VolumeCommand } supportedNotifications = {synthIndexReached, synthDoneSpeaking} description='IBMTTS' name='ibmeci' speakingLanguage="" @classmethod def check(cls): return _ibmeci.eciCheck() def __init__(self): _ibmeci.initialize(self._onIndexReached, self._onDoneSpeaking) # This information doesn't really need to be displayed, and makes IBMTTS unusable if the addon is not in the same drive as NVDA executable. # But display it only on debug mode in case of it can be useful log.debug("Using IBMTTS version %s" % _ibmeci.eciVersion()) lang = languageHandler.getLanguage() self.rate=50 self.speakingLanguage=lang self.variant="1" self.currentEncoding = "mbcs" PROSODY_ATTRS = { PitchCommand: ECIVoiceParam.eciPitchBaseline, VolumeCommand: ECIVoiceParam.eciVolume, RateCommand: ECIVoiceParam.eciSpeed, } def speak(self,speechSequence): last = None defaultLanguage=self.language outlist = [] charmode=False for item in speechSequence: if isinstance(item, string_types): s = self.processText(item) outlist.append((_ibmeci.speak, (s,))) last = s elif isinstance(item,IndexCommand): outlist.append((_ibmeci.index, (item.index,))) elif isinstance(item,LangChangeCommand): l=None if item.lang in langsAnnotations: l = langsAnnotations[item.lang] elif item.lang and item.lang[0:2] in langsAnnotations: l = langsAnnotations[item.lang[0:2]] if l: if item.lang != self.speakingLanguage and item.lang != self.speakingLanguage[0:2]: outlist.append((_ibmeci.speak, (l,))) self.speakingLanguage=item.lang self.updateEncoding(l) else: outlist.append((_ibmeci.speak, (langsAnnotations[defaultLanguage],))) self.speakingLanguage = defaultLanguage elif isinstance(item,CharacterModeCommand): outlist.append((_ibmeci.speak, (b"`ts1" if item.state else b"`ts0",))) if item.state: charmode=True elif isinstance(item,BreakCommand): # taken from eloquence_threshold (https://github.com/pumper42nickel/eloquence_threshold) # Eloquence doesn't respect delay time in milliseconds. # Therefore we need to adjust waiting time depending on current speech rate # The following table of adjustments has been measured empirically # Then we do linear approximation coefficients = { 10:1, 43:2, 60:3, 75:4, 85:5, } ck = sorted(coefficients.keys()) if self.rate <= ck[0]: factor = coefficients[ck[0]] elif self.rate >= ck[-1]: factor = coefficients[ck[-1]] elif self.rate in ck: factor = coefficients[self.rate] else: li = [index for index, r in enumerate(ck) if r<self.rate][-1] ri = li + 1 ra = ck[li] rb = ck[ri] factor = 1.0 * coefficients[ra] + (coefficients[rb] - coefficients[ra]) * (self.rate - ra) / (rb-ra) pFactor = factor*item.time pFactor = int(pFactor) outlist.append((_ibmeci.speak, (b' `p%d '%(pFactor),))) elif type(item) in self.PROSODY_ATTRS: val = max(0, min(item.newValue, 100)) if type(item) == RateCommand: val = self.percentToRate(val) outlist.append((_ibmeci.setProsodyParam, (self.PROSODY_ATTRS[type(item)], val))) else: log.error("Unknown speech: %s"%item) if last is not None and last[-1] not in punctuation: # check if a pitch command is at the end of the list, because p1 need to be send before this. # index -2 is because -1 always seem to be an index command. if outlist[-2][0] == _ibmeci.setProsodyParam: outlist.insert(-2, (_ibmeci.speak, (b'`p1 ',))) else: outlist.append((_ibmeci.speak, (b'`p1 ',))) if charmode: outlist.append((_ibmeci.speak, (b"`ts0",))) outlist.append((_ibmeci.setEndStringMark, ())) outlist.append((_ibmeci.synth, ())) _ibmeci.eciQueue.put(outlist) _ibmeci.process() def processText(self,text): #this converts to ansi for anticrash. If this breaks with foreign langs, we can remove it. text = text.encode(self.currentEncoding, 'replace') # special unicode symbols may encode to backquote. For this reason, backquote processing is after this. text = text.rstrip() if _ibmeci.params[9] in (65536, 65537, 393216, 655360, 720897): text = resub(english_fixes, text) #Applies to all languages with dual language support. if _ibmeci.params[9] in (65536, 65537, 393216, 655360, 720897) and _ibmeci.isIBM: text = resub(english_ibm_fixes, text) if _ibmeci.params[9] in (131072, 131073) and not _ibmeci.isIBM: text = resub(spanish_fixes, text) if _ibmeci.params[9] in ('esp', 131072) and _ibmeci.isIBM: text = resub(spanish_ibm_fixes, text) if _ibmeci.params[9] in (196609, 196608): text = text.replace(br'quil', br'qil') #Sometimes this string make everything buggy with IBMTTS in French if _ibmeci.params[9] in ('deu', 262144): text = resub(german_fixes, text) if _ibmeci.params[9] in ('ptb', 458752) and _ibmeci.isIBM: text = resub(portuguese_ibm_fixes, text) if not self._backquoteVoiceTags: text=text.replace(b'`', b' ') # no embedded commands if self._shortpause: text = pause_re.sub(br'\1 `p1\2\3\4', text) # this enforces short, JAWS-like pauses. if not _ibmeci.isIBM: text = time_re.sub(br'\1:\2 \3', text) # apparently if this isn't done strings like 2:30:15 will only announce 2:30 embeds=b'' if self._ABRDICT: embeds+=b"`da1 " else: embeds+=b"`da0 " if self._phrasePrediction: embeds+=b"`pp1 " else: embeds+=b"`pp0 " if self._sendParams: embeds+=b"`vv%d `vs%d " % (_ibmeci.getVParam(ECIVoiceParam.eciVolume), _ibmeci.getVParam(ECIVoiceParam.eciSpeed)) text = b"%s %s" % (embeds.rstrip(), text) # bring all the printf stuff into one call, in one string. This avoids all the concatonation and printf additions of the previous organization. return text def pause(self,switch): _ibmeci.pause(switch) def terminate(self): _ibmeci.terminate() _backquoteVoiceTags=False _ABRDICT=False _phrasePrediction=False _shortpause=False _sendParams=True def _get_backquoteVoiceTags(self): return self._backquoteVoiceTags def _set_backquoteVoiceTags(self, enable): if enable == self._backquoteVoiceTags: return self._backquoteVoiceTags = enable def _get_ABRDICT(self): return self._ABRDICT def _set_ABRDICT(self, enable): if enable == self._ABRDICT: return self._ABRDICT = enable def _get_phrasePrediction(self): return self._phrasePrediction def _set_phrasePrediction(self, enable): if enable == self._phrasePrediction: return self._phrasePrediction = enable def _get_shortpause(self): return self._shortpause def _set_shortpause(self, enable): if enable == self._shortpause: return self._shortpause = enable def _get_sendParams(self): return self._sendParams def _set_sendParams(self, enable): if enable == self._sendParams: return self._sendParams = enable _rateBoost = False RATE_BOOST_MULTIPLIER = 1.6 def _get_rateBoost(self): return self._rateBoost def _set_rateBoost(self, enable): if enable != self._rateBoost: rate = self.rate self._rateBoost = enable self.rate = rate def _get_rate(self): val = _ibmeci.getVParam(ECIVoiceParam.eciSpeed) if self._rateBoost: val=int(round(val/self.RATE_BOOST_MULTIPLIER)) return self._paramToPercent(val, minRate, maxRate) def percentToRate(self, val): val = self._percentToParam(val, minRate, maxRate) if self._rateBoost: val = int(round(val *self.RATE_BOOST_MULTIPLIER)) return val def _set_rate(self,val): val = self.percentToRate(val) self._rate = val _ibmeci.setVParam(ECIVoiceParam.eciSpeed, val) def _get_pitch(self): return _ibmeci.getVParam(ECIVoiceParam.eciPitchBaseline) def _set_pitch(self,vl): _ibmeci.setVParam(ECIVoiceParam.eciPitchBaseline,vl) def _get_volume(self): return _ibmeci.getVParam(ECIVoiceParam.eciVolume) def _set_volume(self,vl): _ibmeci.setVParam(ECIVoiceParam.eciVolume,int(vl)) def _set_inflection(self,vl): vl = int(vl) _ibmeci.setVParam(ECIVoiceParam.eciPitchFluctuation,vl) def _get_inflection(self): return _ibmeci.getVParam(ECIVoiceParam.eciPitchFluctuation) def _set_hsz(self,vl): vl = int(vl) _ibmeci.setVParam(ECIVoiceParam.eciHeadSize,vl) def _get_hsz(self): return _ibmeci.getVParam(ECIVoiceParam.eciHeadSize) def _set_rgh(self,vl): vl = int(vl) _ibmeci.setVParam(ECIVoiceParam.eciRoughness,vl) def _get_rgh(self): return _ibmeci.getVParam(ECIVoiceParam.eciRoughness) def _set_bth(self,vl): vl = int(vl) _ibmeci.setVParam(ECIVoiceParam.eciBreathiness,vl) def _get_bth(self): return _ibmeci.getVParam(ECIVoiceParam.eciBreathiness) def _getAvailableVoices(self): o = OrderedDict() for name in os.listdir(_ibmeci.ttsPath): if name.lower().endswith('.syn'): info = _ibmeci.langs[name.lower()[:3]] o[str(info[0])] = VoiceInfo(str(info[0]), info[1], info[2]) return o def _get_voice(self): return str(_ibmeci.params[_ibmeci.ECIParam.eciLanguageDialect]) def _set_voice(self,vl): _ibmeci.setVoice(int(vl)) self.updateEncoding(int(vl)) def updateEncoding(self, lang): # lang must be a number asociated with IBMTTS languages or a string with an annotation language. # currently we don't need to consider the decimal part for the conversion. if isinstance(lang, bytes): lang = int(float(lang[2:])) * 65536 #chinese if lang == 393216: self.currentEncoding = "gb2312" # japan elif lang == 524288: self.currentEncoding = "cp932" # korean elif lang == 655360: self.currentEncoding = "cp949" elif lang == 720897: self.currentEncoding = "big5" else: self.currentEncoding = "mbcs" def _get_lastIndex(self): #fix? return _ibmeci.lastindex def cancel(self): _ibmeci.stop() def _getAvailableVariants(self): global variants return OrderedDict((str(id), synthDriverHandler.VoiceInfo(str(id), name)) for id, name in variants.items()) def _set_variant(self, v): global variants self._variant = v if int(v) in variants else "1" _ibmeci.setVariant(int(v)) _ibmeci.setVParam(ECIVoiceParam.eciSpeed, self._rate) #if 'ibmtts' in config.conf['speech']: #config.conf['speech']['ibmtts']['pitch'] = self.pitch def _get_variant(self): return self._variant def _onIndexReached(self, index): synthIndexReached.notify(synth=self, index=index) def _onDoneSpeaking(self): synthDoneSpeaking.notify(synth=self)
class SynthDriver(synthDriverHandler.SynthDriver): supportedSettings = (SynthDriver.VoiceSetting(), SynthDriver.VariantSetting(), SynthDriver.RateSetting(), SynthDriver.PitchSetting(), SynthDriver.InflectionSetting(), SynthDriver.VolumeSetting(), NumericDriverSetting("hsz", "Head Size"), NumericDriverSetting("rgh", "Roughness"), NumericDriverSetting("bth", "Breathiness"), BooleanDriverSetting("backquoteVoiceTags", "Enable backquote voice &tags", True)) supportedCommands = { IndexCommand, CharacterModeCommand, LangChangeCommand, BreakCommand, PitchCommand, RateCommand, VolumeCommand, PhonemeCommand, } supportedNotifications = {synthIndexReached, synthDoneSpeaking} PROSODY_ATTRS = { PitchCommand: _eloquence.pitch, VolumeCommand: _eloquence.vlm, RateCommand: _eloquence.rate, } description = 'Saksham-Eloquence' name = 'eloquence' @classmethod def check(cls): return _eloquence.eciCheck() def __init__(self): _eloquence.initialize(self._onIndexReached) self.curvoice = "enu" self.rate = 50 self.variant = "1" def speak(self, speechSequence): last = None outlist = [] for item in speechSequence: if isinstance(item, str): s = str(item) s = self.xspeakText(s) outlist.append((_eloquence.speak, (s, ))) last = s elif isinstance(item, IndexCommand): outlist.append((_eloquence.index, (item.index, ))) elif isinstance(item, BreakCommand): pFactor = 3 * item.time outlist.append((_eloquence.speak, (f'`p{pFactor}.', ))) elif type(item) in self.PROSODY_ATTRS: pr = self.PROSODY_ATTRS[type(item)] if item.multiplier == 1: # Revert back to defaults outlist.append((_eloquence.cmdProsody, ( pr, None, ))) else: outlist.append((_eloquence.cmdProsody, ( pr, item.multiplier, ))) if last is not None and not last.rstrip()[-1] in punctuation: outlist.append((_eloquence.speak, ('`p1.', ))) outlist.append((_eloquence.index, (0xffff, ))) outlist.append((_eloquence.synth, ())) _eloquence.synth_queue.put(outlist) _eloquence.process() def xspeakText(self, text, should_pause=False): if _eloquence.params[9] == 65536 or _eloquence.params[9] == 65537: text = resub(english_fixes, text) if _eloquence.params[9] == 131072 or _eloquence.params[9] == 131073: text = resub(spanish_fixes, text) if _eloquence.params[9] in (196609, 196608): text = resub(french_fixes, text) #this converts to ansi for anticrash. If this breaks with foreign langs, we can remove it. #text = text.encode('mbcs') text = normalizeText(text) text = resub(anticrash_res, text) if not self._backquoteVoiceTags: text = text.replace('`', ' ') text = "`pp0 `vv%d %s" % (self.getVParam(_eloquence.vlm), text ) #no embedded commands text = pause_re.sub(r'\1 `p1\2\3', text) text = time_re.sub(r'\1:\2 \3', text) #if two strings are sent separately, pause between them. This might fix some of the audio issues we're having. if should_pause: text = text + ' `p1.' return text # _eloquence.speak(text, index) # def cancel(self): # self.dll.eciStop(self.handle) def pause(self, switch): _eloquence.pause(switch) # self.dll.eciPause(self.handle,switch) def terminate(self): _eloquence.terminate() _backquoteVoiceTags = False def _get_backquoteVoiceTags(self): return self._backquoteVoiceTags def _set_backquoteVoiceTags(self, enable): if enable == self._backquoteVoiceTags: return self._backquoteVoiceTags = enable def _get_rate(self): return self._paramToPercent(self.getVParam(_eloquence.rate), minRate, maxRate) def _set_rate(self, vl): self._rate = self._percentToParam(vl, minRate, maxRate) self.setVParam(_eloquence.rate, self._percentToParam(vl, minRate, maxRate)) def _get_pitch(self): return self.getVParam(_eloquence.pitch) def _set_pitch(self, vl): self.setVParam(_eloquence.pitch, vl) def _get_volume(self): return self.getVParam(_eloquence.vlm) def _set_volume(self, vl): self.setVParam(_eloquence.vlm, int(vl)) def _set_inflection(self, vl): vl = int(vl) self.setVParam(_eloquence.fluctuation, vl) def _get_inflection(self): return self.getVParam(_eloquence.fluctuation) def _set_hsz(self, vl): vl = int(vl) self.setVParam(_eloquence.hsz, vl) def _get_hsz(self): return self.getVParam(_eloquence.hsz) def _set_rgh(self, vl): vl = int(vl) self.setVParam(_eloquence.rgh, vl) def _get_rgh(self): return self.getVParam(_eloquence.rgh) def _set_bth(self, vl): vl = int(vl) self.setVParam(_eloquence.bth, vl) def _get_bth(self): return self.getVParam(_eloquence.bth) def _getAvailableVoices(self): o = OrderedDict() for name in os.listdir(_eloquence.eciPath[:-8]): if not name.lower().endswith('.syn'): continue info = _eloquence.langs[name.lower()[:-4]] o[str(info[0])] = synthDriverHandler.VoiceInfo( str(info[0]), info[1], None) return o def _get_voice(self): return str(_eloquence.params[9]) def _set_voice(self, vl): _eloquence.set_voice(vl) self.curvoice = vl def getVParam(self, pr): return _eloquence.getVParam(pr) def setVParam(self, pr, vl): _eloquence.setVParam(pr, vl) def _get_lastIndex(self): #fix? return _eloquence.lastindex def cancel(self): _eloquence.stop() def _getAvailableVariants(self): global variants return OrderedDict( (str(id), synthDriverHandler.VoiceInfo(str(id), name)) for id, name in variants.items()) def _set_variant(self, v): global variants self._variant = v if int(v) in variants else "1" _eloquence.setVariant(int(v)) self.setVParam(_eloquence.rate, self._rate) # if 'eloquence' in config.conf['speech']: # config.conf['speech']['eloquence']['pitch'] = self.pitch def _get_variant(self): return self._variant def _onIndexReached(self, index): if index is not None: synthIndexReached.notify(synth=self, index=index) else: synthDoneSpeaking.notify(synth=self)
class SynthDriver(WorldVoiceBaseSynthDriver, SynthDriver): name = "WorldVoiceXVED2" description = "WorldVoice(VE)" supportedSettings = [ SynthDriver.VoiceSetting(), # SynthDriver.VariantSetting(), SynthDriver.RateSetting(), SynthDriver.PitchSetting(), SynthDriver.VolumeSetting(), DriverSetting( "numlan", # Translators: Label for a setting in voice settings dialog. _("Number &Language"), availableInSettingsRing=True, defaultVal="default", # Translators: Label for a setting in synth settings ring. displayName=_("Number Language"), ), DriverSetting( "nummod", # Translators: Label for a setting in voice settings dialog. _("Number &Mode"), availableInSettingsRing=True, defaultVal="value", # Translators: Label for a setting in synth settings ring. displayName=_("Number Mode"), ), NumericDriverSetting( "chinesespace", # Translators: Label for a setting in voice settings dialog. _("Pause time when encountering spaces between Chinese"), defaultVal=0, minStep=1, ), BooleanDriverSetting( "cni", _("Ignore comma between number"), defaultVal=False, ), BooleanDriverSetting( "uwv", _("Enable WorldVoice setting rules to detect text language"), availableInSettingsRing=True, defaultVal=True, displayName=_("Enable WorldVoice rules"), ), ] supportedCommands = { IndexCommand, CharacterModeCommand, LangChangeCommand, BreakCommand, PitchCommand, RateCommand, VolumeCommand, } supportedNotifications = {synthIndexReached, synthDoneSpeaking} @classmethod def check(cls): with _vocalizer.preOpenVocalizer() as check: return check def __init__(self): _config.load() # Initialize the driver try: _vocalizer.initialize(self._onIndexReached) log.debug("Vocalizer info: %s" % self._info()) except _vocalizer.VeError as e: if e.code == _vocalizer.VAUTONVDA_ERROR_INVALID: log.info("Vocalizer license for NVDA is Invalid") elif e.code == _vocalizer.VAUTONVDA_ERROR_DEMO_EXPIRED: log.info("Vocalizer demo license for NVDA as expired.") raise self._voiceManager = VoiceManager() self._realSpeakFunc = speech.speech.speak self._realSpellingFunc = speech.speech.speakSpelling speech.speech.speak = self.patchedSpeak speech.speech.speakSpelling = self.patchedSpeakSpelling self.speechSymbols = SpeechSymbols() self.speechSymbols.load('unicode.dic') self._languageDetector = languageDetection.LanguageDetector( list(self._voiceManager.languages), self.speechSymbols) self._localeToVoices = self._voiceManager.localeToVoicesMap self._locales = sorted([ l for l in self._localeToVoices if len(self._localeToVoices[l]) > 0 ]) self._localeNames = list( map(self._getLocaleReadableName, self._locales)) self._voice = None def _onIndexReached(self, index): if index is not None: synthIndexReached.notify(synth=self, index=index) else: synthDoneSpeaking.notify(synth=self) def terminate(self): speech.speech.speak = self._realSpeakFunc speech.speech.speakSpelling = self._realSpellingFunc try: self.cancel() self._voiceManager.close() _vocalizer.terminate() except RuntimeError: log.error("Vocalizer terminate", exc_info=True) def speak(self, speechSequence): if self.uwv \ and _config.vocalizerConfig['autoLanguageSwitching']['useUnicodeLanguageDetection'] \ and _config.vocalizerConfig['autoLanguageSwitching']['afterSymbolDetection']: speechSequence = self._languageDetector.add_detected_language_commands( speechSequence) speechSequence = list(speechSequence) speechSequence = self.patchedSpaceSpeechSequence(speechSequence) currentInstance = defaultInstance = self._voiceManager.defaultVoiceInstance.token currentLanguage = defaultLanguage = self.language chunks = [] hasText = False charMode = False for command in speechSequence: if isinstance(command, str): command = command.strip() if not command: continue # If character mode is on use lower case characters # Because the synth does not allow to turn off the caps reporting if charMode or len(command) == 1: command = command.lower() # replace the excape character since it is used for parameter changing chunks.append(command.replace("\x1b", "")) hasText = True elif isinstance(command, IndexCommand): chunks.append("\x1b\\mrk=%d\\" % command.index) elif isinstance(command, BreakCommand): maxTime = 6553 if self.variant == "bet2" else 65535 breakTime = max(1, min(command.time, maxTime)) self._speak(currentInstance, chunks) chunks = [] hasText = False _vocalizer.processBreak(currentInstance, breakTime) elif isinstance(command, CharacterModeCommand): charMode = command.state s = "\x1b\\tn=spell\\" if command.state else "\x1b\\tn=normal\\" chunks.append(s) elif isinstance(command, LangChangeCommand) or isinstance( command, speechcommand.WVLangChangeCommand): if command.lang == currentLanguage: # Keep on the same voice. continue if command.lang is None: # No language, use default. currentInstance = defaultInstance currentLanguage = defaultLanguage continue # Changed language, lets see what we have. currentLanguage = command.lang newVoiceName = self._voiceManager.getVoiceNameForLanguage( currentLanguage) if newVoiceName is None: # No voice for this language, use default. newInstance = defaultInstance else: newInstance = self._voiceManager.getVoiceInstance( newVoiceName).token if newInstance == currentInstance: # Same voice, next command. continue if hasText: # We changed voice, send text we already have to vocalizer. self._speak(currentInstance, chunks) chunks = [] hasText = False currentInstance = newInstance elif isinstance(command, PitchCommand): pitch = self._voiceManager.getVoiceParameter( currentInstance, _vocalizer.VE_PARAM_PITCH, type_=int) pitchOffset = self._percentToParam( command.offset, _vocalizer.PITCH_MIN, _vocalizer.PITCH_MAX) - _vocalizer.PITCH_MIN chunks.append("\x1b\\pitch=%d\\" % (pitch + pitchOffset)) elif isinstance(command, speechcommand.SplitCommand): self._speak(currentInstance, chunks) chunks = [] hasText = False if chunks: self._speak(currentInstance, chunks) def _speak(self, voiceInstance, chunks): text = speech.CHUNK_SEPARATOR.join(chunks).replace(" \x1b", "\x1b") _vocalizer.processText2Speech(voiceInstance, text) def patchedSpeak(self, speechSequence, symbolLevel=None, priority=None): if self._cni: speechSequence = [ comma_number_pattern.sub(lambda m: '', command) if isinstance( command, str) else command for command in speechSequence ] speechSequence = self.patchedNumSpeechSequence(speechSequence) if self.uwv \ and _config.vocalizerConfig['autoLanguageSwitching']['useUnicodeLanguageDetection'] \ and not _config.vocalizerConfig['autoLanguageSwitching']['afterSymbolDetection']: speechSequence = self._languageDetector.add_detected_language_commands( speechSequence) speechSequence = list(speechSequence) self._realSpeakFunc(speechSequence, symbolLevel, priority=priority) def patchedSpeakSpelling(self, text, locale=None, useCharacterDescriptions=False, priority=None): if config.conf["speech"]["autoLanguageSwitching"] \ and _config.vocalizerConfig['autoLanguageSwitching']['useUnicodeLanguageDetection'] \ and config.conf["speech"]["trustVoiceLanguage"]: for text, loc in self._languageDetector.process_for_spelling( text, locale): self._realSpellingFunc(text, loc, useCharacterDescriptions, priority=priority) else: self._realSpellingFunc(text, locale, useCharacterDescriptions, priority=priority) def cancel(self): _vocalizer.stop() def pause(self, switch): if switch: _vocalizer.pause() else: _vocalizer.resume() def _get_volume(self): return self._voiceManager.defaultVoiceInstance.volume def _set_volume(self, value): self._voiceManager.defaultVoiceInstance.volume = value self._voiceManager.defaultVoiceInstance.commit() def _get_rate(self): return self._voiceManager.defaultVoiceInstance.rate def _set_rate(self, value): self._voiceManager.defaultVoiceInstance.rate = value self._voiceManager.defaultVoiceInstance.commit() def _get_pitch(self): return self._voiceManager.defaultVoiceInstance.pitch def _set_pitch(self, value): self._voiceManager.defaultVoiceInstance.pitch = value self._voiceManager.defaultVoiceInstance.commit() def _getAvailableVoices(self): return self._voiceManager.voiceInfos def _get_voice(self): if self._voice is None: voice = self._voiceManager.getVoiceNameForLanguage( languageHandler.getLanguage()) if voice is None: voice = list(self.availableVoices.keys())[0] return voice return self._voiceManager.defaultVoiceName def _set_voice(self, voiceName): self._voice = voiceName if voiceName == self._voiceManager.defaultVoiceName: return # Stop speech before setting a new voice to avoid voice instances # continuing speaking when changing voices for, e.g., say-all # See NVDA ticket #3540 _vocalizer.stop() self._voiceManager.setDefaultVoice(voiceName) # Available variants are cached by default. As variants maybe different for each voice remove the cached value # if hasattr(self, '_availableVariants'): # del self._availableVariants # Synchronize with the synth so the parameters # we report are not from the previous voice. # _vocalizer.sync() def _get_variant(self): return self._voiceManager.defaultVoiceInstance.variant def _set_variant(self, name): self.cancel() self._voiceManager.defaultVoiceInstance.variant = name def _getAvailableVariants(self): dbs = self._voiceManager.defaultVoiceInstance.variants return OrderedDict([(d, VoiceInfo(d, d)) for d in dbs]) def _get_availableLanguages(self): return self._voiceManager.languages def _get_language(self): return self._voiceManager.getVoiceLanguage() def _info(self): s = [self.description] return ", ".join(s) def _get_availableNumlans(self): return dict({ "default": StringParameterInfo("default", _("default")), }, **{ locale: StringParameterInfo(locale, name) for locale, name in zip(self._locales, self._localeNames) }) def _get_numlan(self): return self._numlan def _set_numlan(self, value): self._numlan = value def _get_availableNummods(self): return dict({ "value": StringParameterInfo("value", _("value")), "number": StringParameterInfo("number", _("number")), }) def _get_nummod(self): return self._nummod def _set_nummod(self, value): self._nummod = value def _get_chinesespace(self): return self._chinesespace def _set_chinesespace(self, value): self._chinesespace = value def _get_cni(self): return self._cni def _set_cni(self, value): self._cni = value def _getLocaleReadableName(self, locale): description = languageHandler.getLanguageDescription(locale) return "%s" % (description) if description else locale