在 Windows 10 中使用 PortAudio 修复实时音频

Fixing Real Time Audio with PortAudio in Windows 10

几年前我创建了一个应用程序,它允许我通过缩混 6 通道或 8 通道来处理音频 a.k.a 5.1 作为矩阵立体声编码的 7.1 为此目的我使用了 portaudio 库非常好结果 这是打开流函数和回调以缩混 7.1 信号的示例

 Pa_OpenStream(&Flujo, &inputParameters, &outParameters, SAMPLE_RATE, 1, paClipOff, ptrFunction, NULL);

注意使用的 framesPerBuffer 值只有一 (1),这是我的回调函数

int downmixed8channels(const void *input, void *output, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * info, PaStreamCallbackFlags state, void * userData)
{
    (void)userData;
    (void)info;
    (void)state;
    (void)framesBuffer;

    float *ptrInput = (float*)input;
    float *ptrOutput = (float*)ouput;

    /*This is a struct to identify samples*/

    AudioSamples->L = ptrInput[0];
    AudioSamples->R = ptrInput[1];
    AudioSamples->C = ptrInput[2];
    AudioSamples->LFE = ptrInput[3];
    AudioSamples->RL = ptrInput[4];
    AudioSamples->RR = ptrInput[5];
    AudioSamples->SL = ptrInput[6];
    AudioSamples->SR = ptrInput[7];

    Encoder->8channels(AudioSamples->L,
        AudioSamples->R,
        AudioSamples->C,
        AudioSamples->LFE,
        MuestrasdeAudio->SL,
        MuestrasdeAudio->SR,
        MuestrasdeAudio->RL,
        MuestrasdeAudio->RR,);


    ptrOutput[0] = Encoder->gtLT();
    ptrOutput[1] = Encoder->gtRT();


    return paContinue;
}

正如你所见,输出和输入缓冲区中索引设置的顺序对应于一个离散通道 对于输出 0 = 左声道,1 = 右声道。这曾经运作良好,直到进入 Windows 10 2004,因为我将我的系统更新到这个新版本,我的音频故障和我得到像那些

这些是从 windows 的音频设备面板下的频道测试 window 的声音中捕获的。图像很清楚,我的程序正在丢帧,所以第一个尝试解决这个问题的方法是使用比一个更大的缓冲区来保存样本,然后处理它们然后发送,这是我在第一个中没有使用大于一个的缓冲区大小的原因地方是程序会丢帧。

但是在实现之前我做了一个概念验证,根本不包括音频处理,简单地将数据从输入传递到输出,为此我将 oputput channelCount 参数设置为 8 就像输入一样,结果就这么简单。

    for (int i = 0; i < FramesPerBuffer /*1000*/; i++)
    {
        ptrOutput[i] = ptrOutput[i];
    }

但程序仍在丢弃样本。

接下来我使用了两个回调,一个用于写入缓冲区,另一个用于读取缓冲区并将其发送到输出

    (void)info;
    (void)userData;
    (void)state;
    (void)output;
    
    float* ptrInput = (float*)input;

    for (int i = 0; i < FRAME_SIZE; i++)
    {
        buffer_input[i] = ptrInput[i];
    }

    return paContinue;

回调存储。

    (void)info;
    (void)userData;
    (void)state;
    (void)output;

    float* ptrOutput = (float*)output;

    for (int i = 0; i < FRAME_SIZE; i++)
    {
        AudioSamples->L = (buffer_input[i] );
        AudioSamples->R = (buffer_input[i++]);
        AudioSamples->C = (buffer_input[i++] );
        AudioSamples->LFE = (buffer_input[i++]);
        AudioSamples->SL = (buffer_input[i++] );
        AudioSamples->SR = (buffer_input[i++]);

        Encoder->Encoder(AudioSamples->L, AudioSamples->R, AudioSamples->C, AudioSamples->LFE, 
        AudioSamples->SL, AudioSamples->SR);

        bufferTransformed[w] = (Encoder->getLT() );
        bufferTransformed[w++] = (Encoder->getRT() );
    }

    w = 0;

    for (int i = 0; i < FRAME_REDUCED; i++)
    {
        ptrOutput[i] = buffer_Transformed[i];
    }

return paContinue;

回调处理

处理回调使用每个缓冲区减少的帧,因为 2 个通道少于八个,因为在 portaudio 中,一个帧似乎由每个音频通道的样本组成。

这个也没用,第一个问题,就是怎么同步两个callback,搞了这么多,有什么推荐或者建议,能不能给我解决这个问题,

注意:两个设备的采样率必须相同,我在程序中实现了逻辑来防止这种情况,位深度也相同我使用的是 paFloat32, .portaudio 是 audacity 使用的修改版,因为我想使用他们的 WASAPI 实现 环回

非常感谢!

在一天结束时,我不必以任何方式更改我的回调函数,解决它的方法是将输入和输出参数的参数“.suggestedLatency”更改或增加到 1.0,甚至设备的 defaultLowOutputLatency 或 defaultHighOutputLatency 值会导致很多故障,我对其进行测试直到 1.0 是 de sweepspot,更高的值没有看到改善。

TL;DR 增加了建议的延迟时间,直到故障消失。