我正在尝试实现本文https://stackoverflow.com/a/5319085/1562784中描述的简单延迟/混响,但我遇到了问题。在我记录16bit/16khz样本并在每个记录回调调用中获得8k样本的Windows上,它工作正常。但是在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。
谢谢!
更新:
如已回答的帖子所述,我一次又一次地“混响”旧样本。简单的“如果”解决了一个问题:
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);
}
最佳答案
执行实际混响效果的循环将在相同的样本上多次执行,对函数的调用不同。这是因为您将旧样本保存在缓冲区中,但是每次都对所有样本执行混响。这可能会导致它们在某些时候溢出。
您仅应在新样本上执行混响,而不应对已被修改的样本执行混响。我还建议检查溢出并裁剪到最小值/最大值,而不是在这种情况下包装。
一种适用于任何输入缓冲区大小的混响效果可能更好的方法是维持一个大小为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;
}
}
关于c - 缓冲区较小时的简单混响算法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32374924/