Python pyttsx, how to use external loop

Question:

In my program I need class(which can be some thread) to check some list like “say_list” and when other classes add some text to it, pyttsx say that text.
I search in pyttsx docs and I find some external loops feature but I can not find example which work correctly.
I want something like this:

import pyttsx
import threading

class VoiceAssistant(threading.Thread):
    def __init__(self):
        super(VoiceAssistant, self).__init__()
        self.engine = pyttsx.init()
        self.say_list = []

    def add_say(self, msg):
        self.say_list.append(msg)

    def run(self):
        while True:
            if len(self.say_list) > 0:
                self.engine.say(self.say_list[0])
                self.say_list.remove(self.say_list[0])


if __name__ == '__main__':
    va = VoiceAssistant()
    va.start()

Thanks.

Asked By: destrat18

||

Answers:

I can get the proper results by using python’s built in Queue class:

import pyttsx
from Queue import Queue
from threading import Thread

q = Queue()

def say_loop():
    engine = pyttsx.init()
    while True:
        engine.say(q.get())
        engine.runAndWait()
        q.task_done()

def another_method():
    t = Thread(target=say_loop)
    t.daemon = True
    t.start()
    for i in range(0, 3):
        q.put('Sally sells seashells by the seashore.')
    print "end of another method..."

def third_method():
    q.put('Something Something Something')

if __name__=="__main__":
    another_method()
    third_method()
    q.join() # ends the loop when queue is empty

Above is a simple example I whipped up. It uses the ‘queue/consumer’ model to allow separate functions/classes to access the same queue, then a worker that will execute anytime the queue has items. Should be pretty easy to adapt to your needs.

Further reading about Queues: https://docs.python.org/2/library/queue.html
There appears to be an interface for this in the docs you linked to, but it seemed like you were already on the separate thread track so this seemed closer to what you wanted.

And here’s the modified version of your code:

import pyttsx
from Queue import Queue
import threading

class VoiceAssistant(threading.Thread):
    def __init__(self):
        super(VoiceAssistant, self).__init__()
        self.engine = pyttsx.init()
        self.q = Queue()
        self.daemon = True

    def add_say(self, msg):
        self.q.put(msg)

    def run(self):
        while True:
            self.engine.say(self.q.get())
            self.engine.runAndWait()
            self.q.task_done()


if __name__ == '__main__':
    va = VoiceAssistant()
    va.start()
    for i in range(0, 3):
        va.add_say('Sally sells seashells by the seashore.')
    print "now we want to exit..."
    va.q.join() # ends the loop when queue is empty
Answered By: shark3y

pyttsx3 loop pronunciation

import pyttsx3

voice_text = 'test'

def loopSound():
    def onEnd(name, completed):
        print('finishing', name, completed)
        engine.say(voice_text, 'voice_a')

    engine = pyttsx3.init()
    engine.connect('finished-utterance', onEnd)
    engine.say(voice_text, 'voice_e')
    engine.startLoop()

loopSound()
Answered By: dong
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.