Playing sound with Pyqt4 and QSound

2020-03-08 07:57发布

问题:

To keep it short, after hours of looking for a way to play sound in pyqt4, I still can't figure out why this simple little code wouldn't work? I get no error message or anything, but instead of the sound (I've tried mp3, ogg and wav) I just get a little windows "bing" sound but not the sound file I want actually want. I know there's phonon, but I really want to use QSound for various reasons, also because it's supposed to be much simpler. If you could give me any hint to why this isn't working or give an example of working code using QSound, I'd be extremely thankful.

import sys
from PyQt4 import QtGui, QtCore
from PyQt4.QtGui import QSound

class Example(QtGui.QMainWindow):

    def __init__(self):
        QtGui.QMainWindow.__init__(self)

        self.initUI()

    def initUI(self):

        self.setGeometry(300,300,200,200)

        self.b1 = QtGui.QPushButton("Play", self)
        self.b1.clicked.connect(self.Play)
        self.b1.move(50, 80)


    def Play(self):

        QSound.play("C:\directory\b1.mp3")




def main():
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

回答1:

You may have two different problems here.


First, if you want to use Windows-style pathnames, you need to use either raw strings or backslash escapes. In a regular string, \b is a single backspace character, not a \ followed by a b. In other words, you're trying to play the file 'C:\directory\x081.mp3', when you really want to play the file C:\\directory\\b1.mp3. See String and Bytes literals in the docs for details.

You can try to memorize all of the special backslash-escape characters, but the simpler solution is to just always escape all backslashes. Or, even simpler, use raw strings for all Windows-style pathnames. Or, even simpler, if the function you're using allows POSIX-style pathnames even on Windows, just use them. In other words, one of the following:

"C:\directory\\b1.mp3"
"C:\\directory\\b1.mp3"
r"C:\directory\b1.mp3"
"C:/directory/b1.mp3"

On top of that, if you're using an older version of PyQt, you can't call static Qt methods that way. In other words, you're not calling the QSound::play(filename) static method, but the QSound::play() instance (slot) method. In later versions, this should be fine—although, as the documentation says, constructing a QSound and calling its play method "may… play more immediately", so you may want to do it anyway.

If you have this problem, the way to fix it is:

QSound(r"C:\directory\b1.mp3").play()

Although in realistic code, you may want to keep most of your QSound objects around instead of re-creating them each time.


In a comment, you say:

I found out that QSound actually does not support resources. Unfortunately I have no clue what that means, maybe you could explain what that means for my code.

It doesn't mean anything for your code, at least not today. You've got your sounds in regular files, and you're trying to access those files by absolute pathname.

But if you want to improve your app in the future, it might get in the way.

Resources are explained in The Qt Resource System. The idea is that, instead of having a bunch of separate files for images, etc., you just have one executable file like MyApp.exe, with all of the resource files crammed into that executable. At runtime, you can still access these resources almost as if they were still separate files. You just use special paths like :/sounds/b1.mp3 (or, better, switch from pathnames to URLs, and use special URLs like qrc:///sounds/b1.mp3).

The kicker is that "almost". A few features don't work directly on resources, so you have to explicitly extract a resource to a temporary file if you want to use those features.