辉煌的项目!
您不需要自己对它们求和 - Web Audio AudioParams 对它们的输入求和,因此,如果您有潜在的音频速率调制源,如 LFO(连接到 GainNode 的 OscillatorNode),您只需将其 connect() 到 AudioParam 即可。
这是这里的关键 - AudioParams 能够被 connect() 到 - 并且对节点或 AudioParam 的多个输入连接进行求和。所以你通常想要一个模型
filter cutoff = (cutoff from envelope) + (cutoff from mod/LFO) + (cutoff from cutoff knob)
由于截止是一个频率,因此在对数标度上不是线性的,因此您需要以对数方式进行此加法(否则,在 440Hz 处将截止提高一个八度的包络只会在 880Hz 处将其提高半个八度,等等。 ) - 幸运的是,通过 BiquadFilter 上的“失谐”参数很容易做到。
失谐以音分(1200/倍频程)为单位,因此您必须使用增益节点来调整值(例如,如果您希望调制具有 +1/-1 倍频程范围,请确保振荡器输出在 -1200 和 + 之间) 1200)。您可以看到我如何在我的网络音频合成器中执行此操作(https://github.com/cwilso/midi-synth https://github.com/cwilso/midi-synth):特别是,检查从第 500 行开始的 synth.js:https://github.com/cwilso/midi-synth/blob/master/js/synth.js#L497-L519 https://github.com/cwilso/midi-synth/blob/master/js/synth.js#L497-L519。注意 modFilterGain.connect(this.filter1.detune);尤其。
您不想直接为调制设置任何值,因为实际值会以可能很快的速度变化 - 您希望使用参数调度程序和来自 LFO 的输入求和。您可以根据时间需要设置旋钮值,但事实证明,设置 .value 与在同一 AudioParam 上设置计划值的交互效果很差 - 因此您需要在 AudioParam 中单独(求和)输入。这是棘手的一点,说实话,我的合成器今天做得不好(我应该将其更改为下面描述的方法)。
处理旋钮设置的正确方法是创建一个根据旋钮设置而变化的音频通道 - 也就是说,它是一个可以 connect() 到 filter.detune 的 AudioNode,尽管该 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 连接到增益节点,并将“旋钮”连接到该增益的 .value,即可使用增益节点来缩放值(请记住,一个八度音阶有 1200 音分,因此如果您希望旋钮代表六个八度的截止范围,.值应介于 0 和 7200 之间)。然后将 DCOffsetGain 节点 connect() 到过滤器的 .detune 中(它与来自 LFO 的连接相加,而不是替换,并且还与 AudioParam 上的预定值相加(请记住,您需要以美分为单位缩放预定值) , 也))。顺便说一句,这种方法也可以轻松翻转包络极性(Juno 106 上的 VCF ENV 开关) - 只需反转您在调度程序中设置的值即可。
希望这可以帮助。我现在有点时差反应,所以希望这是清醒的。 :)