换句话说,我需要两个单独的 ADSR 信封用于 OSC 组和滤波器(截止)。我如何通过按音符来同步这两件事?
AMOscillatorBank(幅度)->lowPassFilter(截止)->AudioKit 输出 当‘amplitude’和‘cutoff’分离了adsr包络,并通过链式两个输出生成和转换声音。
我在操场上尝试了一些例子,但我只能使用 adsr 创建 AMOscillatorBank(振幅),并且只传递一些低通滤波器(但不同步到音符按下)。
如果您想要采样精度,您需要将低通滤波器放入库的 DSP 内。我们实际上正在 AK Synth One 项目上这样做,该项目完成后将开源。
这可以通过OperationEffect (AudioKit 5.6.x) 实现。您可以使用正确的 Sporth 代码将原始振荡器混合传递到自定义节点 (OperationEffect),然后设置门控的节点参数(当 noteOn 时设置为 1.0,当 noteOff 时设置为 0.0)。 Sporth 代码从左通道“(14 p)”读取单声道输入样本,以及门参数,例如“(0 p)”(在 Swift 领域中被容易混淆地称为 Parameter1),并将这些传递到第一个滤波器 ADSR包络发生器,然后是 moogladder,然后是振幅 ADSR 包络。如果你设置正确的话,听起来会很棒。我生成 Sporth 代码的示例 Swift 代码如下所示:
var moogFilterEnvAmpEnvSporth: String {
// TODO also DryWetMix using s1preset.filterADSRMix (should be done inside, after moogladder, before adsr)
// (0 p) is a gate set by noteOn/noteOff
let filterAdsrParams = "\(filterAttack) \(filterDecay) \(filterSustain) \(filterRelease)"
let ampAdsrParams = "\(attackDuration) \(decayDuration) \(sustainLevel) \(releaseDuration)"
let ret = """
_cutoff var
_gate var
_velocity var
_leftin var
\(cutoff) _cutoff set
(0 p) _gate set
(1 p) _velocity set
(14 p) _leftin set
_leftin get
(
\(filterADSRMix) 1.0 min
_cutoff get
(
_cutoff get
(_gate get) \(filterAdsrParams) adsr
*
)
scale
)
\(resonance) moogladder
((_gate get) \(ampAdsrParams) adsr) *
(_velocity get) *
dup
"""
return ret
}
}
最后的 dup 只是将左声道复制到右声道以使其成为立体声,适合我的用例。
此代码实际上尝试重现 SynthOne 预设(JSON 文件)的核心声音,并且做得不错。使用振荡器部分(此处未显示,只是简单的 AudioKit 节点混合在一起),大约两打 SynthOne 预设参数已正确连接。我可以在带有复调、力度、延音踏板的 MIDI 键盘上演奏 AKS1 预设音色的子集(也是使用 AudioKit 节点完成的,而不是 Sporth),而且它们听起来相当合理。请注意,这些参数在运行时不可更改,但在创建 OpertionEffect 节点时硬编码到 Sporth 代码中,尽管如果您破解 SporthAudioKit 本身,您可能可以添加 64 或 128 个参数,这些参数会传递到 Sporth 中,您可以将其连接起来最多 UI 旋钮。
LFO 控制和效果(bitcrush、autopan、延迟、混响)留给读者作为练习。还有arp/seq、调音表等等
参见: