AudioKit v5:如何修改DunneAudioKit Synth的波形?
解决AudioKit Synth波形修改与扩展功能问题
为什么你的代码没生效
AudioKit的Synth类默认使用内置的合成器语音(AKSynthVoice),直接调用au.setWavetable无法覆盖默认语音的波形设置。要自定义波形,必须替换Synth的默认语音为你自己实现的SynthVoice子类——每个复音音符对应一个Voice实例,波形、调制等逻辑都要在Voice里定义。
步骤1:自定义SynthVoice实现波形控制
创建继承自AKPolyphonicSynthVoice的自定义语音类,在里面定义波形表、振荡器组合,以及子振荡器、FM、噪声模块:
import AudioKit class CustomSynthVoice: AKPolyphonicSynthVoice { // 主振荡器 var oscillator: AKWavetableOscillator // 子振荡器(可选) var subOscillator: AKOscillator? // FM调制器 var fmOscillator: AKOscillator? var fmAmount: AKParameter = 0.0 // 噪声发生器 var noiseGenerator: AKWhiteNoise? // 包络与滤波 var envelope: AKAmplitudeEnvelope var filter: AKLowPassFilter override init() { // 组合多种波形:正弦+方波各50%比例混合 let sineTable = Table(.sine) let squareTable = Table(.square) let mixedTable = Table([sineTable, squareTable], weights: [0.5, 0.5]) oscillator = AKWavetableOscillator(wavetable: mixedTable) envelope = AKAmplitudeEnvelope(oscillator) // 初始化子振荡器(低八度,方波) subOscillator = AKOscillator(waveform: AKTable(.square)) subOscillator?.amplitude = 0.3 // 初始化FM调制器 fmOscillator = AKOscillator(waveform: AKTable(.sine)) fmAmount = 50.0 // 初始化噪声发生器 noiseGenerator = AKWhiteNoise(amplitude: 0.1) // 构建信号链:主振荡器+子振荡器+噪声 → 包络 → 滤波 let mixer = AKMixer(envelope, subOscillator!, noiseGenerator!) filter = AKLowPassFilter(mixer) super.init() self.connect(input: filter) } // 触发音符时的参数配置 override func start(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, frequency: Double, amplitude: Double) { oscillator.frequency = frequency oscillator.amplitude = Double(velocity) / 127.0 // 子振荡器设为低八度 subOscillator?.frequency = frequency / 2 subOscillator?.start() // FM调制:调制器频率为主音2倍,调制量控制谐波丰富度 fmOscillator?.frequency = frequency * 2 fmOscillator?.amplitude = fmAmount fmOscillator?.start() oscillator.modulationSource = fmOscillator noiseGenerator?.start() envelope.start() oscillator.start() } // 释放音符时的收尾处理 override func stop(velocity: MIDIVelocity) { envelope.stop() oscillator.stop() subOscillator?.stop() fmOscillator?.stop() noiseGenerator?.stop() // 延迟移除Voice,确保包络播放完毕 DispatchQueue.main.asyncAfter(deadline: .now() + envelope.releaseDuration) { self.stop() } } // 复音Voice必备实现方法 override func renderSilence() -> Bool { return envelope.isStopped } override func reset() { oscillator.reset() envelope.reset() subOscillator?.reset() fmOscillator?.reset() noiseGenerator?.reset() } }
步骤2:将自定义Voice关联到Synth实例
替换Synth的默认语音,使用自定义的CustomSynthVoice,这样调用play(noteNumber:velocity:)时就会应用你的波形和模块:
import AudioKit class SynthManager { let audioEngine = AudioEngine() var audioSynth: Synth! init() { // 初始化Synth并指定自定义Voice类型 audioSynth = Synth(voice: CustomSynthVoice.self) // 设置包络参数(和你之前修改的attack/decay一致) audioSynth.attackDuration = 0.1 audioSynth.decayDuration = 0.2 audioSynth.sustainLevel = 0.7 audioSynth.releaseDuration = 0.5 // 连接输出并启动音频引擎 audioEngine.output = audioSynth try? audioEngine.start() } // 播放音符方法 func playNote(_ noteNumber: MIDINoteNumber, velocity: MIDIVelocity = 100) { audioSynth.play(noteNumber: noteNumber, velocity: velocity) } // 停止音符方法 func stopNote(_ noteNumber: MIDINoteNumber) { audioSynth.stop(noteNumber: noteNumber) } }
关键说明
- 波形组合:通过
Table的多波形初始化方法,调整weights参数可改变正弦、方波、锯齿波的混合比例。 - 子振荡器:独立添加振荡器并设置为低八度或其他倍数,控制振幅调整混合占比。
- FM调制:将FM振荡器输出连接到主振荡器的
modulationSource,调整fmAmount可改变调制深度,生成更丰富的谐波。 - 噪声发生器:混合白/粉噪声模块,增加音色质感(比如模拟复古合成器底噪)。
- 复音支持:
Synth本身是复音架构,会自动为每个触发音符创建CustomSynthVoice实例,无需手动管理多个振荡器——每个复音对应一个Voice,Voice内部可包含多个振荡器模块。
调试提示
- 若波形无变化,检查自定义Voice的信号链连接是否正确,确保
connect(input:)指向最终混合信号。 - 调整振荡器振幅、包络参数,避免信号被过度衰减导致听不见。
- 可单独测试每个模块(先启用主振荡器,再逐步添加子振荡器、FM、噪声),定位问题。
内容的提问来源于stack exchange,提问作者Evan Aaron Escobar
相关产品推荐
相关产品推荐

