Python中Sounddevice输入输出信号时间向量同步问题排查
问题
在Python中使用Sounddevice库时,我尝试同时播放输出信号并录制输入信号,之后将两者叠加绘图以还原真实场景。目前使用Stream类,回调函数如下所示:
def callback(indata, outdata, frames, time, status): if status: print(status) if not hasattr(callback, "lastframe"): callback.lastframe = 0 # Initialiser la première fois lastframe = callback.lastframe end = lastframe+frames size = len(out[lastframe:end]) outdata[:size,0] = out[lastframe:end] outsig['signal'] = np.append(outsig['signal'],outdata[:,0]) outsig['time'] = np.append(outsig['time'],np.linspace(time.outputBufferDacTime,time.outputBufferDacTime+(frames-1)/48e3,frames)) callback.lastframe = end insig['signal'] = np.append(insig['signal'],indata) insig['time'] = np.append(insig['time'],np.linspace(time.inputBufferAdcTime,time.inputBufferAdcTime+(frames-1)/48e3,frames)) if size < frames: raise sd.CallbackStop
我通过time.outputBufferDacTime和time.inputBufferAdcTime获取块中首个样本的播放/录制时间,结合采样率和块大小构建输入输出信号的时间向量。目前已接近预期结果,但有时后续块未衔接上(见附图),该伪影未在实际输出中听到,且输入输出不同步,怀疑是代码问题,请问可能的原因是什么?
分析与解决建议
np.append动态扩容引发的实时性问题:回调函数里频繁用np.append扩展数组,会不断触发内存重新分配,一旦回调处理耗时超过块的时间窗口,就会打乱后续块的处理节奏,导致时间戳衔接断裂。Sounddevice对回调的实时性要求极高,这类耗时操作必须避免,建议提前预分配足够大的数组,用索引直接写入数据。- 输入输出时间基准不统一:
outputBufferDacTime和inputBufferAdcTime是硬件层面两个独立的时间基准,输入输出本身存在固定硬件延迟,不同块的时间戳采样点也可能存在偏差,直接用这两个时间向量绘图必然出现同步错位。应该以输出时间戳为基准,根据硬件的输入延迟(可通过sd.query_devices()查看或实际测量)偏移输入信号的时间向量,实现对齐。 - 最后一块的时间向量生成逻辑错误:当
size < frames触发停止时,仍用固定的frames生成时间向量,但实际有效样本数是size,这会导致最后一段时间向量长度和信号长度不匹配,出现衔接伪影。需根据实际size生成对应长度的时间向量。 - 全局变量线程不安全:
outsig、insig和callback.lastframe属于跨线程共享的全局变量,回调线程和主线程对其读写时没有锁保护,可能出现数据或时间戳被错误覆盖的情况,表现为块衔接异常。
内容的提问来源于stack exchange,提问作者bouaaah
相关产品推荐
相关产品推荐

