网络音频合成:如何处理在攻击或释放阶段更改滤波器截止?

Web Audio synthesis: how to handle changing the filter cutoff during the attack or release phase?

我正在使用 WebAudio 构建 Roland Juno-106 合成器的仿真。 The live WIP version is here.

如果在起音或释放期间更改截止频率或包络调制量,同时滤波器同时被包络调制,我不知道如何处理更新滤波器。 That code is located around here。当前的实现不像模拟合成器那样响应,但我不太清楚如何计算它。

在真实的合成器上,滤波器会根据截止频率、包络调制量和包络中的当前阶段而立即改变,但上升或下降也会平滑地继续。

我将如何模拟这种行为?

出色的项目!

您不需要自己求和 - Web Audio AudioParams 求和它们的输入,所以如果您有潜在的音频速率调制源,如 LFO(连接到 GainNode 的 OscillatorNode),您只需连接()它到 AudioParam.

这是这里的关键 - AudioParams 能够连接到() - 并且对节点或 AudioParam 的多个输入连接求和。所以你通常想要一个

的模型
filter cutoff = (cutoff from envelope) + (cutoff from mod/LFO) + (cutoff from cutoff knob)

由于截止频率是一个频率,因此在对数刻度上不是线性频率,因此您希望以对数方式进行此加法(否则,将截止频率在 440Hz 处提升一个八度的包络只会将其提升半个八度880Hz 等)——幸运的是,这很容易通过 BiquadFilter 上的 "detune" 参数实现。

失谐以音分(1200/倍频程)为单位,因此您必须使用增益节点来调整值(例如,如果您希望调制具有 +1/-1 倍频程范围,请确保振荡器输出正常在 -1200 和 +1200 之间)。您可以看到我是如何在我的网络音频合成器中执行此操作的 (https://github.com/cwilso/midi-synth): in particular, check out synth.js starting around line 500: https://github.com/cwilso/midi-synth/blob/master/js/synth.js#L497-L519。请注意 modFilterGain.connect(this.filter1.detune);特别是。

您不想直接为调制设置任何值,因为实际值将以可能很快的速度变化 - 您想要使用参数调度器和来自 LFO 的输入求和。您可以根据需要根据时间设置旋钮值,但事实证明,设置 .value 与在同一 AudioParam 上设置预定值的交互效果不佳 - 因此您需要对 AudioParam 进行单独(求和)输入。这是棘手的一点,老实说,我的合成器今天做得不好(我应该将其更改为下面描述的方法)。

处理旋钮设置的正确方法是创建一个根据您的旋钮设置而变化的音频通道 - 也就是说,它是一个您可以连接到 filter.detune 的音频节点,尽管示例该 AudioNode 产生的值仅为正值,并且仅在更改旋钮时更改值。为此,您需要一个 DC 偏移源 - 即,一个产生恒定样本值流的 AudioNode。我能想到的最简单的方法是使用生成缓冲区为 1:

的 AudioBufferSourceNode
   function createDCOffset() {
    var buffer=audioContext.createBuffer(1,1,audioContext.sampleRate);
    var data = buffer.getChannelData(0);
    data[0]=1;
    var bufferSource=audioContext.createBufferSource();
    bufferSource.buffer=buffer;
    bufferSource.loop=true;
    bufferSource.start(0);
    return bufferSource;
}

然后,只需将 DCOffset 连接到一个增益节点,并将 "knob" 连接到该增益的 .value 以使用增益节点缩放值(请记住,一个八度音阶有 1200 音分,所以如果你想让你的旋钮代表一个六倍频程的截止范围,.value 应该在零和 7200 之间)。然后将 DCOffsetGain 节点连接到过滤器的 .detune(它与来自 LFO 的连接相加而不是替换,并且还与 AudioParam 上的预定值相加(记住您需要以美分为单位缩放预定值, 也))。顺便说一下,这种方法也可以很容易地翻转包络极性(Juno 106 上的 VCF ENV 开关)——只需反转您在调度程序中设置的值即可。

希望这对您有所帮助。我现在有点时差,所以希望这是清醒的。 :)