I want to play sounds with QtMultimedia
.
In the case of QMediaPlayer
, I could play mp3 file , it is made from gTTS.
(I think it is okay but I don't like the file remains unless I excute codes for deleting it.)
I make a mp3 file with gTTS module and I want to play sounds with the buffer directly.
It seems that I can make a valid object but QAudioOutput
doesn't do anything.
I seriarize the mp3 file into a database and fetch it when I like.
What is short of my code?
Here is the excerpt of my original Code.
In my original code, the buffer data is in Qt.UserRole + x and I can take them whenever.
The playlist is constucted with QTableWidget
and QTableWidgetItem.
from PySide2 import QtCore
from PySide2 import QtWidgets
from PySide2 import QtMultimedia
import os
import PySide2
import sys
dirname = os.path.dirname(PySide2.__file__)
plugin_path = os.path.join(dirname, 'plugins', 'platforms')
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
import gtts
def main():
if QtWidgets.QApplication.instance() is not None:
app = QtWidgets.QApplication.instance()
else:
app = QtWidgets.QApplication([])
widget = QtWidgets.QTableWidget()
widget.setColumnCount(2)
text = "hello"
lang = "en"
onsei = gtts.gTTS(text=text, lang=lang)
buf = QtCore.QBuffer()
buf.setOpenMode( QtCore.QIODevice.WriteOnly)
onsei.write_to_fp(buf)
buf.close()
if not widget.rowCount():
widget.setRowCount(1)
else:
widget.insertRow(1)
nitem = QtWidgets.QTableWidgetItem()
nitem.setText(str(widget.rowCount()))
item = QtWidgets.QTableWidgetItem()
item.setText("{0}_tts_lang_{1}.mp3".format(text, lang))
item.setData(QtCore.Qt.UserRole+1, buf.data())
variant = item.data(QtCore.Qt.UserRole+1)
format = QtMultimedia.QAudioFormat()
format.setSampleRate(8000)
format.setChannelCount(1)
format.setSampleSize(16)
format.setCodec("audio/pcm")
format.setByteOrder(QtMultimedia.QAudioFormat.LittleEndian)
format.setSampleType(QtMultimedia.QAudioFormat.UnSignedInt)
buf = QtCore.QBuffer()
buf.setData(variant)
buf.open(QtCore.QIODevice.ReadOnly)
buf.seek(0)
audio = QtMultimedia.QAudioOutput(format, app)
audio.setVolume(0.5)
audio.setBufferSize(buf.size())
audio.start(buf)
buf.close()
print(67)
# sys.exit(QtWidgets.QApplication.exec_())
sys.exit()
if __name__ == "__main__":
main()
Instead of using QAudioOutput you could use QMediaPlayer:
import sys
import threading
import uuid
from PySide2 import QtCore, QtGui, QtWidgets, QtMultimedia
import gtts
IdentifierRole = QtCore.Qt.UserRole
DataRole = QtCore.Qt.UserRole + 1
DownLoadRole = QtCore.Qt.UserRole + 2
ActiveRole = QtCore.Qt.UserRole + 3
class BackgroundColorDelegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super().initStyleOption(option, index)
color = None
if index.data(DownLoadRole):
color = QtGui.QColor("green")
if index.data(ActiveRole):
color = QtGui.QColor("red")
if color:
option.backgroundBrush = color
class DownLoader(QtCore.QObject):
downloaded = QtCore.Signal(str, QtCore.QByteArray)
def start(self, identifier, text, lang):
threading.Thread(
target=self._execute, args=(identifier, text, lang), daemon=True
).start()
def _execute(self, identifier, text, lang):
tts = gtts.gTTS(text=text, lang=lang)
buf = QtCore.QBuffer()
buf.open(QtCore.QBuffer.ReadWrite)
tts.write_to_fp(buf)
self.downloaded.emit(identifier, buf.data())
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.player = QtMultimedia.QMediaPlayer()
self.current_buff = QtCore.QBuffer()
self.tablewidget = QtWidgets.QTableWidget(
0,
2,
selectionBehavior=QtWidgets.QAbstractItemView.SelectRows,
editTriggers=QtWidgets.QAbstractItemView.NoEditTriggers,
)
delegate = BackgroundColorDelegate(self.tablewidget)
self.tablewidget.setItemDelegateForColumn(0, delegate)
self.tablewidget.itemClicked.connect(self.on_item_clicked)
self.setCentralWidget(self.tablewidget)
self.add_row("hello", "en")
self.add_row("world", "en")
def add_row(self, text, lang):
it = QtWidgets.QTableWidgetItem("{0}_tts_lang_{1}.mp3".format(text, lang))
identifier = str(uuid.uuid4())
it.setData(IdentifierRole, identifier)
downloader = DownLoader(self)
downloader.start(identifier, text, lang)
downloader.downloaded.connect(self.on_downloaded)
downloader.downloaded.connect(downloader.deleteLater)
row = self.tablewidget.rowCount()
self.tablewidget.insertRow(row)
self.tablewidget.setItem(row, 0, it)
@QtCore.Slot(str, QtCore.QByteArray)
def on_downloaded(self, identifier, data):
model = self.tablewidget.model()
indexes = model.match(
model.index(0, 0), IdentifierRole, identifier, flags=QtCore.Qt.MatchExactly
)
if indexes:
item = self.tablewidget.itemFromIndex(indexes[0])
item.setData(DataRole, data)
item.setData(DownLoadRole, True)
@QtCore.Slot("QTableWidgetItem*")
def on_item_clicked(self, item):
self.player.stop()
self.current_buff.close()
data = item.data(DataRole)
if not data:
return
self.current_buff.setData(data)
self.current_buff.open(QtCore.QIODevice.ReadOnly)
self.player.setMedia(QtMultimedia.QMediaContent(), self.current_buff)
self.player.play()
for row in range(self.tablewidget.rowCount()):
it = self.tablewidget.item(row, 0)
it.setData(ActiveRole, it is item)
def main():
app = QtWidgets.QApplication.instance()
if app is None:
app = QtWidgets.QApplication([])
w = MainWindow()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()