系列文章目录

  • Delay Line 简介及其 C/C++ 实现
  • LFO 低频振荡器简介及其 C/C++ 实现


文章目录

  • 系列文章目录
  • 一、Delay 是什么
  • 二、Delay 原理
  • 2.1 The Basic Delay
  • 2.2 Delay With Feedback
  • 2.3 Wet & Dry
  • 三、Delay C/C++ 实现
  • 总结
  • 参考



一、Delay 是什么

Delay(延迟)是一种信号处理技术,它将输入信号纪录起来,然后过一段时间再播放。当延迟信号与当前信号混合时,会产生类似回声(Echo)的效果。大多数人都有过在大山中大喊的经历,声音在山谷之间传递,回声余音袅袅。没错,所谓的 Echo 就是这种感觉。看下面两个对比视频,加深对 Echo 的理解:


土拨鼠的尖叫



土拨鼠的尖叫-Echo


毫无疑问,Delay 是当今市场上最强大的音乐制作工具之一。我们听到的几乎所有的调制效果都是用特定的延时创造的。


二、Delay 原理

2.1 The Basic Delay

最简单 Delay,即输入信号与延迟信号叠加得到输出信号,差分方程如下:
java 混音算法 混响delay算法_java 混音算法
其中 java 混音算法 混响delay算法_DSP_02 为延迟时间,更准确的说,表示延迟了 java 混音算法 混响delay算法_DSP_02

java 混音算法 混响delay算法_音频_04


我们对(1)进行 Z 变换,以此来探究 Basic Delay 对频率的影响:

java 混音算法 混响delay算法_欧拉公式_05

java 混音算法 混响delay算法_音频_06 可以推断出它没有极点,只有 D 个零点。接下来求它的零点:

java 混音算法 混响delay算法_音频_07

接下来就是复数次方根的求解了,这部分内容可以参考 「珂学原理」No.110「复数的n次方根」。这里就不在重复视频提到的方法,而是利用欧拉公式求解。让 java 混音算法 混响delay算法_音效处理_08 ,通过欧拉公式转换得到:

java 混音算法 混响delay算法_音效处理_09

由于 java 混音算法 混响delay算法_音频_10 为实数,无复数部分,因此可得:

java 混音算法 混响delay算法_欧拉公式_11

java 混音算法 混响delay算法_java 混音算法_12 时,java 混音算法 混响delay算法_欧拉公式_13

java 混音算法 混响delay算法_音频_14 时,java 混音算法 混响delay算法_欧拉公式_15

java 混音算法 混响delay算法_欧拉公式_16 时,java 混音算法 混响delay算法_DSP_17

我们发现 D 个零点是平均分布在单位元上的,不同 D 的频谱响应如下图所示。

java 混音算法 混响delay算法_音频_18


java 混音算法 混响delay算法_DSP_19

此外,我们还可以在 Audition 上使用 Basic Delay 对扫频信号进行处理,可以看到明显的梳妆特征。

处理前:

java 混音算法 混响delay算法_java 混音算法_20


处理后:

java 混音算法 混响delay算法_音频_21

2.2 Delay With Feedback

Basic Delay 只能产生单一的回声,应用比较有限。大多数 Delay 算法还会包含一个反馈控制,它将延迟后的信号以一定比例送回输入,如下图所示:

java 混音算法 混响delay算法_欧拉公式_22

假设反馈控制那一条信号为 java 混音算法 混响delay算法_java 混音算法_23,那么上图的差分方程为:
java 混音算法 混响delay算法_音效处理_24
进一步推导有:
java 混音算法 混响delay算法_欧拉公式_25
java 混音算法 混响delay算法_欧拉公式_26

对上述差分方程进行 Z 变换得:

java 混音算法 混响delay算法_音频_27

java 混音算法 混响delay算法_音频_28

从公式(6)可知该滤波器有 D 个零点和 D 个极点,平均分布在单位圆内。再一次,复数次方根求解请参考 「珂学原理」No.110「复数的n次方根」。不同 D 值的频响曲线和零极点分布图如下:

java 混音算法 混响delay算法_音效处理_29

2.3 Wet & Dry

我们称处理后的信号为 “湿” 的信号,未经处理的信号为 “干”信号。一种更加实用的 Delay 算法将会 “湿” 信号和 “干” 信号进行 mix,并通过 Wet 和 Dry 两个系数来控制干湿比。其块状图如下:

java 混音算法 混响delay算法_java 混音算法_30

差分方程为:
java 混音算法 混响delay算法_java 混音算法_31

z 变换推导和之前类似,不再赘述了。


三、Delay C/C++ 实现

说完原理,我们来说具体要如何实现。通常,Delay 使用 Delay Line 来实现,整体实现并不复杂,用一个函数就可以简单概况:

void process(AudioBuffer<float> *buffer,
            int delay_samples, float feedback, float dry, float wet) {

    for (size_t c = 0; c < buffer->getNumberChannels(); ++c) {
        float *channel = buffer->getWriterPointer(c);
        auto *dline = dlines_.getDelayLine(c);
        
        for (size_t i = 0; i < buffer->getNumberFrames(); ++i) {
            float in = channel[i];
            float d_y = dline->get(delay_samples);
            float d_x = in + feedback * d_y;

            dline->push(d_x);

            channel[i] = dry * in + wet * d_y;
        }
    }
}

上述代码中:

  1. buffer->getWriterPointer(c)dlines_.getDelayLine(c) ,分别获取当前声道数据和当前声道所使用的 Delay Line
  2. 在第二个 for 循环中,实现了公式(7)中的代码

总结

以上就是今天的全部内容,我们首先介绍了 Delay 是什么,它可以产生 Echo,用于音效制作上;接着介绍了 Delay 的数学原理,从 Basic Delay 逐步发展到最终版本 Delay with Dry&Wet;最后还给出了 Delay 的 C/C++ 实现代码。