gTTS无法两次保存文件

时间:2018-08-08 07:45:30

标签: python python-3.x pygame text-to-speech

我正在尝试将gTTS用作个人助理项目的逼真的文本到语音模块。查询google服务时,我可以保存mp3文件并使用pygame运行它。

from pygame import mixer
from gtts import gTTS    

def speak(data):
    tts = gTTS(text=data, lang='en')
    tts.save('speech.mp3')
    mixer.init()
    mixer.music.load('speech.mp3')
    mixer.music.play()

一旦成功输出“讲话”功能,它就会运行,但是再次运行它会失败,并显示错误。

Traceback (most recent call last):
  File "C:\Users\user1\Desktop\project_ai\assistant.py", line 7, in <module>
    text_to_speech.main('hello')
  File "C:\Users\user1\Desktop\project_ai\modules\speech_text_synthesis\text_to_speech.py", line 8, in main
    tts.save('speech.mp3')                                                                                                                                       File "C:\Users\user1\AppData\Local\Programs\Python\Python36\lib\site-packages\gtts\tts.py", line 246, in save
    with open(savefile, 'wb') as f:                                                                                                                                   PermissionError: [Errno 13] Permission denied: 'speech.mp3'

尝试再次将文本保存到另一个mp3时发生错误。因此pygame无法播放。我知道我可以简单地更改文件名来保存它,但是我不愿意。我怎么能做到这一点?

2 个答案:

答案 0 :(得分:1)

这似乎是pygame的常见问题,至少我在SO上找到了有关此主题的一些已删除问题。

尝试在保存后通过内存映射文件加载文件,而不是仅使用文件名,例如:

import mmap
...
def speak(data):
    tts = gTTS(text=data, lang='en')
    tts.save('speech.mp3')
    with open('speech.mp3') as f: 
        m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) 

    pygame.mixer.music.load(m) 
    pygame.mixer.music.play() 

    m.close() 

使用上下文管理器可确保在将文件复制到内存后实际上已将其关闭,并且pygame.mixer.music.load完全不会触摸文件。

答案 1 :(得分:1)

最后...成功...

我已经研究了几个小时了。除了PyGame(pyaudio,playsound,pyglet等),我还尝试了多种不同的声音播放器。我走的路都是其他人都倒下的。

然后......给我带来了...另一条路... 使用两个文件名。(一种称为双缓冲的技术)。

虽然我没有使用此特定代码,但我想我应该使用您的代码给出答案。...

from pygame import mixer
from gtts import gTTS    

count = 0

def speak(data):
    global count

    tts = gTTS(text=data, lang='en')
    tts.save(f'speech{count%2}.mp3')
    mixer.init()
    mixer.music.load(f'speech{count%2}.mp3')
    mixer.music.play()
    count += 1

它起作用的原因是,当TTS库切换到新文件时,它将释放前一个文件。尝试使用1个文件名时面临的问题是,我们努力寻找一种释放文件资源的方法。当您切换到其他文件名时,此方法将释放它。

享受互联网!去做一些很酷的程序!