pythonpyqtpyqt5qmediaplayer

How to play a numpy array in Qt without saving it to a file?


QMediaPlayer can be used to play a music file i.e., *.wav, *.mp3, etc. But can I use it to play a wave recorded in an array?

From the official documentation, I found QMediaPlayer::setMedia has a parameter stream. I guess this API can be used to play music in an array, however, the documentation doesn't give more details about the stream format or how to construct a stream from a wave array.

(We can assume this array contains float values ranging from -1 to 1 and the sampling rate is a known variable.)


Solution

  • The logic is to convert the array into a set of bytes that has some format that is supported by QtMultimedia such as wav, mp3, etc, and then use a QBuffer as a container for those bytes.

    import io
    import os
    
    import librosa
    from scipy.io import wavfile
    from PyQt5 import QtCore, QtMultimedia
    
    CURRENT_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)))
    
    
    def main():
        app = QtCore.QCoreApplication([])
    
        filename = os.path.join(CURRENT_DIR, "sound.mp3")
        data, fs = librosa.load(filename)
    
        # convert arrat to bytes
        f = io.BytesIO()
        wavfile.write(f, fs, data)
    
        # copy the bytes to a QBuffer
        buf = QtCore.QBuffer()
        buf.setData(f.getvalue())
        buf.open(QtCore.QIODevice.ReadOnly)
    
        player = QtMultimedia.QMediaPlayer()
        player.setMedia(QtMultimedia.QMediaContent(), buf)
    
        def handle_state_changed(state):
            if state == QtMultimedia.QMediaPlayer.StoppedState:
                QtCore.QCoreApplication.quit()
    
        player.stateChanged.connect(handle_state_changed)
        player.play()
    
        app.exec_()
    
    
    if __name__ == "__main__":
        main()