能否创建5个可同时运行的振荡器数组并独立控制各振荡器的频率与振幅?
实现5个独立控制的音频振荡器(AudioKit + SwiftUI)
可以实现5个同时工作且独立控制的振荡器,核心是用数组存储多个振荡器实例,再通过Mixer将所有音频信号混合后输出。下面是适配Xcode项目的完整实现方案:
修改音频生成器类
首先重构ToneGenerator,用数组管理多个振荡器,并用混音器合并信号:
import AudioKit import AVFoundation class ToneGenerator { let engine = AudioEngine() let mixer = Mixer() // 存储5个振荡器的数组 var oscillators: [PlaygroundOscillator] = [] init() { // 初始化5个振荡器,添加到混音器 for _ in 0..<5 { let osc = PlaygroundOscillator() osc.amplitude = 0 // 默认静音 oscillators.append(osc) mixer.addInput(osc) } // 将混音器设为引擎输出 engine.output = mixer // 启动音频引擎(添加错误处理避免崩溃) do { try engine.start() } catch { print("音频引擎启动失败: \(error.localizedDescription)") } } // 控制指定索引的振荡器启停 func toggleOscillator(at index: Int, isOn: Bool) { guard index < oscillators.count else { return } if isOn { oscillators[index].start() } else { oscillators[index].stop() } } // 设置指定索引振荡器的频率 func setFrequency(for index: Int, value: Float) { guard index < oscillators.count else { return } oscillators[index].frequency = value } // 设置指定索引振荡器的振幅 func setAmplitude(for index: Int, value: Float) { guard index < oscillators.count else { return } oscillators[index].amplitude = value } }
构建SwiftUI交互界面
在ContentView中添加独立控件,分别控制每个振荡器的开关、频率和振幅:
import SwiftUI struct ContentView: View { let toneGenerator = ToneGenerator() // 为每个振荡器定义独立的状态 @State private var oscillatorStates: [Bool] = Array(repeating: false, count: 5) @State private var frequencies: [Float] = [200, 300, 400, 500, 600] @State private var amplitudes: [Float] = Array(repeating: 0.5, count: 5) var body: some View { ScrollView { VStack(spacing: 20) { ForEach(0..<5, id: \.self) { index in VStack(spacing: 10) { Text("振荡器 \(index + 1)") .font(.headline) // 开关按钮 Button(action: { oscillatorStates[index].toggle() toneGenerator.toggleOscillator(at: index, isOn: oscillatorStates[index]) }) { Text(oscillatorStates[index] ? "停止" : "播放") .frame(width: 80, height: 40) .background(oscillatorStates[index] ? Color.red : Color.green) .foregroundColor(.white) .cornerRadius(8) } // 频率滑块 HStack { Text("频率: \(Int(frequencies[index])) Hz") Slider(value: $frequencies[index], in: 50...1000) { _ in toneGenerator.setFrequency(for: index, value: frequencies[index]) } } // 振幅滑块 HStack { Text("音量: \(String(format: "%.2f", amplitudes[index]))") Slider(value: $amplitudes[index], in: 0...1) { _ in toneGenerator.setAmplitude(for: index, value: amplitudes[index]) } } } .padding() .background(Color.gray.opacity(0.1)) .cornerRadius(10) } } .padding() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
关键说明
- 数组管理振荡器:用
[PlaygroundOscillator]存储5个实例,通过索引快速定位操作目标 - 混音器合并信号:所有振荡器的输出都接入
Mixer,再统一输出到音频引擎,避免多个直接输出冲突 - 独立状态控制:每个振荡器对应独立的开关、频率、振幅状态变量,确保操作互不干扰
- 错误处理优化:替换原代码的
try!为do-catch,避免音频引擎启动失败导致崩溃
内容的提问来源于stack exchange,提问作者Peter_22
相关产品推荐
相关产品推荐

