Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pyttsx3 .runAndWait stops working after first execution

Tags:

python

pyttsx3

I am working on a piece of code where the functionality of runAndWait is required multiple times (a spelling game where the user has to input spellings being read aloud)

Consider the following code snippet (not from the actual code, but similar enough to what I want):

import pyttsx3

engine = pyttsx3.init()
engine.say("Hello World")
engine.runAndWait()
engine.stop()

engine.say("Hi")
engine.runAndWait()
engine.stop()

When run, I would expect it to say both "Hello World", then "Hi", however it only says "Hello World" when ran.
Why is this the case?
Are there any workarounds?

EDIT #1: Some commenters are asking for hardware/software info, so I will provide it here:
HP Laptop running Windows 11 23H2 (Build 22631.5768), 4GB of RAM, Intel Core i3-1005G1 with base speed at 1.2GHz (according to taskmgr) and Integrated Graphics (I don't know the speaker/sound hardware).

Latest version of pyttsx3 from pip (I attempted to install pyaudio as a fix but it didn't help), so I am using the default engine (on Windows) with pyttsx3.

Sorry for not clarifying what I'm using before.

like image 505
atthegreatestworld Avatar asked Nov 14 '25 15:11

atthegreatestworld


1 Answers

I am not exactly sure what is happening here, but it is a problem with the engine when saying the second word.

import pyttsx3

engine = pyttsx3.init()
engine.say("Hello World")
engine.runAndWait()
print("HELLO CALLED")
engine.stop()

engine.say("Hi")
engine.runAndWait()
print("HI CALLED")
engine.stop()

prints both "HI CALLED" and "HELLO CALLED", meaning there is something wrong with the engine.

My guess is that for some reason the engine is not adding "Hi" to the queue.

There are two workarounds:

One is to create a fresh engine every time you say something.

  1. import pyttsx3
    
    def say(text):
        engine = pyttsx3.init()
        engine.say(text)
        engine.runAndWait()
        del engine
    
    say("Hello World")
    print("SAYING HELLO WORLD")
    
    say("Hi")
    print("SAYING HI")
    

    This means that we have to instantly trigger runAndWait, unless you are fine with something like this:

import pyttsx3

engine = ""
def say(text):
    global engine
    del engine

    engine = pyttsx3.init()
    engine.say(text)
    return engine


engine = say("Hello World") # Have to assign engine every time you wanna say something
engine.runAndWait()
print("SAYING HELLO WORLD")

engine = say("Hi")
engine.runAndWait()
print("SAYING HI")

A limitation with this is that you cannot have multiple phrases in your queue since the engine is getting refreshed every time. Unless you are fine with this:

def say(text, refresh=True):
    global engine
    if refresh:
        del engine

        engine = pyttsx3.init()
        engine.say(text)
        return engine

    engine.say(text)
    return engine

and,

engine = say("Hello World")
engine.runAndWait()
print("SAYING HELLO WORLD")

engine = say("Hi")
engine.runAndWait()
print("SAYING HI")

engine = say("Hi")
engine = say("Hello", refresh=False) # Dont refresh engine since
engine.runAndWait()

Another workaround is to not use runAndWait() between saying the two phrases:

import pyttsx3

engine = pyttsx3.init()
engine.say("Hello World")

engine.say("Hi")
engine.runAndWait()
engine.stop()

Summary:

Workaround #1 is the most flexible while workaround #2 is the easiest to implement.

like image 175
Aadvik Avatar answered Nov 17 '25 06:11

Aadvik



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!