微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在游戏循环中运行pyttsx3

如何解决在游戏循环中运行pyttsx3

我试图在游戏中使用pyttsx3进行语音响应游戏中的事件,但是我无法弄清楚如何在不暂停游戏循环的情况下执行语音命令,直到音频播放完毕。出于这个原因,使用runAndWait()不好,而且我无法在文档中使用iterate()来运行示例,因为我需要它。请参见下面的代码

import pyttsx3
import pygame as pg

def onStart(name):
   print('start')

def onWord(name,location,length):
    print('word',name,length)

def onEnd(name,completed):
   print('end')

def speak(*args,**kwargs):
    engine.connect('started-utterance',onStart)
    engine.connect('started-word',onWord)
    engine.connect('finished-utterance',onEnd)
    engine.say(*args,**kwargs)

def main():
    engine.startLoop(False)
    n = 0
    while True:

        n += 1
        print(n)
        if n == 3:
            speak('The first utterance.')
        elif n == 6:
            speak('Another utterance.')

        engine.iterate()
        clock.tick(1)

if __name__ == '__main__':
    pg.init()
    engine = pyttsx3.init()
    clock = pg.time.Clock()
    main()
    pg.quit()
    sys.exit()

在此示例中,第一条语句在正确的时间触发,但似乎pyttsx3在该点停止了处理-不再说命令发出任何声音,只有第一个start-utterance事件触发-starts-word并且说完的命令永远不会触发。我已经尽我所能尝试了所有方法,但仍然无法正常工作。有什么想法吗?

解决方法

我对 pyttx3 不熟悉,但是我创建了一个包含pygame事件循环的示例。颜色随着每次单击鼠标事件而变化,并且说出颜色的名称。

import random
import pygame
import pyttsx3

WIDTH = 640
HEIGHT = 480
FPS = 120

simple_colors = [
    "red","orange","yellow","green","blue","violet","purple","black","white","brown",]

pygame.init()
window = pygame.display.set_mode((WIDTH,HEIGHT))
clock = pygame.time.Clock()

# TTS Setup
engine = pyttsx3.init()
engine.startLoop(False)  # have to call iterate in the main loop

# set a random color
current_color = random.choice(simple_colors)
# create a centered rectangle to fill with color
color_rect = pygame.Rect(10,10,WIDTH - 20,HEIGHT - 20)
frames = 0
paused = False
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONUP:
            current_color = random.choice(simple_colors)
            engine.stop()  # interrupt current speech?
            engine.say(f"The next color is {current_color}")

    # update game elements
    pygame.display.set_caption(
        f"Color: {current_color:10} Frame: {frames:10} FPS: {clock.get_fps():.1f}"
    )
    # draw surface - fill background
    window.fill(pygame.color.Color("grey"))
    ## draw image
    window.fill(pygame.color.Color(current_color),color_rect)
    # show surface
    pygame.display.update()
    # call TTS Engine
    engine.iterate()
    # limit frames
    clock.tick(FPS)
    frames += 1
pygame.quit()
engine.endLoop()

如果运行此命令,您将看到描述的问题重复出现,游戏循环暂停,由标题栏中的帧数指示。我使用了更长的句子,而不仅仅是颜色名称,这加剧了这个问题。也许对 pyttx3 有更好理解的人会理解我们都错了。无论如何,我们可以通过在另一个线程中运行“文本到语音”引擎来解决此问题。

import random
import threading
import queue
import pygame
import pyttsx3


# Thread for Text to Speech Engine
class TTSThread(threading.Thread):
    def __init__(self,queue):
        threading.Thread.__init__(self)
        self.queue = queue
        self.daemon = True
        self.start()

    def run(self):
        tts_engine = pyttsx3.init()
        tts_engine.startLoop(False)
        t_running = True
        while t_running:
            if self.queue.empty():
                tts_engine.iterate()
            else:
                data = self.queue.get()
                if data == "exit":
                    t_running = False
                else:
                    tts_engine.say(data)
        tts_engine.endLoop()


WIDTH = 640
HEIGHT = 480
FPS = 120

simple_colors = [
    "red",HEIGHT))
clock = pygame.time.Clock()

# create a queue to send commands from the main thread
q = queue.Queue()
tts_thread = TTSThread(q)  # note: thread is auto-starting

# set a random color
current_color = random.choice(simple_colors)
# Initial voice message
q.put(f"The first color is {current_color}")
# create a centered rectangle to fill with color
color_rect = pygame.Rect(10,HEIGHT - 20)
frames = 0
paused = False
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
            q.put("exit")
        elif event.type == pygame.MOUSEBUTTONUP:
            current_color = random.choice(simple_colors)
            q.put(f"The next color is {current_color}")

    # update game elements
    pygame.display.set_caption(
        f"Color: {current_color:10} Frame: {frames:10} FPS: {clock.get_fps():.1f}"
    )
    # draw surface - fill background
    window.fill(pygame.color.Color("grey"))
    ## draw image
    window.fill(pygame.color.Color(current_color),color_rect)
    # show surface
    pygame.display.update()
    # limit frames
    clock.tick(FPS)
    frames += 1
pygame.quit()

在这种情况下,我们使用queue将文本发送到将执行文本转语音的线程,因此帧计数器不会暂停。不幸的是,我们无法中断讲话,但这对您的应用程序可能不是问题。

如果您需要进一步说明发生什么情况,请告诉我,我试图将其简化。

编辑:查看this issue recorded on github似乎Windows上的语音中断不起作用,该讨论中的解决方法是在一个单独的过程中运行文本转语音引擎,该过程终止了。我认为这可能会在每次需要中断时为过程和引擎重新初始化带来不可接受的启动成本。它可能适合您的使用。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。