混响算法

时间:2011-03-15 22:45:38

标签: c++ signal-processing

我正在寻找一种简单或评论的混响算法,即使在伪代码中也会有很多帮助。

我找到了一对,但代码往往相当深奥,难以理解。

4 个答案:

答案 0 :(得分:39)

这是一个非常简单的“延迟线”实现,它将在现有数组中产生混响效果(C#,buffershort[]):

int delayMilliseconds = 500; // half a second
int delaySamples = 
    (int)((float)delayMilliseconds * 44.1f); // assumes 44100 Hz sample rate
float decay = 0.5f;
for (int i = 0; i < buffer.length - delaySamples; i++)
{
    // WARNING: overflow potential
    buffer[i + delaySamples] += (short)((float)buffer[i] * decay);
}

基本上,您获取每个样本的值,将其乘以衰减参数,并将结果添加到缓冲区delaySamples中的值。

这将产生真正的“混响”效果,因为每个声音都会在振幅下降的情况下多次被听到。为了获得更简单的回声效果(每个声音仅重复一次),您使用基本相同的代码,只反向运行for循环。

更新:此上下文中的“混响”一词有两个常见用法。我上面的代码示例产生了漫画中常见的经典混响效果,而在音乐应用中,该术语用于表示混响,或者更常见的是创建人工空间效果。

关于混响的文献难以理解的一个重要原因是,创建良好的空间效果需要比我的示例方法更复杂的算法。然而,大多数电子空间效应是使用多个延迟线构建的,因此这个样本有望说明正在发生的事情的基础知识。为了产生非常好的效果,你可以(或者应该)使用FFT甚至简单的模糊来混淆混响的输出。

更新2:以下是多延迟线混响设计的一些提示:

  • 选择不会相互干扰的延迟值(在波形意义上)。例如,如果你有一个500毫秒的延迟和一个250毫秒的延迟,那么会有很多点都有来自两条线的回声,产生不切实际的效果。通常将基本延迟乘以不同的素数,以帮助确保不会发生这种重叠。

  • 在一个大房间里(在现实世界中),当你发出噪音时,你会倾向于听到一些相对不失真的尖锐(几毫秒)尖锐回声,接着是一个更大,更微弱的“云” “回声。您可以通过使用一些向后运行的延迟线来创建初始回声和一些完整的混响线以及一些模糊来创建“云”,从而以低成本实现这种效果。

  • 绝对的最佳技巧(我几乎觉得我不想放弃这个,但是到底是什么)只有在音频是立体声的情况下才有效。如果稍微改变左右声道之间延迟线的参数(例如左声道为490ms,右声道为513ms,左声道为.273衰减,右边为.2631),你会产生很多听起来更逼真的混响。

答案 1 :(得分:23)

数字混响通常有两种形式。

  • 卷积混响通常由convolving impulse response和输入信号工作。脉冲响应通常是真实房间或其他混响源的记录。混响的特征由脉冲响应定义。因此,卷积混响通常提供有限的调整混响字符的方法。

  • 算法混响模仿具有延迟,过滤和反馈网络的混响。不同的方案将以不同的方式组合这些基本构建块。大部分技术都在于了解如何调整网络。算法混响通常会向最终用户公开几个参数,因此可以调整混响字符以适应。

EarLevel的“A Bit About Reverb”帖子是对该主题的精彩介绍。它解释了卷积和算法混响之间的差异,并展示了如何实现每个算法的一些细节。

Julius O. Smith的

Physical Audio Signal Processing有一章关于混响算法,包括一个专门用于Freeverb算法的部分。在搜索一些源代码示例时,略过它可能会有所帮助。

Sean Costello的Valhalla博客充满了有趣的混响花絮。

答案 2 :(得分:5)

您需要的是您想要建模或模拟的房间或混响室的脉冲响应。完整的脉冲响应将包括所有多路径和多路径回波。脉冲响应的长度大致等于脉冲声音完全衰减到可听阈值或给定本底噪声所需的时间长度(采样中)。

给定长度为N的脉冲矢量,您可以通过脉冲矢量对输入矢量(由当前音频输入样本与先前N-1个输入样本连接)的矢量乘法产生音频输出样本,适当的缩放。

有些人通过假设脉冲响应中的大多数抽头(除了1之前的所有抽头)为零来简化这一点,并且仅使用几个缩放的延迟线用于剩余的回声,然后将其添加到输出中。

对于更逼真的混响,您可能希望对每只耳朵使用不同的脉冲响应,并且响应与头部位置有所不同。只有四分之一英寸的磁头移动可能会使脉冲响应中的峰值位置改变1个样本(44.1k速率)。

答案 3 :(得分:1)

您可以使用GVerb。从here获取代码.GVerb是一个LADSPA插件,如果您想了解LADSPA,可以去here

Here是GVerb的维基,包括解释参数和一些即时混响设置。

我们也可以直接在Objc中使用它:

ty_gverb        *_verb;
_verb = gverb_new(16000.f, 41.f, 40.0f, 7.0f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f);
AudioSampleType *samples = (AudioSampleType*)dataBuffer.mBuffers[0].mData;//Audio Data from AudioUnit Render or ExtAuidoFileReader
float lval,rval;
for (int i = 0; i< fileLengthFrames; i++) {
     float value = (float)samples[i] / 32768.f;//from SInt16 to float
     gverb_do(_verb, value, &lval, &rval);
     samples[i] =  (SInt16)(lval * 32767.f);//float to SInt16
}

GVerb是一种单声道效果,但是如果你想要一个立体声效果,你可以分别通过效果运行每个声道,然后根据需要平移和混合处理过的信号和干信号