读取QAudioProbe缓冲区

2024-09-28 22:25:18 发布

您现在位置:Python中文网/ 问答频道 /正文

Qt文档(https://doc.qt.io/qtforpython-5/PySide2/QtMultimedia/QAudioBuffer.html)说我们应该像这样从QAudioProbe读取缓冲区:

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

这是C++,但我需要用Python来写这个。p>

我不知道如何使用Qt quint16数据类型,甚至不知道如何导入它

这是我的全部代码:

#!/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()

输出:

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

Tags: importfalsedatasizemainaddressqtprobe
1条回答
网友
1楼 · 发布于 2024-09-28 22:25:18

我在一个新的PySide2 5.13.2环境中遇到了同样的问题,运行print(probe.data().toBytes())返回了大小为0的块,我知道这不可能,因为其他内置功能正在访问数据

我和其他任何人一样讨厌这种黑客行为,但如果你想测试东西,可以通过这种方式访问缓冲区内容(请不要在生产代码中使用这种方式):

  1. 通过format了解缓冲区的数据类型、endian属性等,并推断出您需要的正确的C类型(例如,signed int 16)

  2. VoidPtr打印输出中提取打印地址,并将其转换为整数

  3. 通过读取给定地址、给定类型和给定数量的帧来创建numpy数组


代码:

首先,在应用程序的某个地方,您将通过setSourceQAudioProbe连接到源,然后将audioBufferProbed信号连接到一个方法,例如:

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

然后,以下on_audio_probed功能将获取numpy数组并打印其范数,该范数在声音出现时会增加:

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

我刚刚用一个QAudioRecorder测试了它,使用了16位无符号wav,效果“很好”(音频看起来和听起来都不错,请参见下面的屏幕截图)。同样,这基本上是一个模因代码,所以上面任何向你的表亲展示你的音频缓冲应用程序都是非常危险的,不要在严肃的代码中使用。但是在任何情况下,请让我知道是否有其他的解决方法对您有效,或者这在不同的环境下是否也有效!希望如果开发人员看到人们确实在使用这种方法,他们会更快地解决问题:)

enter image description here

干杯
安德烈斯

相关问题 更多 >