AllanChain / blog

Blogging in GitHub issues. Building with Astro.
https://allanchain.github.io/blog/
MIT License
13 stars 0 forks source link

Playing sound with Qt in Python: Error decoding source #184

Open AllanChain opened 2 years ago

AllanChain commented 2 years ago

View Post on Blog

The correct way for playing sound with PySide6 and fixing the "error decoding source".


Qt is a widely adopted GUI framework, but its documentation is quite awful, especially when working in Python. And it's likely that you get the error

QSoundEffect(qaudio): Error decoding source /path/to/the/file

when trying to play some sound effects with Qt. This error message is quite misleading. Apart from the obvious circumstance that the audio file is broken, there might be some other causes.

Cause 1: You are trying to play an MP3 file

MP3 files are not supported. You can convert the MP3 file to a WAV file:

ffmpeg -i ding.mp3 ding.wav

Cause 2: You are passing the path, not URL

QSoundEffect.setSource is expecting an URL, not a Path or str. So any one of these works:

self.soundEffect.setSource(
    QtCore.QUrl.fromLocalFile(Path(__file__).parent / "ding.wav")
)
self.soundEffect.setSource(QtCore.QUrl.fromLocalFile("./ding.wav"))
self.soundEffect.setSource("file:./ding.wav")

But none of these works:

self.soundEffect.setSource("ding.wav")
self.soundEffect.setSource(str(Path(__file__).parent / "ding.wav"))

Appendix: Full code

import sys
from pathlib import Path

from PySide6 import QtCore, QtMultimedia, QtWidgets

class MyWidget(QtWidgets.QWidget):
    def __init__(self, parent=None) -> None:
        super().__init__(parent)

        mainLayout = QtWidgets.QVBoxLayout(self)
        self.soundButton = QtWidgets.QPushButton(text="Play")
        mainLayout.addWidget(self.soundButton)

        self.soundEffect = QtMultimedia.QSoundEffect()
        self.soundEffect.setSource("file:./ding.wav")
        self.soundEffect.setLoopCount(3)

        self.soundButton.clicked.connect(self.soundEffect.play)

if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    widget = MyWidget()
    widget.resize(200, 100)
    widget.show()
    sys.exit(app.exec())