pythonpython-3.xpygametext-to-speech

gTTS unable to save file twice


I am attempting to use gTTS as a realistic text to speech module for a personal assistant project. When querying the google service I am able to save the mp3 file and run it with 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()

Upon running the function "speak" once it succesfully outputs, however when running it again it fails with an error.

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'

The error happens when attempting to save the text to another mp3 again. Thus pygame is unable to play it. I am aware that I can simply change the name of the file to save it but I would rather not. How am I able to accomplish this?


Solution

  • Finally... success...

    I have been researching this problem for several hours. I've tried multiple different sound players in addition to PyGame (pyaudio, playsound, pyglet, ...). I went down the same road everyone else had been down.

    And then.... it hit me... a different road... Use TWO filenames. (a technique called double-buffering).

    While I didn't use this particular code, I thought I should present an answer using your code....

    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
    

    The reason it works is that the TTS library will release the previous file when it switches to the new one. The problem we were facing when trying to use 1 filename is that we struggled to find a way to get the file resource freed up. This method frees it when you switch to the other filename.

    Enjoy internet! Go make some cool programs!