Reputation: 13
When press the button, the mp3 files are played, a message box stating that comes from playing. There is a button to stop the mp3 file in the message box, and I want to close the message box when the mp3 file ends without pressing the button.
It takes some time for the playing window to appear due to various tasks before playing music. So, I changed the order of the code so that when the button is pressed, a window appears first, and the rest of the work is done. However, does not start the next task until the message box is closed because of 'msg.exec_()'. I am very confused as to what to do .
Any help would be greatly appreciated.
def play(self):
file = open("op.txt", "r").read().replace("\n", " ")
tts = gTTS(text = str(file),lang='ko',slow = False)
tts.save("op.mp3")
file = open("./button/b1/b1.txt", "r").read().replace("\n", " ")
tts = gTTS(text = str(file),lang='ko',slow = False)
tts.save("voice.mp3")
file = open("./button/b1/b1-1.txt", "r").read().replace("\n", " ")
tts = gTTS(text = str(file),lang='ko',slow = False)
tts.save("voice2.mp3")
sound1 = AudioSegment.from_file("./op.mp3", format="mp3")
sound2 = AudioSegment.from_file("./voice.mp3", format="mp3")
sound3 = AudioSegment.from_file("./voice2.mp3", format="mp3")
combined = sound1 + sound2 + sound3
file_handle = combined.export("./complite.mp3", format="mp3")
pygame.init()
pygame.mixer.music.load('./complite.mp3')
pygame.mixer.music.play(0)
if not pygame.mixer.music.get_busy():
self.msg.close()
self.msg.setIcon(QMessageBox.Information)
self.msg.setWindowTitle('Playing')
self.msg.setText('playing...')
self.msg.setStandardButtons(QMessageBox.Cancel)
retval = self.msg.exec_()
if retval == QMessageBox.Cancel :
pygame.mixer.music.stop()
Upvotes: 1
Views: 450
Reputation: 243955
Instead of using pygame to play the audio, you should use QMediaPlayer since it allows easier handling for Qt since it has signals that indicate the state of the playback in addition to using the Qt eventloop.
On the other hand, you must execute the text-to-speech process in a secondary thread so as not to block the GUI, also it is not necessary to generate intermediate files since you can reproduce the bytes.
import io
import sys
import threading
from functools import cached_property
from PyQt5.QtCore import pyqtSignal, QBuffer, QIODevice, QObject
from PyQt5.QtWidgets import QApplication, QMessageBox, QPushButton, QVBoxLayout, QWidget
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from gtts import gTTS
from pydub import AudioSegment
class Translator(QObject):
started = pyqtSignal()
finished = pyqtSignal()
translated = pyqtSignal(bytes)
def translate(self, *, texts, language):
threading.Thread(
target=self._translate, args=(texts, language), daemon=True
).start()
def _translate(self, texts, language):
self.started.emit()
sounds = []
for text in texts:
tts = gTTS(text=text, lang=language, slow=False)
fp = io.BytesIO()
tts.write_to_fp(fp)
fp.seek(0)
sounds.append(AudioSegment.from_mp3(fp))
combined = sum(sounds)
fp = io.BytesIO()
combined.export(fp, format="wav")
self.translated.emit(fp.getvalue())
self.finished.emit()
class Widget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
lay = QVBoxLayout(self)
lay.addWidget(self.button)
self.button.clicked.connect(self.handle_button_clicked)
self.translator.translated.connect(self.handle_translate_translated)
self.player.stateChanged.connect(self.handle_player_state_changed)
self.messagebox.finished.connect(self.handle_messagebox_finished)
@cached_property
def button(self):
return QPushButton("Start")
@cached_property
def translator(self):
return Translator()
@cached_property
def player(self):
return QMediaPlayer()
@cached_property
def buffer(self):
return QBuffer()
@cached_property
def messagebox(self):
messagebox = QMessageBox()
messagebox.setIcon(QMessageBox.Information)
messagebox.setWindowTitle("Playing")
messagebox.setText("playing...")
messagebox.setStandardButtons(QMessageBox.Cancel)
return messagebox
def handle_button_clicked(self):
texts = self.load_texts()
self.button.setEnabled(False)
self.translator.translate(texts=texts, language="ko")
def handle_translate_translated(self, data):
self.buffer.close()
self.buffer.setData(data)
self.buffer.open(QIODevice.ReadOnly)
self.player.setMedia(QMediaContent(), self.buffer)
self.player.play()
self.messagebox.open()
def handle_player_state_changed(self, state):
if state == QMediaPlayer.StoppedState:
self.messagebox.close()
self.button.setEnabled(True)
def handle_messagebox_finished(self):
self.player.stop()
def load_texts(self):
texts = []
for filename in ("op.txt", "./button/b1/b1.txt", "./button/b1/b1-1.txt"):
with open(filename, "r") as f:
text = f.read().replace("\n", " ")
texts.append(text)
return texts
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = Widget()
widget.show()
sys.exit(app.exec_())
Upvotes: 1