2

I was in the process of making a program that simply repeats any text you enter, and seemed to be working when I first tested it. The problem is that the second time I attempt to type anything, it crashes and says that permission was denied to the sound file I was recording it to. I believe it is because the file was already opened, but none the less I do not know how to fix it. I am using the gTTS and Pygame modules.

from gtts import gTTS
from tempfile import TemporaryFile
from pygame import mixer

#Plays Sound
def play():
    mixer.init()
    mixer.music.load("Speech.mp3")
    mixer.music.play()
#Voice
def voice(x):
    text = gTTS(text= x, lang= 'en')
    with open("Speech.mp3", 'wb') as f:
        text.write_to_fp(f)
        f.close()
    play()

#Prompts user to enter text for speech
while True:
    voice_input = input("What should Wellington Say: ")
    voice(voice_input)
John Lowe
  • 41
  • 2
  • You don't need to manually close `f` since it is open in a context manager, when you exit the context manager the file is automatically closed. – nbryans Jun 23 '16 at 17:32
  • Thanks, didn't know that, but it still is crashing at the same point. – John Lowe Jun 23 '16 at 17:40
  • Does it tell you what line it's crashing at? Are you running in a protected directory? – nbryans Jun 23 '16 at 17:44
  • Its crashing at: "with open("Speech.mp3", 'wb') as f:" – John Lowe Jun 23 '16 at 17:48
  • What directory are you running your script in? – nbryans Jun 23 '16 at 17:50
  • The project directory created by visual studio. The file can be detected and manipulated by the program, the problem is that it can be only once. – John Lowe Jun 23 '16 at 17:52
  • After the program creates the file, check the permissions on it. I was able to recreate your error by removing write permission (on linux, `chmod -x Speech.mp3`) and then trying this. – nbryans Jun 23 '16 at 17:54
  • 1
    The system holds write permissions – John Lowe Jun 23 '16 at 17:56
  • If you remove the play() function it works, although it only records the sound to a file and does not play it. – John Lowe Jun 23 '16 at 17:59
  • Take a look at this thread [here](http://stackoverflow.com/questions/7746263/how-play-mp3-with-pygame). I'm guessing that when you run `play()` it starts playing, and your program moves onto the next iteration immediately. pygame might 'lock' the file until it's done playing, resulting in an error when you try to access it later and it's still locked. This could be wrong, however, but something to look into. – nbryans Jun 23 '16 at 18:04
  • Nope that doesn't seem to be it, crashing at the same spot – John Lowe Jun 23 '16 at 18:13

3 Answers3

2

Figured it out. I added this function:

def delete():
    sleep(2)
    mixer.music.load("Holder.mp3")
    os.remove("Speech.mp3")

And call it after .play(), so it now simply deletes the file when it is done and then re-creates it when you need to use it next.

nbryans
  • 1,507
  • 17
  • 24
John Lowe
  • 41
  • 2
0

To expand on my comment above (with help from this thread), I think play() may be locking the file. You can manually try the following:

def play():
    mixer.init()
    mixer.music.load("Speech.mp3")
    mixer.music.play()
    while pygame.mixer.music.get_busy(): 
        pygame.time.Clock().tick(10)

or

def play():
    mixer.init()
    mixer.music.load("Speech.mp3")
    mixer.music.play()
    mixer.music.stop()

But this second fix might have the consequence of not hearing anything played back.

Community
  • 1
  • 1
nbryans
  • 1,507
  • 17
  • 24
  • If you do it the second method it doesn't play sound, then crashes, and if you do it the first method it only crashes. – John Lowe Jun 23 '16 at 18:17
0

I fixed the problem by writing to a temporary file and using os.rename:

from gtts import gTTS
from pygame import mixer
import os

play_name = 'Speech.mp3'
save_name = "%s.%s" % (play_name, '.tmp')

def play():
    mixer.music.load(play_name)
    mixer.music.play()

def voice(x):
    text = gTTS(text=x, lang='en')
    with open(save_name, 'wb') as tmp_file:
        text.write_to_fp(tmp_file)
    os.rename(save_name, play_name)

try:
    mixer.init()
    while True:
        voice_input = raw_input("What should Wellington Say: ")
        voice(voice_input)
        play()
except KeyboardInterrupt:
    pass

I ran a test where I typed in a very long sentence and then another sentence while the first one was playing and everything still worked.