xcodeswiftuiaudiokit

Is it possible to create 5 oscillators (an array?) working simultaneously and control their frequency and amplitude independently of each other?


import SwiftUI
import AudioKit

class ToneGenerator {
    let engine = AudioEngine()
    let osc = PlaygroundOscillator()
 
    init(){
        engine.output = osc
        try! engine.start()
    }
}

struct ContentView: View {
    
    let toneGenerator = ToneGenerator()
    var freq01: Float = 200
    var volume01: Float = 0.5
    @State var isPressed = false
  
    var body: some View {
        
        Text("BEEP")
            .font((.title))
            .simultaneousGesture(
                DragGesture(minimumDistance: 0)
                    .onChanged({ _ in
                        isPressed = true
                        toneGenerator.osc.frequency = freq01
                        toneGenerator.osc.amplitude = volume01
                        toneGenerator.osc.start()
                    })
                    .onEnded({ _ in
                        isPressed = false
                        toneGenerator.osc.stop()
                    })
            )
    }
}

I tried to create several generators, but did not understand how to do it.

All the materials I found on the Internet are related to the Playground and do not work in Xcode.


Solution

  • I'm not 100% sure what you're trying to achieve, but how about something like this. The key is to use $toneGenerators[index] to create a binding to the tone generator so you can change the volume and frequency.

    class ToneGenerator: Identifiable {
        let id = UUID()
        let engine = AudioEngine()
        var osc = PlaygroundOscillator()
        
        init(){
            engine.output = osc
            try! engine.start()
        }
    }
    
    struct ContentView: View {
        
        @State var toneGenerators: [ToneGenerator] = []
        let freqs = [Float(100), 200, 300, 400, 500]
        
        var body: some View {
            
            VStack {
                HStack {
                    Button("BEEP") {
                        let toneGenerator = ToneGenerator()
                        toneGenerator.osc.frequency = Float.random(in: 100...1000)
                        toneGenerator.osc.amplitude = 0.5
                        toneGenerator.osc.start()
                        toneGenerators.append(toneGenerator)
                    }
                    .font((.title))
                    Button("STOP") {
                        toneGenerators.forEach { toneGenerator in
                            toneGenerator.osc.stop()
                        }
                        toneGenerators = []
                    }
                    .tint(.red)
                    .font((.title))
                }
                Text(toneGenerators.count, format: .number) + Text(" generators")
    
                Grid {
                    GridRow {
                        Text("Freq").bold()
                        Text("Volume").bold()
                    }
                    ForEach(toneGenerators) { toneGenerator in
                        let index = toneGenerators.firstIndex(where: { $0.id == toneGenerator.id })!
                        GridRow {
                            Slider(value: $toneGenerators[index].osc.frequency, in: 100...1000)
                            Slider(value: $toneGenerators[index].osc.amplitude, in: 0...1)
                        }
                        
                    }
                }
                .padding()
                
                Spacer()
            }
        }
    }