예제 #1
0
class SynthDriver(synthDriverHandler.SynthDriver):
	supportedSettings=(SynthDriver.VoiceSetting(), SynthDriver.VariantSetting(),
	SynthDriver.RateSetting(), BooleanSynthSetting("rateBoost", _("Rate boos&t")),
	SynthDriver.PitchSetting(), SynthDriver.InflectionSetting(), SynthDriver.VolumeSetting(), NumericSynthSetting("hsz", _("Head Size"), False), NumericSynthSetting("rgh", _("Roughness"), False), NumericSynthSetting("bth", _("Breathiness"), False), BooleanSynthSetting("backquoteVoiceTags", _("Enable backquote voice &tags"), False))
	description='IBMTTS'
	name='ibmeci'
	speakingLanguage=""
	@classmethod
	def check(cls):
		return _ibmeci.eciCheck()
		
	def __init__(self):
		_ibmeci.initialize()
		# 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"


	def speak(self,speechSequence):
		last = None
		defaultLanguage=self.language
		outlist = []
		for item in speechSequence:
			if isinstance(item, string_types):
				s = self.processText(unicode(item))
				outlist.append((_ibmeci.speak, (s,)))
				last = s
			elif isinstance(item,speech.IndexCommand):
				outlist.append((_ibmeci.index, (item.index,)))
			elif isinstance(item,speech.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
				else:
					outlist.append((_ibmeci.speak, (langsAnnotations[defaultLanguage],)))
					self.speakingLanguage = defaultLanguage
			elif isinstance(item,speech.CharacterModeCommand):
				outlist.append((_ibmeci.speak, (b"`ts1" if item.state else "b`ts0",)))
			elif isinstance(item,speech.SpeechCommand):
				log.debugWarning("Unsupported speech command: %s"%item)
			else:
				log.error("Unknown speech: %s"%item)
		if last is not None and not last[-1] in punctuation: outlist.append((_ibmeci.speak, (b'`p1',)))
		outlist.append((_ibmeci.setEndStringMark, ()))
		
		outlist.append((_ibmeci.speak, (b"`ts0",)))
		outlist.append((_ibmeci.synth, ()))
		_ibmeci.synthQueue.put(outlist)
		_ibmeci.process()

	def processText(self,text):
		text = text.rstrip()
		if _ibmeci.params[9] in (65536, 65537): text = resub(english_fixes, text)
		if _ibmeci.params[9] in (131072,  131073): text = resub(spanish_fixes, text)
		if _ibmeci.params[9] in (196609, 196608):
			text = resub(french_fixes, text)
			text = text.replace('quil', 'qil') #Sometimes this string make everything buggy with IBMTTS in French
		#if not self._backquoteVoiceTags: text = text.replace(u'‵', ' ')
		if self._backquoteVoiceTags:
			text = "`pp0 `vv%d %s" % (self.getVParam(_ibmeci.vlm), text.replace('`', ' ')) #no embedded commands
			text = resub(anticrash_res, text)
			#this converts to ansi for anticrash. If this breaks with foreign langs, we can remove it.
			text = text.encode('mbcs', 'replace')
		else:
			#this converts to ansi for anticrash. If this breaks with foreign langs, we can remove it.
			text = text.encode('mbcs', 'replace')
			text = resub(anticrash_res, text)
			text = b"`pp0 `vv%d %s" % (self.getVParam(_ibmeci.vlm), text.replace(b'`', b' ')) #no embedded commands
		text = pause_re.sub(br'\1 `p1\2\3', text)
		text = time_re.sub(br'\1:\2 \3', text)
		# temporal fix: replace , with `" -" because IBMTTS seems ignore commas at the end.
		# if you know a better solution please let me know to update it.
		if text[-1] == b",": text = text[0:-1]+b" -"
		return text



	def pause(self,switch):
		_ibmeci.pause(switch)

	def terminate(self):
		_ibmeci.terminate()

	_backquoteVoiceTags=False
	def _get_backquoteVoiceTags(self):
		return self._backquoteVoiceTags

	def _set_backquoteVoiceTags(self, enable):
		if enable == self._backquoteVoiceTags:
			return
		self._backquoteVoiceTags = 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 = self.getVParam(_ibmeci.rate)
		if self._rateBoost: val=int(round(val/self.RATE_BOOST_MULTIPLIER))
		return self._paramToPercent(val, minRate, maxRate)

	def _set_rate(self,vl):
		val = self._percentToParam(vl, minRate, maxRate)
		if self._rateBoost: val = int(round(val *self.RATE_BOOST_MULTIPLIER))
		self._rate = val
		self.setVParam(_ibmeci.rate, val)

	def _get_pitch(self):
		return self.getVParam(_ibmeci.pitch)

	def _set_pitch(self,vl):
		self.setVParam(_ibmeci.pitch,vl)

	def _get_volume(self):
		return self.getVParam(_ibmeci.vlm)

	def _set_volume(self,vl):
		self.setVParam(_ibmeci.vlm,int(vl))

	def _set_inflection(self,vl):
		vl = int(vl)
		self.setVParam(_ibmeci.fluctuation,vl)

	def _get_inflection(self):
		return self.getVParam(_ibmeci.fluctuation)

	def _set_hsz(self,vl):
		vl = int(vl)
		self.setVParam(_ibmeci.hsz,vl)

	def _get_hsz(self):
		return self.getVParam(_ibmeci.hsz)

	def _set_rgh(self,vl):
		vl = int(vl)
		self.setVParam(_ibmeci.rgh,vl)

	def _get_rgh(self):
		return self.getVParam(_ibmeci.rgh)

	def _set_bth(self,vl):
		vl = int(vl)
		self.setVParam(_ibmeci.bth,vl)

	def _get_bth(self):
		return self.getVParam(_ibmeci.bth)

	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[9])
	def _set_voice(self,vl):
		_ibmeci.set_voice(vl)
	def getVParam(self,pr):
		return _ibmeci.getVParam(pr)

	def setVParam(self, pr,vl):
		_ibmeci.setVParam(pr, vl)

	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))
		self.setVParam(_ibmeci.rate, self._rate)
