我在回调模式下使用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
输入缓冲区以获取浮动样本并对其进行分析。一切都很好,除了解包有点慢。
答案 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倍。