当缓冲区很小时,简单的混响alghoritm

时间:2015-09-03 11:54:47

标签: c linux audio

我试图实现这篇文章https://stackoverflow.com/a/5319085/1562784中描述的简单延迟/混响,但我遇到了问题。在我录制16bit / 16khz样本的窗口上,每次录制回拨电话获得8k样本,它工作正常。但是在linux上我从声卡中得到了更小的块。大概150个样本。因为我修改了延迟/混响代码来缓冲样本:

#define REVERB_BUFFER_LEN 8000

static void reverb( int16_t* Buffer, int N)
{
    int i;
    float decay = 0.5f;
    static int16_t sampleBuffer[REVERB_BUFFER_LEN] = {0};

    //Make room at the end of buffer to append new samples
    for (i = 0; i < REVERB_BUFFER_LEN - N; i++)
        sampleBuffer[ i ] = sampleBuffer[ i + N ] ;     

    //copy new chunk of audio samples at the end of buffer
    for (i = 0; i < N; i++)
        sampleBuffer[REVERB_BUFFER_LEN - N + i ] = Buffer[ i ] ;

    //perform effect
    for (i = 0; i < REVERB_BUFFER_LEN - 1600; i++)
    {
        sampleBuffer[i + 1600] += (int16_t)((float)sampleBuffer[i] * decay);
    }   

    //copy output sample
    for (i = 0; i < N; i++)
        Buffer[ i ] = sampleBuffer[REVERB_BUFFER_LEN - N + i ];


}

这会在输出上产生白噪声,所以显然我做错了。 在linux上,我录制的是16bit / 16khz,就像在Windows上一样,我在VMWare中运行linux。

谢谢!

更新

正如回答的帖子中所指出的那样,我正在反复思考&#39;旧样本一遍又一遍。简单&#39;如果&#39;解决了一个问题:

    for (i = 0; i < REVERB_BUFFER_LEN - 1600; i++)
    {
        if((i + 1600) >= REVERB_BUFFER_LEN - N)
            sampleBuffer[i + 1600] += (int16_t)((float)sampleBuffer[i] * decay);
    }

1 个答案:

答案 0 :(得分:1)

执行实际混响效果的循环将在相同的样本上,在对函数的不同调用上执行多次。这是因为您将旧样本保存在缓冲区中,但每次都对所有样本执行混响。这可能会导致它们在某些时候溢出。

您应该只对新样本执行混响,而不是对已经修改过的样本执行混响。我还建议检查溢出和剪切到最小/最大值,而不是在这种情况下包装。

执行任何输入缓冲区大小的混响的一种更好的方法是维护一个大小为REVERB_SAMPLES(在你的情况下为1600)的循环缓冲区,其中包含最后一个样本。

void reverb( int16_t* buf, int len) {
    static int16_t reverb_buf[REVERB_SAMPLES] = {0};
    static int reverb_pos = 0;

    for (int i=0; i<len; i++) {
        int16_t new_value = buf[i] + reverb_buf[reverb_pos] * decay;
        reverb_buf[reverb_pos] = new_value;
        buf[i] = new_value;
        reverb_pos = (reverb_pos + 1) % REVERB_SAMPLES;
    }
}