#  if 'ibmtts' in config.conf['speech']:
#   config.conf['speech']['ibmtts']['pitch'] = self.pitch

	def _get_variant(self): return self._variant
예제 #2
0
파일: espeak.py 프로젝트: yang123vc/nvda
class SynthDriver(SynthDriver):
	name = "espeak"
	description = "eSpeak NG"

	supportedSettings=(
		SynthDriver.VoiceSetting(),
		SynthDriver.VariantSetting(),
		SynthDriver.RateSetting(),
		# Translators: This is the name of the rate boost voice toggle
		# which further increases the speaking rate when enabled.
		BooleanSynthSetting("rateBoost",_("Rate boos&t")),
		SynthDriver.PitchSetting(),
		SynthDriver.InflectionSetting(),
		SynthDriver.VolumeSetting(),
	)

	@classmethod
	def check(cls):
		return True

	def __init__(self):
		_espeak.initialize()
		log.info("Using eSpeak version %s" % _espeak.info())
		lang=languageHandler.getLanguage()
		_espeak.setVoiceByLanguage(lang)
		self._language=lang
		self._variantDict=_espeak.getVariantDict()
		self.variant="max"
		self.rate=30
		self.pitch=40
		self.inflection=75

	def _get_language(self):
		return self._language

	PROSODY_ATTRS = {
		speech.PitchCommand: "pitch",
		speech.VolumeCommand: "volume",
		speech.RateCommand: "rate",
	}

	IPA_TO_ESPEAK = {
		u"θ": u"T",
		u"s": u"s",
		u"ˈ": u"'",
	}

	def _processText(self, text):
		text = unicode(text)
		# We need to make several replacements.
		return text.translate({
			0x1: None, # used for embedded commands
			0x3C: u"&lt;", # <: because of XML
			0x3E: u"&gt;", # >: because of XML
			0x5B: u" [", # [: [[ indicates phonemes
		})

	def speak(self,speechSequence):
		defaultLanguage=self._language
		textList=[]
		langChanged=False
		prosody={}
		# We output malformed XML, as we might close an outer tag after opening an inner one; e.g.
		# <voice><prosody></voice></prosody>.
		# However, eSpeak doesn't seem to mind.
		for item in speechSequence:
			if isinstance(item,basestring):
				textList.append(self._processText(item))
			elif isinstance(item,speech.IndexCommand):
				textList.append("<mark name=\"%d\" />"%item.index)
			elif isinstance(item,speech.CharacterModeCommand):
				textList.append("<say-as interpret-as=\"characters\">" if item.state else "</say-as>")
			elif isinstance(item,speech.LangChangeCommand):
				if langChanged:
					textList.append("</voice>")
				textList.append("<voice xml:lang=\"%s\">"%(item.lang if item.lang else defaultLanguage).replace('_','-'))
				langChanged=True
			elif isinstance(item,speech.BreakCommand):
				textList.append('<break time="%dms" />' % item.time)
			elif type(item) in self.PROSODY_ATTRS:
				if prosody:
					# Close previous prosody tag.
					textList.append("</prosody>")
				attr=self.PROSODY_ATTRS[type(item)]
				if item.multiplier==1:
					# Returning to normal.
					try:
						del prosody[attr]
					except KeyError:
						pass
				else:
					prosody[attr]=int(item.multiplier* 100)
				if not prosody:
					continue
				textList.append("<prosody")
				for attr,val in prosody.iteritems():
					textList.append(' %s="%d%%"'%(attr,val))
				textList.append(">")
			elif isinstance(item,speech.PhonemeCommand):
				# We can't use unicode.translate because we want to reject unknown characters.
				try:
					phonemes="".join([self.IPA_TO_ESPEAK[char] for char in item.ipa])
					# There needs to be a space after the phoneme command.
					# Otherwise, eSpeak will announce a subsequent SSML tag instead of processing it.
					textList.append(u"[[%s]] "%phonemes)
				except KeyError:
					log.debugWarning("Unknown character in IPA string: %s"%item.ipa)
					if item.text:
						textList.append(self._processText(item.text))
			elif isinstance(item,speech.SpeechCommand):
				log.debugWarning("Unsupported speech command: %s"%item)
			else:
				log.error("Unknown speech: %s"%item)
		# Close any open tags.
		if langChanged:
			textList.append("</voice>")
		if prosody:
			textList.append("</prosody>")
		text=u"".join(textList)
		_espeak.speak(text)

	def cancel(self):
		_espeak.stop()

	def pause(self,switch):
		_espeak.pause(switch)

	_rateBoost = False
	RATE_BOOST_MULTIPLIER = 3

	def _get_rateBoost(self):
		return self._rateBoost

	def _set_rateBoost(self, enable):
		if enable == self._rateBoost:
			return
		rate = self.rate
		self._rateBoost = enable
		self.rate = rate

	def _get_rate(self):
		val=_espeak.getParameter(_espeak.espeakRATE,1)
		if self._rateBoost:
			val=int(val/self.RATE_BOOST_MULTIPLIER)
		return self._paramToPercent(val,_espeak.minRate,_espeak.maxRate)

	def _set_rate(self,rate):
		val=self._percentToParam(rate, _espeak.minRate, _espeak.maxRate)
		if self._rateBoost:
			val=int(val*self.RATE_BOOST_MULTIPLIER)
		_espeak.setParameter(_espeak.espeakRATE,val,0)

	def _get_pitch(self):
		val=_espeak.getParameter(_espeak.espeakPITCH,1)
		return self._paramToPercent(val,_espeak.minPitch,_espeak.maxPitch)

	def _set_pitch(self,pitch):
		val=self._percentToParam(pitch, _espeak.minPitch, _espeak.maxPitch)
		_espeak.setParameter(_espeak.espeakPITCH,val,0)

	def _get_inflection(self):
		val=_espeak.getParameter(_espeak.espeakRANGE,1)
		return self._paramToPercent(val,_espeak.minPitch,_espeak.maxPitch)

	def _set_inflection(self,val):
		val=self._percentToParam(val, _espeak.minPitch, _espeak.maxPitch)
		_espeak.setParameter(_espeak.espeakRANGE,val,0)

	def _get_volume(self):
		return _espeak.getParameter(_espeak.espeakVOLUME,1)

	def _set_volume(self,volume):
		_espeak.setParameter(_espeak.espeakVOLUME,volume,0)

	def _getAvailableVoices(self):
		voices=OrderedDict()
		for v in _espeak.getVoiceList():
			l=v.languages[1:]
			# #5783: For backwards compatibility, voice identifies should always be lowercase
			identifier=os.path.basename(v.identifier).lower()
			voices[identifier]=VoiceInfo(identifier,v.name,l)
		return voices

	def _get_voice(self):
		curVoice=getattr(self,'_voice',None)
		if curVoice: return curVoice
		curVoice = _espeak.getCurrentVoice()
		if not curVoice:
			return ""
		# #5783: For backwards compatibility, voice identifies should always be lowercase
		return curVoice.identifier.split('+')[0].lower()

	def _set_voice(self, identifier):
		if not identifier:
			return
		# #5783: For backwards compatibility, voice identifies should always be lowercase
		identifier=identifier.lower()
		if "\\" in identifier:
			identifier=os.path.basename(identifier)
		self._voice=identifier
		try:
			_espeak.setVoiceAndVariant(voice=identifier,variant=self._variant)
		except:
			self._voice=None
			raise
		self._language=super(SynthDriver,self).language

	def _get_lastIndex(self):
		return _espeak.lastIndex

	def terminate(self):
		_espeak.terminate()

	def _get_variant(self):
		return self._variant

	def _set_variant(self,val):
		self._variant = val if val in self._variantDict else "max"
		_espeak.setVoiceAndVariant(variant=self._variant)

	def _getAvailableVariants(self):
		return OrderedDict((ID,VoiceInfo(ID, name)) for ID, name in self._variantDict.iteritems())
