PortAudio 回调和 ASIO sdk 的输入延迟
Posted
技术标签:
【中文标题】PortAudio 回调和 ASIO sdk 的输入延迟【英文标题】:input delay with PortAudio callback and ASIO sdk 【发布时间】:2015-10-16 13:17:48 【问题描述】:我正在尝试使用 portaudio 库和 ASIO sdk 从我的吉他获取输入以通过我的计算机播放。
我一直在关注官方网站上的一些教程来设置基础知识。目前我让它工作了,所以 portaudio 正在监听正确的输入和输出设备,我有回调设置来输出输入并且像这样不做任何事情:
static int paTestCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
float *out = (float*)outputBuffer;
float* in = (float*)inputBuffer;
for (int i = 0; i<framesPerBuffer; i++)
*out++ = *in++; /* left */
*out++ = *in++; /* right */
return 0;
这个回调是通过调用这个来设置的:
PaError error = Pa_OpenDefaultStream(&stream, 2, 2, paFloat32, 44100, paFramesPerBufferUnspecified, paTestCallback, &data);
Pa_StartStream(stream);
现在,这确实有效,但是当我在吉他上敲弦以及通过监视器听到它时,我有很多延迟(大约 0.5 秒)。
有没有办法解决这个延迟?需要重写回调方法吗?
编辑:
所以,使用此代码而不是基本的Pa_OpenDefaultStream()
,我得到了更好的延迟
int defaultIn = Pa_GetDefaultInputDevice();
int defaultOut = Pa_GetDefaultOutputDevice();
PaStreamParameters *inParam = new PaStreamParameters();
inParam->channelCount = 2;
inParam->device = defaultIn;
inParam->sampleFormat = paFloat32;
inParam->suggestedLatency = 0.05;
PaStreamParameters *outParam = new PaStreamParameters();
outParam->channelCount = 2;
outParam->device = defaultOut;
outParam->sampleFormat = paFloat32;
outParam->suggestedLatency = 0;
error = Pa_OpenStream(&stream, inParam, outParam, 44100, paFramesPerBufferUnspecified, paNoFlag, paTestCallback, &data);
if (error != paNoError)
Logger::log("[PortAudioManager] Could not open default stream. Exiting function...");
return;
Pa_StartStream(stream);
不过还是有一点延迟,主要是在演奏多于一个音符时很明显。
编辑:
在 Ross-Bencina 的帮助下,我发现 Windows 默认输入设备和输出设备不会对 PortAudio 中主机 api 的索引进行任何更改。我似乎一直在使用 MME。我执行以下操作以获得 ASIO 设备的正确索引:
int hostNr = Pa_GetHostApiCount();
std::vector<const PaHostApiInfo*> infoVertex;
for (int t = 0; t < hostNr; ++t)
infoVertex.push_back(Pa_GetHostApiInfo(t));
然后我检查了哪个是带有 ASIO 的,并将 PaStreamParameters
中的建议延迟设置为 0,延迟现在消失了,声音很好(虽然现在是单声道)。
【问题讨论】:
【参考方案1】:使用paFramesPerBufferUnspecified
,您在正确的轨道上。
ASIO 延迟行为取决于驱动程序。有两种可能:
ASIO 驱动程序让代码(即 PortAudio)请求延迟(可能有一些限制)。 PortAudio 在支持的驱动程序缓冲区大小和您请求的延迟之间找到最佳匹配。
另一种可能性是您的音频接口不提供对延迟设置的编程控制。相反,延迟只能从驱动程序的 ASIO 控制面板 UI 中选择(并且驱动程序将在 PortAudio 上强制固定缓冲区大小)。在这种情况下,您应该调查驱动程序控制面板 UI 以设置最低的可用延迟。
在任何一种情况下,您使用Pa_OpenStream
的方法都接近最佳,但您应该要求输入和输出的延迟为零(在您的编辑中,您要求输入延迟为 50 毫秒,输出延迟为零)。最终结果将是 PortAudio 选择最小的可用 ASIO 缓冲区大小。如果这变得不稳定(音频故障),那么您需要增加请求的延迟。
include/pa_asio.h
公开了一个特定于主机 API 的接口,用于查询驱动程序允许的 ASIO 缓冲区大小(请注意,如果您更改控制面板中的设置,这可能会发生变化)。它还提供了显示驱动程序控制面板 UI 的功能。
编辑:请注意,如果您仅为 ASIO 构建 PortAudio,Pa_GetDefaultInputDevice()
和 Pa_GetDefaultOutputDevice()
只会返回 ASIO 设备。如果您在构建中包含任何其他更常见的 API(例如 WMME 或 DirectSound),它们将被优先作为(最低公分母)默认设备。您可以添加一个检查,确认您实际上正在访问 ASIO 设备:
assert(Pa_GetHostApiInfo(Pa_GetDeviceInfo(Pa_GetDefaultOutputDevice())->hostApi)->type == paASIO);
如果 PortAudio 编译时支持多个主机 API: 获取默认 ASIO 设备:使用 Pa_GetHostApiCount
和 Pa_GetHostApiInfo
枚举主机 API 以查找 ASIO 主机 API。然后从返回的PaHostApiInfo
结构中提取默认的 ASIO 设备索引。
【讨论】:
很高兴听到我在想同样的事情。我尝试将两个延迟都设置为零,这给了我真正的切碎声音。关于 Asio 控制面板:设备加载 portaudio 时没有。它不像我启动 Guitar Rig 时那样显示在我的任务栏中。 我也尝试了PaAsio_ShowControlPanel(defaultIn, hwnd)
,但我收到一个错误,提示我的设备无效。对此有什么想法吗?
嗯。如果您为only ASIO 构建了PortAudio,Pa_GetDefaultInputDevice
只会返回一个 ASIO 设备。如果您还使用例如WMME 或 DirectSound,然后 Pa_GetDefaultInputDevice 将通过 ASIO 返回那些。您可能需要确定哪个设备是您的 ASIO 服务。例如通过运行 pa_devs 或检索默认 ASIO 设备(查看设备枚举 API 了解详细信息)。
天哪!非常感谢你。我认为在 Windows 选项中设置默认播放和录制设备会更改这些值,但事实并非如此。我列出了所有的 hostAPI,然后就这样搞定了!
设置 Windows 默认设备永远不会选择 ASIO。很高兴你让它工作了:)以上是关于PortAudio 回调和 ASIO sdk 的输入延迟的主要内容,如果未能解决你的问题,请参考以下文章