读取 QAudioProbe 缓冲区
Reading QAudioProbe buffer
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)
...
我 运行 在一个新的 PySide2 5.13.2
环境中遇到了同样的问题,并且 运行 print(probe.data().toBytes())
返回了大小为 0 的块,我知道这不可能因为其他内置功能正在访问数据。
我和其他人一样讨厌这个 hack,但是如果你想 test 可以通过这种方式访问缓冲区内容(请 do不要在生产代码中使用它):
通过 format 了解缓冲区的数据类型、字节顺序等,并推断出您需要的正确 C 类型(例如 signed int 16)。
从VoidPtr
打印输出中提取打印地址,并将其转换为整数
通过在给定地址、给定类型和给定帧数读取来创建一个 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
我刚刚使用 QAudioRecorder
使用 16 位无符号 wavs 对其进行了测试,它工作“很好”(音频看起来和听起来都不错,请参见下面的屏幕截图)。再次强调,这基本上是一个模因代码,所以任何上面向你的堂兄弟展示你的花哨的音频缓冲应用程序的东西都是非常危险的,不要在严肃的代码中使用。但无论如何,让我知道是否有任何其他解决方法对您有用,或者这是否也适用于不同的环境!希望如果开发人员看到人们实际上在使用这种方法,他们会尽快解决问题 :)
干杯!
安德烈斯
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)
...
我 运行 在一个新的 PySide2 5.13.2
环境中遇到了同样的问题,并且 运行 print(probe.data().toBytes())
返回了大小为 0 的块,我知道这不可能因为其他内置功能正在访问数据。
我和其他人一样讨厌这个 hack,但是如果你想 test 可以通过这种方式访问缓冲区内容(请 do不要在生产代码中使用它):
通过 format 了解缓冲区的数据类型、字节顺序等,并推断出您需要的正确 C 类型(例如 signed int 16)。
从
VoidPtr
打印输出中提取打印地址,并将其转换为整数通过在给定地址、给定类型和给定帧数读取来创建一个 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
我刚刚使用 QAudioRecorder
使用 16 位无符号 wavs 对其进行了测试,它工作“很好”(音频看起来和听起来都不错,请参见下面的屏幕截图)。再次强调,这基本上是一个模因代码,所以任何上面向你的堂兄弟展示你的花哨的音频缓冲应用程序的东西都是非常危险的,不要在严肃的代码中使用。但无论如何,让我知道是否有任何其他解决方法对您有用,或者这是否也适用于不同的环境!希望如果开发人员看到人们实际上在使用这种方法,他们会尽快解决问题 :)
干杯!
安德烈斯