Python 在游戏循环中运行pyttsx3
我试图在游戏中使用pyttsx3,在游戏中,语音是对游戏中的事件的响应,但是我不知道如何在不暂停游戏循环直到音频结束的情况下执行语音命令。出于这个原因,使用runAndWait()是不好的,我也无法让文档中使用iterate()的示例按照我的需要工作。请参阅下面的代码:Python 在游戏循环中运行pyttsx3,python,pygame,pyttsx,Python,Pygame,Pyttsx,我试图在游戏中使用pyttsx3,在游戏中,语音是对游戏中的事件的响应,但是我不知道如何在不暂停游戏循环直到音频结束的情况下执行语音命令。出于这个原因,使用runAndWait()是不好的,我也无法让文档中使用iterate()的示例按照我的需要工作。请参阅下面的代码: import pyttsx3 import pygame as pg def onStart(name): print('start') def onWord(name, location, length):
import pyttsx3
import pygame as pg
def onStart(name):
print('start')
def onWord(name, location, length):
print('word', name, location, 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似乎在该点停止处理-没有进一步的say命令产生任何声音,只有第一个启动的话语事件触发-启动的单词和完成的话语命令从不触发。我想尽一切办法都试过了,但还是没能成功。有什么想法吗?我不熟悉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",
"orange",
"yellow",
"green",
"blue",
"violet",
"purple",
"black",
"white",
"brown",
]
pygame.init()
window = pygame.display.set_mode((WIDTH, 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, 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
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()
在本例中,我们使用a将文本发送到将执行文本到语音的线程,因此帧计数器不会暂停。不幸的是,我们无法中断演讲,但这对您的应用程序来说可能不是问题
如果你需要进一步解释发生了什么事,请告诉我,我已经尽量保持简单
编辑:看看Windows上的语音中断似乎不起作用,讨论中的解决方法是在一个单独的进程中运行文本到语音引擎,该进程将被终止。我认为,每次需要中断时,可能会导致工艺和发动机重新初始化的启动成本不可接受。它可能适合您的使用。我不熟悉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",
"orange",
"yellow",
"green",
"blue",
"violet",
"purple",
"black",
"white",
"brown",
]
pygame.init()
window = pygame.display.set_mode((WIDTH, 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, 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
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()
在本例中,我们使用a将文本发送到将执行文本到语音的线程,因此帧计数器不会暂停。不幸的是,我们无法中断演讲,但这对您的应用程序来说可能不是问题
如果你需要进一步解释发生了什么事,请告诉我,我已经尽量保持简单
编辑:看看Windows上的语音中断似乎不起作用,讨论中的解决方法是在一个单独的进程中运行文本到语音引擎,该进程将被终止。我认为,每次需要中断时,可能会导致工艺和发动机重新初始化的启动成本不可接受。它可能适合您的使用