PyAudio:在回调模式下使用的最有效的格式和打包/解包方法是什么?

时间:2014-11-07 19:37:15

标签: python audio portaudio pyaudio

我在回调模式下使用pyaudio,paFloat32格式,2个通道,每个缓冲区1024帧,我对更有效的输入/输出音频缓冲区数据交换感兴趣。

要解压缩输入音频缓冲区并获取浮动样本列表,我使用:

fmt       = str( N_CHANNELS * BUFFER_SIZE ) + 'f'
in_floats = struct.unpack( fmt, in_data )

使用struct.pack()struct.unpack()是非常低效的,它需要大量的CPU资源,几乎与音频信号处理本身相同。由于大多数声卡都是16位,我也尝试使用paInt16格式,但结果几乎相同。

在回调模式下使用最有效的格式和打包/解包方法(当然是保持全分辨率)?

编辑:PyAudio使用类似于Portaudio使用的C数据结构的二进制流或缓冲区交换数据。我需要解压缩in_data输入缓冲区以获取浮动样本并对其进行分析。一切都很好,除了解包有点慢。

1 个答案:

答案 0 :(得分:1)

使用NumPy或stdlib的array模块会快得多,因为struct.unpack的大部分费用都不是解包,而是&# #39; s在Python float对象中装箱每个浮点值。

例如:

In [1177]: f = [random.random() for _ in range(65536)]

In [1178]: b = struct.pack('65536f', *f)

In [1179]: %timeit struct.unpack('65536f', b)
1000 loops, best of 3: 1.61 ms per loop

In [1180]: %timeit array.array('f', b)
100000 loops, best of 3: 17.7 µs per loop

这个速度快了100倍。而且无论如何,你都有一个可迭代的浮点数,它只是array而不是tuple

但是,如果您计划对这些值进行任何算术运算,那么您仍然需要迭代这些值 - 并且array必须将其中的每一个取消装箱这样做,这将在你节省的大部分时间里重新加入。

NumPy进来的地方;我怀疑np.frombuffer(b, dtype=np.float32)将比创建array.array('f', b)快得多,但它允许您直接对未装箱的值进行矢量化算术。例如:

In [1186]: a1 = array.array('f', b)

In [1187]: a2 = np.frombuffer(b, dtype=np.float32)

In [1189]: %timeit sum(f)
1000 loops, best of 3: 586 µs per loop

In [1189]: %timeit sum(a1)
1000 loops, best of 3: 907 µs per loop

In [1190]: %timeit a2.sum()
10000 loops, best of 3: 80.3 µs per loop

正如您所看到的,使用array.array会使速度慢两倍(我使用sum,因为实际的迭代和算术是在C中完成的,但使用np.array代替它快5倍。