PortAudio 回调和 ASIO sdk 的输入延迟

Dri*_*ies 4 c++ portaudio asio steinberg-asio

我正在尝试使用 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;
}
Run Code Online (Sandbox Code Playgroud)

这个回调是通过调用这个来设置的:

PaError error = Pa_OpenDefaultStream(&stream, 2, 2, paFloat32, 44100, paFramesPerBufferUnspecified, paTestCallback, &data);
Pa_StartStream(stream);
Run Code Online (Sandbox Code Playgroud)

现在,这确实有效,但是当我敲击吉他的弦以及通过监听音箱听到它时,我有很多延迟(大约 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);
Run Code Online (Sandbox Code Playgroud)

尽管如此,仍然有一点延迟,当演奏更多而不是单个音符时,最明显。

编辑:

在 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));
}
Run Code Online (Sandbox Code Playgroud)

然后我只是检查了哪个是 ASIO 并将两个中的建议PaStreamParameters延迟设置为 0,延迟现在消失了,声音很好(尽管现在是单声道)。

Ros*_*ina 5

使用paFramesPerBufferUnspecified.

ASIO 延迟行为取决于驱动程序。有两种可能:

  1. ASIO 驱动程序让代码(即 PortAudio)请求延迟(可能有一些限制)。PortAudio 会在受支持的驱动程序缓冲区大小和您请求的延迟之间找到最佳匹配。

  2. 另一种可能性是您的音频接口不提供对延迟设置的编程控制。相反,延迟只能从驱动程序的 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);
Run Code Online (Sandbox Code Playgroud)

如果 PortAudio 编译时支持多个主机 API:要获取默认 ASIO 设备:使用Pa_GetHostApiCountPa_GetHostApiInfo查找 ASIO 主机 API枚举主机 API。然后从返回的PaHostApiInfo结构中提取默认的 ASIO 设备索引。