Jacob,

What you are looking at is called a thread pool. The simple case you
have now is that you start a thread whenever there is work to do
(playing a sound). The thread does this work, then exits. A thread
pool means you have a set number of threads idling and receiving work
via a queue. When work appears, they perform it and then go back to
idle.

There are thread pool implementations for Python that you could simply
plug into your application.

from multiprocessing.pool import ThreadPool

http://code.activestate.com/recipes/203871-a-generic-programming-thread-pool/

In either case, if you are looking to kill off a thread midway through
the work (cut off the sound before it is done playing). Then you will
need to use a flag to inform the thread that you wish for it to stop
playing sound. This means you need a polling loop that will play a
short sample of the track and then check the flag before playing the
next sample. This way the thread can exit part of the way through the
sound.

A thread pool will not save memory. It saves the setup/teardown of
threads. This is a relatively expensive process, and if an application
starts hundreds of thousands of threads during it's lifetime, this
adds up. Think about it, either way, you will need a number of
concurrent threads that equals the number of sounds you wish to play
concurrently. This means a thread pool will have X threads active
(though idle) at all times. The simple case will have X threads active
(and working) only while the sounds are being played. The only real
advantage of the thread pool is that it avoids setup/teardown, so it
could possibly save some latency when playing a new sound. This is
because a new thread does not need to be initialized, it just has to
wake up and start playing the sound. You have to decide if this
latency is a problem and if so, go the thread pool route. Of course,
Python threads are not native threads, so I think any advantage here
probably washes out. My suggestion is to stick with the simple case.

A simple sound player class can do the whole task for you, and your
code will be much easier to follow and debug. Throwing a thread pool
into the mix will complicate things.

Simple case:

class PlaySound(threading.Thread):
    def __init__(self, sound='foobar.wav'):
        self.sound = sound
        self.running = True
        self.sample = 0
        threading.Thread.__init__(self):
        self.start()

    def playsample(self):
        soundlib.play(self.sound, startms=self.sample*100, lengthms=100)
        self.sample += 100

    def run(self):
        while self.running:
            self.playsample()

    def stop(self):
        self.running = False

s = PlaySound('explosion.wav')
if user_exited:
    s.stop()

The main key here is that instead of playing the whole sound file in
one shot, you play only a small portion of it between polls. This way
the thread can stop mid-sound. You need to use a sound library that
will support breaking a sound into multiple parts in order to achieve
this.

Another option here is to ditch threads altogether and find a sound
library that does async playback. Let it handle this mess for you.

http://docs.python.org/library/winsound.html
_______________________________________________
python-win32 mailing list
python-win32@python.org
http://mail.python.org/mailman/listinfo/python-win32

Reply via email to