简体   繁体   English

直接使用 QtMultimedia.QAudioOutput 播放 gtts 缓冲区

[英]play gtts buffer with QtMultimedia.QAudioOutput directly

I want to play sounds with QtMultimedia .我想用QtMultimedia播放声音。

In the case of QMediaPlayer , I could play mp3 file, it is made from gTTS.QMediaPlayer的情况下,我可以播放 mp3 文件,它是由 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.我用 gTTS 模块制作了一个 mp3 文件,我想直接用缓冲区播放声音。

It seems that I can make a valid object but QAudioOutput doesn't do anything.看来我可以制作一个有效的 object 但QAudioOutput没有做任何事情。

I seriarize the mp3 file into a database and fetch it when I like.我将 mp3 文件序列化到数据库中,并在我喜欢的时候获取它。

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.在我的原始代码中,缓冲区数据位于 Qt.UserRole + x 中,我可以随时获取它们。

The playlist is constucted with QTableWidget and QTableWidgetItem.播放列表由QTableWidget和 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:您可以使用 QMediaPlayer,而不是使用 QAudioOutput:

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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM