Dispatching a Win32 COM in the background?

David LeBlanc whisper at oz.net
Fri Jun 21 02:50:58 EDT 2002


Hmmm... if this is working for you, that's great - it just looks strange to
me.

If Background_TTS is the background speacher thread, shouldn't it have the
queue.get() in it and the foreground have the queue.put()?

It's also worth noting that self isn't used or needed at the global level,
so self.speech is kind of different ;-)

Actually... tell me how this works :) :

import threading

# Private class
class _speech_processor(threading.Thread):
	def __init__(self, speech_queue, talker):
		threading.Thread.__init__(self)
		self._talk_queue = speech_queue
		self._talker = talker

	def run(self):
		tq = self._talk_queue # tiny speed up?
		talker = self._talker
		while 1: # the main thread will kill us.
			talker.Speak(tq.get())

# end of _speech_processor

class BackgroundSpeaker():
	def __init__(self, debug_mode):
		self._debug_mode = debug_mode
		self._bg = None
		self._speech_queue = None
		self._talker = None
		self._statusOK = 1 # Must be before try/excepts. Success unless failure!
		try:
			from win32com.client import constants # I think this is redundant
       		import win32com.client # since you'll get the constants here too
		except ImportError:
			if (self._debug_mode):
				print "Unable to import Win32COM extensions - are they installed?"
			self._statusOK = 0

		try:
       		self._talker = win32com.client.Dispatch("SAPI.SpVoice")
		except:
			if (self._debug_mode):
				print "Error Initializing Microsoft Speech API."
			self._statusOK = 0

	# leading '_' means private method (by agreement only - not enforced)
	def _start_bg(self):
		import Queue
		self._speech_queue = Queue.Queue()
		self._bg = _speech_processor(self._speech_queue, self._talker)
		self._bg.start()

	def say(self, speech):
		if not self._statusOK:
			if self._debug_mode:
				print "Unable to say: %s." % speech, "Components not installed."
			return
		if self._bg is None:
			self._start_bg()
		self._speech_queue.put(speech)

# end of BackgroundSpeaker

if __name__ == '__main__'

import time
import sys

debug_mode = 1

Speaker = BackgroundSpeaker(debug_mode) # It always creates, even if it
can't talk.

while 1:
	speech = raw_input("Enter a phrase to speak, then hit Enter")
	if speech == "":
		Speaker.say("All done")
		time.sleep(20) # give some time for finishing up.
		sys.exit()
	Speaker.say(speech)

I would be interested in hearing if this works! It may have typos since I
did it all manually. Don't have the speech kit to test with.

HTH,

David LeBlanc
Seattle, WA USA

> -----Original Message-----
> From: python-list-admin at python.org
> [mailto:python-list-admin at python.org]On Behalf Of Steven M. Castellotti
> Sent: Thursday, June 20, 2002 12:12
> To: python-list at python.org
> Subject: RE: Dispatching a Win32 COM in the background?
>
>
> Thanks a lot guys, your suggestions have worked perfectly!
>
> 	Just for the record, here's what the full implementation looks like.
>
> This code allows text to be piped to Microsoft's Text-To-Speech
> sythesizer, spoken in the background, in a thread-safe manner:
>
> #####################################################################
>
> import threading
>
> class Background_TTS(threading.Thread):
>
>    def __init__(self, debug_mode):
>       threading.Thread.__init__(self)
>
>       self.debug_mode = debug_mode
>       self.loop = 1
>
>       import Queue
>       self.text_queue = Queue.Queue()
>
>
>    #####################################################################
>
>    def Speak(self, text):
>       self.text_queue.put(text)
>
>
>    #####################################################################
>
>    def stop(self):
>
>       self.loop = 0
>
>
>    #####################################################################
>
>    def run(self):
>       from win32com.client import constants
>       import win32com.client
>       import time
>
>       speech = win32com.client.Dispatch("SAPI.SpVoice")
>
>       while self.loop:
>
>       if not(self.text_queue.empty()):
>          text = self.text_queue.get()
>          speech.Speak(text)
>          time.sleep(.001)
>
> #####################################################################
>
> initialization looks like this:
>
> try:
>    self.speech = Background_TTS(self.gameInformation.debug_mode)
>    self.speech.start()
> except:
>    if (self.gameInformation.debug_mode):
>    print "Error Initializing Microsoft Speech API."
> else:
>    self.text_to_speech_enabled = 1
>
> #####################################################################
>
> calling the synthesizer:
>
> self.speech.Speak(text)
>
> #####################################################################
>
> and finally, stopping the process:
>
> self.speech.stop()
>
>
>
> 	Once again guys, thanks!
>
> -Steve Castellotti
>  SteveC (at) innocent.com
>  http://cogengine.sourceforge.net/
>
>
>
> On Wed, 19 Jun 2002 18:56:05 -0500, David LeBlanc wrote:
>
> > Hmmm... and the run method of Background could be sitting on one end of
> > a Queue (Queue is thread-safe: see your python doc for details) that's
> > buffering the asyncronous calls on the speacher. The main task then just
> > stuffs a talk request into the queue and the Background processes it
> > when it gets to it.
> >
> > David LeBlanc
> > Seattle, WA USA
> >
> >> -----Original Message-----
> >> From: python-list-admin at python.org
> >> [mailto:python-list-admin at python.org]On Behalf Of Peter Hansen Sent:
> >> Wednesday, June 19, 2002 16:47
> >> To: python-list at python.org
> >> Subject: Re: Dispatching a Win32 COM in the background?
> >>
> >>
> >> "Steven M. Castellotti" wrote:
> >> >
> >> > 2) Make the call inside a thread which produces the same effect.
> >>
> >> This might work (I don't know anything about COM though).  Try putting
> >> your own code inside the run method of a thread:
> >>
> >> import threading
> >> class Background(threading.Thread):
> >>     def __init__(self):
> >>         threading.Thread.__init__(self)
> >>
> >>     def run(self):
> >>         print 'Starting'
> >>         pass   # your own code goes here
> >>         print 'Done'
> >>
> >> >>> b = Background()
> >> >>> b.start()
> >> Starting
> >> <possibly a pause here?>
> >> Done
> >>
> >> If at this point you get a >>> prompt back right away, but the speech
> >> generation is carrying on "in the background" then you're all set. Make
> >> sure you do this with code you've already tested outside of the thread,
> >> so you'll know that any failure is not the fault of your own code...
> >>
> >> -Peter
> >> --
> >> http://mail.python.org/mailman/listinfo/python-list
> --
> http://mail.python.org/mailman/listinfo/python-list






More information about the Python-list mailing list