我目前正在使用PyAudio来开发轻型录音实用程序,该实用程序可以满足我计划中的应用程序的特定需求。我正在使用ASIO音频接口(interface)。我正在编写程序要做的是通过界面播放wav文件,同时记录界面的输出。该接口(interface)正在实时处理车载信号并更改音频。当我打算将此渲染的输出导入到DAW中时,我需要将输出与输入音频完美同步。使用DAW,我可以同时在界面中播放音频并记录输出。当我这样做时,它已在DAW中完美同步。我的实用程序的目的是能够从python脚本触发此操作。
通过蛮力方法,我想出了一个可行的解决方案,但是现在我陷入了一个魔术数字,并且不确定这是某种常数还是可以计算出的数值。如果是一个数字,我可以计算出这是理想的值,但我仍然想了解这两种方法的来源。
我的回调如下:
def testCallback(in_data, frame_count, time_info, status):
#read data from wave file
data = wave_file.readframes(frame_count)
#calculate number of latency frames for playback and recording
#1060 is my magic number
latencyCalc = math.ceil((stream.get_output_latency() + stream.get_input_latency()) * wave_file.getframerate()) + 1060
#no more data in playback file
if data == "":
#this is the number of times we must keep the loop alive to capture all playback
recordEndBuffer = latencyCalc / frame_count
if lastCt < recordEndBuffer:
#return 0-byte data to keep callback alive
data = b"0"*wave_file.getsampwidth()*frame_count
lastCt += 1
#we start recording before playback, so this accounts for the initial "pre-playback" data in the output file
if firstCt > (latencyCalc/frame_count):
wave_out.writeframes(in_data)
else:
firstCt += 1
return (data, pyaudio.paContinue)
我关心的是函数:
latencyCalc = math.ceil((stream.get_output_latency() + stream.get_input_latency()) * wave_file.getframerate()) + 1060
通过观察输出文件与原始播放文件的偏移量,我将这一计算汇总在一起。发生了两件事,当同时播放时,我的输出文件比原始文件晚开始,并且也早结束了。通过反复试验,我确定在开始时额外增加了特定数量的帧,而在结束时缺少了特定数量的帧。这将计算这些帧数。我确实了解第一部分,它是使用采样率将输入/输出延迟(以秒/亚秒精度提供)转换为帧。但是我不确定如何填写1060的值,因为我不确定它的来源。
我发现通过使用ASIO驱动程序上的延迟设置,我的应用程序将继续正确同步记录的文件,即使由于调整而导致输出/输入延迟超过更改(输入/输出延迟始终是相同的值),因此1060在我的机器上似乎是一致的。但是,我根本不知道这是否是可以计算的值。或者,如果它是一个特定的常数,我不确定它到底代表什么。
任何有助于更好地理解这些值(value)的帮助将不胜感激。我很高兴我的实用程序现在可以正常工作,但是想完全了解这里发生的事情,因为我怀疑潜在地使用其他接口(interface)可能将无法再正常工作(出于某些原因,我希望对此提供支持) )。
编辑2014年4月8日以回应Roberto:
我收到的值(value)
等待时间= Math.ceil((stream.get_output_latency()+ stream.get_input_latency())* wave_file.getframerate())+ 1060
是8576,额外的1060使总延迟达到9636帧。您对我为什么添加1060帧的假设是正确的。我正在通过外部ASIO接口(interface)播放文件,而我希望在记录的文件中捕获的处理是接口(interface)上发生的处理的结果(不是我编写的内容)。为了比较输出,我只播放了测试文件并记录了接口(interface)的输出,而没有任何接口(interface)上的处理效果。然后,我检查了Audacity中的两个音轨,并通过反复试验确定1060是我能使两者最接近的位置。从那以后,我意识到它仍然不是很完美,但是当同时播放时,它非常接近并且听不到检测到(当删除1060偏移时,情况并非如此,会有明显的延迟)。与1060相比,添加/删除额外的框架也是太多的补偿。
我相信您是正确的,额外的延迟来自外部接口(interface)。最初,我想知道是否可以使用我手头的数字信息来计算它,但是我认为它只是接口(interface)中的一个常数。我认为这是对的,因为我确定如果删除1060,文件的偏移量与执行相同的测试完全相同,但是要在Reaper中手动进行(这正是我要自动化的过程)。我得到的延迟要比用新的蛮力抵销来收割的延迟要好得多,所以我将其称为胜利。在我的应用程序中,目标是用新处理的文件完全替换原始文件,因此希望两者之间的绝对最小延迟时间。
回答您关于PyAudio中的ASIO的问题时,答案是肯定的。您必须使用ASIO SDK编译PortAudio,PortAudio才能与ASIO一起运行,然后更新PyAudio设置以这种方式进行编译。幸运的是,我正在使用内置了ASIO支持的http://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio Windows,然后可以通过ASIO访问设备。
最佳答案
由于不允许发表评论,因此我在这里问您:stream.get_output_latency() + stream.get_input_latency()) * wave_file.getframerate()
的值是什么?以及您如何首先获得1060这个数字?
在您已标记的代码行中:latencyCalc = math.ceil((stream.get_output_latency() + stream.get_input_latency()) * wave_file.getframerate()) + 1060
,您只需在总延迟中添加额外的1060帧。从您的描述中,我不清楚您为什么这样做,但是我假设您已经测量了结果文件中的总延迟,并且除了输入延迟+输出延迟之和之外,总是有恒定数量的额外帧。因此,您是否认为这种额外的延迟可能是由于处理造成的?您说您要对输入的音频信号进行一些处理。处理当然要花一些时间。尝试对未更改的输入信号执行相同的操作,然后查看是否减少/消除了额外的延迟。甚至您应用程序的其他部分,例如如果应用程序具有GUI,则所有这些事情都会减慢记录速度。您没有完全描述您的应用程序,但是我猜测额外的延迟是由您的代码以及代码所执行的操作引起的。为什么“魔数”总是一样?因为您的代码始终是相同的。
简历:“魔术数字”代表什么?显然,除了总往返延迟之外,它还表示一些额外的延迟。
是什么导致这种额外的延迟?原因很可能是您代码中的某个地方。您的应用程序正在做的事情需要花费一些额外的时间,因此会造成一些额外的延迟。我想到的唯一可能的另一件事是,您在设置中的某处添加了一些额外的“静默期”,因此您也可以检查一下。
关于python - PyAudio-同步播放和录制,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22879114/