I'm trying to make a simple Python script which should take a text as input and using gtts, play it as audio. I'm using the following code, but it's not working and I don't know why.
from gtts import gTTS
import pygame
from io import BytesIO
pygame.init()
def say(text):
tts = gTTS(text=text, lang='en')
fp = BytesIO()
tts.write_to_fp(fp)
fp.seek(0)
pygame.mixer.init()
pygame.mixer.music.load(fp)
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
pygame.time.Clock().tick(10)
say("hello")
Python version 3.9.1
gTTS version 2.2.1
pygame version 2.0.1
Windows 10
EDIT: This is the complete error I get:
pygame 2.0.1 (SDL 2.0.14, Python 3.9.1)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "c:\Users\Marco\Documents\Programmazione\gtts\main2.py", line 19, in <module>
say("hello")
File "c:\Users\Marco\Documents\Programmazione\gtts\main2.py", line 14, in say
pygame.mixer.music.load(fp)
pygame.error: ModPlug_Load failed
I tried this code on Linux and I get error
Module format not recognized
so I think gtts
(Google Text-To-Speech) could change MP3 format (maybe it has better quality) and now pygame
has problem to play it.
In PyGame doc you can even see
"Be aware that MP3 support is limited.
On some systems an unsupported format can crash the program, e.g. Debian Linux."
I tested few other modules and at this moment work for me only pydub
, mpg123
.
I try to use modules which don't have to save in file (I don't check if they do save it on disk somewhere deeper in code) and don't use subprocess to run external player.
pydub - which uses ffmpeg
or libav
and simpleaudio
, pyaudio
(pip install pydub
)
from gtts import gTTS
from io import BytesIO
tts = gTTS(text="Hello", lang='en')
fp = BytesIO()
tts.write_to_fp(fp)
fp.seek(0)
# ---
from pydub import AudioSegment
from pydub.playback import play
song = AudioSegment.from_file(fp, format="mp3")
play(song)
mpg123 - which uses libmpg123
(probably pygame
also use it) (pip install mpg123
)
from gtts import gTTS
from io import BytesIO
tts = gTTS(text="Hello", lang='en')
fp = BytesIO()
tts.write_to_fp(fp)
fp.seek(0)
# ---
from mpg123 import Mpg123, Out123
mp3 = Mpg123()
mp3.feed(fp.read())
out = Out123()
for frame in mp3.iter_frames(out.start):
out.play(frame)
Maybe if to change code in gtts
it could read it even without BytesIO
. because gtts
uses requests
which can give direct acces to file data.