我目前正在为 Gamebody Advance 编写一些混响算法代码,以便为音乐获得一些环境感觉,而不是让声音变得平淡无奇。一些具有挑战性的限制是 GBA 的低 CPU 速度(~16 MHz ARM CPU)和我在 31536 Hz 时可用于混响缓冲区的 4KiB 内存。也许我可以以一半的速度进行混响以节省一些记忆。目标是将 CPU 预算保持在 5% 以下,我很清楚这是一个非常迫切的目标。我尝试了一些简单的东西,比如简单的反馈线,但结果并没有那么好,听起来更像是回声而不是实际的混响。但是,我可以让 ASM 以大约 2-3% 的 CPU 时间工作。
因此,在尝试在硬件上实现任何东西之前,我编写了一个小 C++ 应用程序来尝试一些算法,并且没有在 GBA 上没有浮点数的怪癖。这是我想出的核心代码:
// processing is done inplace on "buffer"
// samples ares stored L/R alternating
//
// reverbBuffer is a simple mono buffer
// buffer wraparound is already taken care of
//
// My reverb buffer positions are selected by being 'approximately' coprime
//
// NBPOS = 3 (number of taps on the buffer)
for (size_t i = 0; i < todo; i++) {
float dryL = buffer[0];
float dryR = buffer[1];
float wetL = 0.f;
float wetR = 0.f;
for (int i = 0; i < NBPOS; i++) {
wetL += coeffL[i] * reverbBuffer[bufferPos[i]];
wetR += coeffR[i] * reverbBuffer[bufferPos[i]];
}
*buffer++ = dryL + wetMix * wetL;
*buffer++ = dryR + wetMix * wetR;
reverbBuffer[bufferPos[0]] = ((dryL + dryR) * 0.5f) * dryMix + ((wetL + wetR) * 0.5f);
for (int i = 0; i < NBPOS; i++)
bufferPos[i]++;
}
为了测试,我在几个 44.1kHz 的波形文件上使用它,并带有适当更长的混响缓冲区。
所以,我们的结果……好坏参半。我添加了一些逻辑来为反馈系数(-1.0 到 1.0)、“dryMix”和“wetMix”变量(0.0 到 1.0)创建随机值。取决于我有多幸运,要么得到了可怕的金属振荡,要么得到了相当好的结果(我仍然认为没有什么是完美的)。
有什么方法可以为我的反馈抽头找到好的系数吗?除了声音不好之外,我还遇到了不稳定和自振的问题。我没有任何专业的 DSP 知识,但我猜我所有系数的绝对值之和不应超过 1.0(但是对于负系数而言,这似乎并不总是正确的)。
此外,如果没有办法以很有意义的方式计算这些系数,是否至少有一种方法可以随机生成这些系数,而不会导致自振荡?
PS:我在谷歌上搜索了很多关于混响和各种东西的信息,但我没有找到完全适合我的算法。通常它们太基本(单击反馈线)或者它们不够快(因为我需要一些非常快且内存占用少的东西)。