예제 #3
0
class SynthDriver(SynthDriver):
    name = "espeak"
    description = "eSpeak"

    supportedSettings = (
        SynthDriver.VoiceSetting(),
        SynthDriver.VariantSetting(),
        SynthDriver.RateSetting(),
        # Translators: This is the name of the rate boost voice toggle
        # which further increases the speaking rate when enabled.
        BooleanSynthSetting("rateBoost", _("Rate boos&t")),
        SynthDriver.PitchSetting(),
        SynthDriver.InflectionSetting(),
        SynthDriver.VolumeSetting(),
    )

    @classmethod
    def check(cls):
        return True

    def __init__(self):
        _espeak.initialize()
        log.info("Using eSpeak version %s" % _espeak.info())
        lang = languageHandler.getLanguage()
        _espeak.setVoiceByLanguage(lang)
        self._language = lang
        self._variantDict = _espeak.getVariantDict()
        self.variant = "max"
        self.rate = 30
        self.pitch = 40
        self.inflection = 75

    def _get_language(self):
        return self._language

    def speak(self, speechSequence):
        defaultLanguage = self._language
        textList = []
        langChanged = False
        for item in speechSequence:
            if isinstance(item, basestring):
                s = unicode(item)
                # Replace \01, as this is used for embedded commands.
                #Also replace < and > as espeak handles xml
                s.translate({
                    ord(u'\01'): None,
                    ord(u'<'): u'&lt;',
                    ord(u'>'): u'&gt;'
                })
                textList.append(s)
            elif isinstance(item, speech.IndexCommand):
                textList.append("<mark name=\"%d\" />" % item.index)
            elif isinstance(item, speech.CharacterModeCommand):
                textList.append("<say-as interpret-as=\"characters\">" if item.
                                state else "</say-as>")
            elif isinstance(item, speech.LangChangeCommand):
                if langChanged:
                    textList.append("</voice>")
                textList.append(
                    "<voice xml:lang=\"%s\">" %
                    (item.lang if item.lang else defaultLanguage).replace(
                        '_', '-'))
                langChanged = True
            elif isinstance(item, speech.SpeechCommand):
                log.debugWarning("Unsupported speech command: %s" % item)
            else:
                log.error("Unknown speech: %s" % item)
        if langChanged:
            textList.append("</voice>")
        text = u"".join(textList)
        _espeak.speak(text)

    def cancel(self):
        _espeak.stop()

    def pause(self, switch):
        _espeak.pause(switch)

    _rateBoost = False
    RATE_BOOST_MULTIPLIER = 3

    def _get_rateBoost(self):
        return self._rateBoost

    def _set_rateBoost(self, enable):
        if enable == self._rateBoost:
            return
        rate = self.rate
        self._rateBoost = enable
        self.rate = rate

    def _get_rate(self):
        val = _espeak.getParameter(_espeak.espeakRATE, 1)
        if self._rateBoost:
            val = int(val / self.RATE_BOOST_MULTIPLIER)
        return self._paramToPercent(val, _espeak.minRate, _espeak.maxRate)

    def _set_rate(self, rate):
        val = self._percentToParam(rate, _espeak.minRate, _espeak.maxRate)
        if self._rateBoost:
            val = int(val * self.RATE_BOOST_MULTIPLIER)
        _espeak.setParameter(_espeak.espeakRATE, val, 0)

    def _get_pitch(self):
        val = _espeak.getParameter(_espeak.espeakPITCH, 1)
        return self._paramToPercent(val, _espeak.minPitch, _espeak.maxPitch)

    def _set_pitch(self, pitch):
        val = self._percentToParam(pitch, _espeak.minPitch, _espeak.maxPitch)
        _espeak.setParameter(_espeak.espeakPITCH, val, 0)

    def _get_inflection(self):
        val = _espeak.getParameter(_espeak.espeakRANGE, 1)
        return self._paramToPercent(val, _espeak.minPitch, _espeak.maxPitch)

    def _set_inflection(self, val):
        val = self._percentToParam(val, _espeak.minPitch, _espeak.maxPitch)
        _espeak.setParameter(_espeak.espeakRANGE, val, 0)

    def _get_volume(self):
        return _espeak.getParameter(_espeak.espeakVOLUME, 1)

    def _set_volume(self, volume):
        _espeak.setParameter(_espeak.espeakVOLUME, volume, 0)

    def _getAvailableVoices(self):
        voices = OrderedDict()
        for v in _espeak.getVoiceList():
            l = v.languages[1:]
            identifier = os.path.basename(v.identifier)
            voices[identifier] = VoiceInfo(identifier, v.name, l)
        return voices

    def _get_voice(self):
        curVoice = getattr(self, '_voice', None)
        if curVoice: return curVoice
        curVoice = _espeak.getCurrentVoice()
        if not curVoice:
            return ""
        return curVoice.identifier.split('+')[0]

    def _set_voice(self, identifier):
        if not identifier:
            return
        if "\\" in identifier:
            identifier = os.path.basename(identifier)
        self._voice = identifier
        try:
            _espeak.setVoiceAndVariant(voice=identifier, variant=self._variant)
        except:
            self._voice = None
            raise
        self._language = super(SynthDriver, self).language

    def _get_lastIndex(self):
        return _espeak.lastIndex

    def terminate(self):
        _espeak.terminate()

    def _get_variant(self):
        return self._variant

    def _set_variant(self, val):
        self._variant = val if val in self._variantDict else "max"
        _espeak.setVoiceAndVariant(variant=self._variant)

    def _getAvailableVariants(self):
        return OrderedDict((ID, VoiceInfo(ID, name))
                           for ID, name in self._variantDict.iteritems())