#DRIVERS FOR SAPI 5 AND VOICES!
#NOTE THE CONSTANTS AND IN THE SPEAK FUNCTION AND THE ADDING/OR OF THE VALUES.
from comtypes.client import CreateObject
import _winreg
class constants4tts:
Wait = -1
Sync = 0
Async = 1
Purge = 2
Is_filename = 4
XML = 8
Not_XML = 16
Persist = 32
Punc = 64
class SynthDriver():
name="sapi5"
description="Microsoft Speech API version 5 (sapi.SPVoice)"
_pitch = 0
_voices = []
_wait = -1 #WAIT INDEFINITELY
_sync = 0 #WAIT UNTIL SPEECH IS DONE.
_async = 1 #DO NOT WAIT FOR SPEECH
_purge = 2 #CLEAR SPEAKING BUFFER
_is_filename = 4 #OPEN WAV FILE TO SPEAK OR SAVE TO WAV FILE
_xml = 8 #XML COMMANDS, PRONUNCIATION AND GRAMMER.
_not_xml = 16 #NO XML COMMANDS
_persist_xml = 32 #Changes made in one speak command persist to other calls to Speak.
_punc = 64 #PRONOUNCE ALL PUNCTUATION!
def check(self):
try:
r=_winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT,"SAPI.SPVoice")
r.Close()
return True
except:
return False
#INITIALIZE ENGINE!
def init(self):
try:
self.tts = CreateObject( 'sapi.SPVoice')
self._voice=1
self._voiceCount = len(self.tts.GetVoices())
for v in range(self._voiceCount):
self._voices.append( self.tts.GetVoices()[v])
return True
except:
return False
#TERMINATE INSTANCE OF ENGINE!
def terminate(self):
del self.tts
#NUMBER OF VOICES FOR ENGINE!
def getVoiceCount(self):
return len(self.tts.GetVoices())
#NAME OF A VOICE NUMBER!
def getVoiceName(self, num):
return self.tts.GetVoices()[num-1].GetDescription()
#WHAT IS VOICE RATE?
def getRate(self):
"MICROSOFT SAPI 5 RATE IS -10 TO 10"
return (self.tts.rate)
#WHAT IS THE VOICE PITCH?
def getPitch(self):
"PITCH FOR MICROSOFT SAPI 5 IS AN XML COMMAND!"
return self._pitch
#GET THE ENGINE VOLUME!
def getVolume(self):
"MICROSOFT SAPI 5 VOLUME IS 1% TO 100%"
return self.tts.volume
#GET THE VOICE NUMBER!
def getVoiceNum(self):
return self._voice
#SET A VOICE BY NAME!
def setVoiceByName(self, name):
"VOICE IS SET BY NAME!"
for i in range( self._voiceCount):
vp = self.tts.GetVoices()[ i].GetDescription().find( name)
if vp>=0:
self.tts.Voice = self._voices[i]
# self.tts.Voice = self.tts.GetVoices()[i]
self.tts.Speak( "%s Set!" % name)
self._voice=i+1
break
if i >= self._voiceCount:
self.tts.Speak( "%s Not Found!" % name)
#USED FOR BOOKMARKING AND USE LATER!
def _get_lastIndex(self):
bookmark=self.tts.status.LastBookmark
if bookmark!="" and bookmark is not None:
return int(bookmark)
else:
return -1
#NOW SET ENGINE PARMS!
#SET THE VOICE RATE!
def setRate(self, rate):
"MICROSOFT SAPI 5 RATE IS -10 TO 10"
if rate > 10: rate = 10
if rate < -10: rate = -10
self.tts.Rate = rate
#SET PITCH OF THE VOICE!
def setPitch(self, value):
"MICROSOFT SAPI 5 pitch is really controled with xml around speECH TEXT AND IS -10 TO 10"
if value > 10: value = 10
if value < -10: value = -10
self._pitch=value
#SET THE VOICE VOLUME!
def setVolume(self, value):
"MICROSOFT SAPI 5 VOLUME IS 1% TO 100%"
self.tts.Volume = value
#CREATE ANOTHER INSTANCE OF A VOICE!
def createVoice(self, value=1):
if value > self.getVoiceCount:
value = self.getVoiceCount
if value < 1:
value = 1
new_tts = CreateObject( 'sapi.SPVoice')
return (new_tts.GetVoices()[ value-1])
#SPEAKING TEXT!
#SPEAK TEXT USING BOOKMARKS AND PITCH!
def SpeakText(self, text, wait=False, index=None):
"SPEAK TEXT AND XML FOR PITCH MUST REPLACE ANY <> SYMBOLS BEFORE USING XML BRACKETED TEXT"
flags = constants4tts.XML
text = text.replace( "<", "<")
pitch = ((self._pitch*2)-100)/10
if isinstance(index, int):
bookmarkXML = "" % index #NOTE \" FOR XML FORMAT CONVERSION!
else:
bookmarkXML = ""
flags = constants4tts.XML
if wait is False:
flags += constants4tts.Async
self.tts.Speak( "%s%s" % (pitch, bookmarkXML, text), flags)
#CANCEL SPEAK IN PROGRESS!
def cancel(self):
#if self.tts.Status.RunningState == 2:
self.tts.Speak(None, 1|constants4tts.Purge)
#SET AUDIO STREAM FOR OUTPUT TO A FILE!
def SpeakToWav(self, filename, text):
stream = CreateObject("SAPI.SpFileStream")
tts4file = CreateObject( 'sapi.SPVoice')
from comtypes.gen import SpeechLib
stream.Open( filename, SpeechLib.SSFMCreateForWrite)
tts4file.AudioOutputStream = stream
tts4file.Speak( text, 0)
stream.Close()
del tts4file
#SPEAK TEXT!
def Speak(self, text, wait=0, sync=0, async=0, purge=0, isfile=0, xml=0, not_xml=0, persist=0, punc=0):
"SAPI 5 HAS NO PITCH SO HAS TO BE IN TEXT SPOKEN!"
pitch=self._pitch
self.tts.Speak( "%s" % (pitch, text), wait |sync |async |purge |isfile |xml |not_xml |persist |punc)
#SPEAK TEXT WITHOUT PITCH!
def Speaking(self, text, wait=0, sync=0, async=0, purge=0, isfile=0, xml=0, not_xml=0, persist=0, punc=0):
"SPEAKING A FILE WITHOUT PITCH"
self.tts.Speak( text, wait |sync |async |purge |isfile |xml |not_xml |persist |punc)
#SET THE VOICE BY VALUE!
def setVoice(self,value):
"SET VOICE AND SAY ITS DESCRIPTION!"
if value < 1:
value=1
if value > self._voiceCount:
value = self._voiceCount
self.tts.Voice = self._voices[ value-1]
vd = self.tts.GetVoices()[ value-1].GetDescription()
self.tts.Speak( vd[ vd.find(" "):])
self._voice=value
#READ ALL THE VOICES IN THE ENGINE!
def read_Voices(self):
self.tts.Speak( "Voices are:")
for i in range(1, self._voiceCount+1):
print self.getVoiceName(i)
self.tts.Voice = self.tts.GetVoices()[i-1]
vd = self.tts.GetVoices()[ i-1].GetDescription()
self.tts.Speak( "%d) %s" % (i, vd[ vd.find(" "):]))