【问题标题】:Reading QAudioProbe buffer读取 QAudioProbe 缓冲区
【发布时间】:2021-03-01 05:33:02
【问题描述】:

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 编写。

我不知道如何使用 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)
...

【问题讨论】:

  • 使用 print(probe.data().toBytes()) 但根据您显示的日志,它的数据大小为 0。
  • 这令人失望。你知道在 PySide2/Python 中显示 WAV 文件响度级别的其他方法吗?
  • 我有同样的问题,我尝试使用那个 byte_array = (ctypes.c_uint8 * length_array).from_address(buff.constData().__int__()) 但没有结果
  • @devdev 评论该错误以引起开发者的关注

标签: python qt qt5 pyside pyside2


【解决方案1】:

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

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

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

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

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


代码:

首先,在您的应用程序的某个地方,您将通过setSource 将您的QAudioProbe 连接到您的源,然后将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

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

干杯!
安德烈斯

【讨论】:

  • 很高兴它有帮助。请密切关注它。就我而言,到目前为止它一直很稳定,连续多天服务
猜你喜欢
  • 1970-01-01
  • 2012-03-15
  • 1970-01-01
  • 1970-01-01
  • 2020-07-13
  • 1970-01-01
  • 2012-09-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多