读取 QAudioProbe 缓冲区 [英] Reading QAudioProbe buffer

查看:68
本文介绍了读取 QAudioProbe 缓冲区的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Qt 文档(

干杯!
安德烈斯

The Qt documentation (https://doc.qt.io/qtforpython-5/PySide2/QtMultimedia/QAudioBuffer.html) says that we should read the buffer from QAudioProbe like this:

// With a 16bit sample buffer:
quint16 *data = buffer->data<quint16>(); // May cause deep copy

This is C++, but I need to write this in Python.

I am not sure how to use the Qt quint16 data type or even how to import it.

Here is my full code:

#!/bin/python3

from PySide2.QtMultimedia import QMediaPlayer, QMediaContent, QAudioProbe, QAudioBuffer
from PySide2.QtCore import QUrl, QCoreApplication, QObject, Signal, Slot
import sys


def main():

    app = QCoreApplication()
    player = QMediaPlayer()
    url = QUrl.fromLocalFile("/home/ubuntu/sound.wav")
    content = QMediaContent(url)
    player.setMedia(content)
    player.setVolume(50)

    probe = QAudioProbe()
    probe.setSource(player)
    probe.audioBufferProbed.connect(processProbe)

    player.play()


def processProbe(probe):
    print(probe.data())


if __name__ == "__main__":
    main()

Output:

shiboken2.shiboken2.VoidPtr(Address 0x2761000, Size 0, isWritable False)
shiboken2.shiboken2.VoidPtr(Address 0x2761000, Size 0, isWritable False)
shiboken2.shiboken2.VoidPtr(Address 0x2761000, Size 0, isWritable False)
shiboken2.shiboken2.VoidPtr(Address 0x2761000, Size 0, isWritable False)
...

解决方案

I ran into the same issue with a fresh PySide2 5.13.2 environment, and running print(probe.data().toBytes()) returned chunks of size 0 which I knew couldn't be the case because other built-in functionality was accessing the data.

I hate this hack as much as anyone else, but if you want to test things it is possible to access the buffer contents this way (please do not use this in production code):

  1. Find out about the datatype, endian-ness etc of your buffer via format, and infer the proper C type that you'll need (e.g. signed int 16).

  2. Extract the printed address from the VoidPtr printout, and convert it to an integer

  3. Create a numpy array by reading at the given address, with the given type, and by the given amount of frames.


Code:

First of all, somewhere in your app, you'll be connecting your QAudioProbe to your source via setSource, and then the audioBufferProbed signal to a method e.g.:

self.audio_probe.audioBufferProbed.connect(self.on_audio_probed)

Then, the following on_audio_probed functionality will fetch the numpy array and print its norm, which should increase in presence of sound:

import numpy as np
import ctypes

def get_buffer_info(buf):
    """
    """
    num_bytes = buf.byteCount()
    num_frames = buf.frameCount()
    #
    fmt = buf.format()
    sample_type = fmt.sampleType()  # float, int, uint
    bytes_per_frame = fmt.bytesPerFrame()
    sample_rate = fmt.sampleRate()
    #
    if sample_type == fmt.Float and bytes_per_frame == 4:
        dtype = np.float32
        ctype = ctypes.c_float
    elif sample_type == fmt.SignedInt and bytes_per_frame == 2:
        dtype = np.int16
        ctype = ctypes.c_int16
    elif sample_type == fmt.UnsignedInt and bytes_per_frame == 2:
        dtype = np.uint16
        ctype = ctypes.c_uint16
    #
    return dtype, ctype, num_bytes, num_frames, bytes_per_frame, sample_rate

def on_audio_probed(audio_buffer):
    """
    """
    cdata = audio_buffer.constData()
    (dtype, ctype, num_bytes, num_frames,
     bytes_per_frame, sample_rate) = get_buffer_info(audio_buffer)
    pointer_addr_str = str(cdata).split("Address ")[1].split(", Size")[0]
    pointer_addr = int(pointer_addr_str, 16)
    arr = np.array((ctype * num_frames).from_address(pointer_addr))
    print(np.linalg.norm(arr))  # should increase in presence of sound


I just tested it with a QAudioRecorder using 16-bit unsigned wavs, and it worked "fine" (audio looked and sounded good, see screenshot below). Again, this is basically a meme code so anything above showing your fancy audio buffered app to your cousins will be extremely risky, do not use in serious code. But in any case let me know if any other workarounds worked for you, or if this also worked in a different context! Hopefully if the devs see that people are actually using this approach they'll fix the issue much sooner :)

Cheers!
Andres

这篇关于读取 QAudioProbe 缓冲区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