Giter Site home page Giter Site logo

Comments (4)

NickCulbertson avatar NickCulbertson commented on June 2, 2024 3

Haha! It does make some things easier and others parts are about the same.

Here is a better example making a 5-pole EQ. It needs to be refactored, but it works.

import AudioKit
import AudioKitEX
import AudioKitUI
import AVFoundation
import SoundpipeAudioKit
import SwiftUI
import Controls

/// AudioKit version of Apple's EQ Audio Unit
public class AppleEQ: Node {
    public var equalizerAU: AVAudioUnitEQ
    
    let input: Node
    
    /// Connected nodes
    public var connections: [Node] { [input] }
    
    /// Underlying AVAudioNode
    public var avAudioNode: AVAudioNode
    
    /// globalGain (Default 0) -96 -> 24
    public var globalGain: AUValue = 0 {
        didSet {
            equalizerAU.globalGain = globalGain
        }
    }
    
    public init(_ input: Node, bands: Int = 5, globalGain: AUValue = 0) {
        equalizerAU = AVAudioUnitEQ(numberOfBands: bands)
        self.input = input
        avAudioNode = equalizerAU
    }
}

class AppleEQConductor: ObservableObject, ProcessesPlayerInput {
    let engine = AudioEngine()
    let player = AudioPlayer()
    var filter: AppleEQ
    let dryWetMixer: DryWetMixer
    let buffer: AVAudioPCMBuffer
    
    @Published var frequency1 : Float = 100.0 {
        didSet {
            filter.equalizerAU.bands[0].frequency = frequency1
        }
    }
    
    @Published var gain1 : Float = 0.0 {
        didSet {
            filter.equalizerAU.bands[0].gain = gain1
        }
    }
    
    @Published var frequency2 : Float = 300.0 {
        didSet {
            filter.equalizerAU.bands[1].frequency = frequency2
        }
    }
    
    @Published var gain2 : Float = 0.0 {
        didSet {
            filter.equalizerAU.bands[1].gain = gain2
        }
    }
    
    @Published var frequency3 : Float = 1000.0 {
        didSet {
            filter.equalizerAU.bands[2].frequency = frequency3
        }
    }
    
    @Published var gain3 : Float = 0.0 {
        didSet {
            filter.equalizerAU.bands[2].gain = gain3
        }
    }
    
    @Published var frequency4 : Float = 4000.0 {
        didSet {
            filter.equalizerAU.bands[3].frequency = frequency4
        }
    }
    
    @Published var gain4 : Float = 0.0 {
        didSet {
            filter.equalizerAU.bands[3].gain = gain4
        }
    }
    
    @Published var frequency5 : Float = 10000.0 {
        didSet {
            filter.equalizerAU.bands[4].frequency = frequency5
        }
    }
    
    @Published var gain5 : Float = 0.0 {
        didSet {
            filter.equalizerAU.bands[4].gain = gain5
        }
    }
    
    @Published var globalGain : Float = 0.0 {
        didSet {
            filter.equalizerAU.globalGain = globalGain
        }
    }
    
    init() {
        buffer = Cookbook.sourceBuffer
        player.buffer = buffer
        player.isLooping = true
        
        filter = AppleEQ(player, bands: 5)
        dryWetMixer = DryWetMixer(player, filter)
        engine.output = dryWetMixer
        
        filter.equalizerAU.bands[0].frequency = 100.0
        filter.equalizerAU.bands[1].frequency = 300.0
        filter.equalizerAU.bands[2].frequency = 1_000.0
        filter.equalizerAU.bands[3].frequency = 4_000.0
        filter.equalizerAU.bands[4].frequency = 10_000.0
        
        for i in 0..<5 {
            filter.equalizerAU.bands[i].gain = 0
            filter.equalizerAU.bands[i].bypass = false
            filter.equalizerAU.bands[i].filterType = .parametric
        }
    }
}

struct AppleEQView: View {
    @StateObject var conductor = AppleEQConductor()
    
    var body: some View {
        VStack {
            PlayerControls(conductor: conductor)
            HStack {
                VStack {
                    CookbookKnob(text: "Frequency 1", parameter: $conductor.frequency1, range: 20...20000)
                    CookbookKnob(text: "Gain 1", parameter: $conductor.gain1, range: -96...24)
                }
                VStack {
                    CookbookKnob(text: "Frequency 2", parameter: $conductor.frequency2, range: 20...20000)
                    CookbookKnob(text: "Gain 2", parameter: $conductor.gain2, range: -96...24)
                }
                VStack {
                    CookbookKnob(text: "Frequency 3", parameter: $conductor.frequency3, range: 20...20000)
                    CookbookKnob(text: "Gain 3", parameter: $conductor.gain3, range: -96...24)
                }
                VStack {
                    CookbookKnob(text: "Frequency 4", parameter: $conductor.frequency4, range: 20...20000)
                    CookbookKnob(text: "Gain 4", parameter: $conductor.gain4, range: -96...24)
                }
                VStack {
                    CookbookKnob(text: "Frequency 5", parameter: $conductor.frequency5, range: 20...20000)
                    CookbookKnob(text: "Gain 5", parameter: $conductor.gain5, range: -96...24)
                }
                CookbookKnob(text: "Global Gain", parameter: $conductor.globalGain, range: -96...24)

            }
            DryWetMixView(dry: conductor.player,
                          wet: conductor.filter,
                          mix: conductor.dryWetMixer)
            
        }
        .padding()
        .cookbookNavBarTitle("Equalizer Filter")
        .onAppear {
            conductor.start()
        }
        .onDisappear {
            conductor.stop()
        }
    }
}

from audiokit.

NickCulbertson avatar NickCulbertson commented on June 2, 2024 2

from audiokit.

NickCulbertson avatar NickCulbertson commented on June 2, 2024 1

This can be done, but is a tough one to generalize since AVAudioUnitEQ(numberOfBands: ) is doing some work under the hood with [AVAudioUnitEQFilterParameters].

Here is a quick implementation you can try running in the Cookbook as a starting point. I'm sending a constant when initializing AVAudioUnitEQ(numberOfBands: 5) that you can change to whatever value you need. In the example the knob updates all frequencies just to show how to map the parameters to a local variable.

import AudioKit
import AudioKitEX
import AudioKitUI
import AVFoundation
import SoundpipeAudioKit
import SwiftUI

/// AudioKit version of Apple's EQ Audio Unit
///
public class AppleEQ: Node {
    public var equalizerAU = AVAudioUnitEQ(numberOfBands: 5)

    let input: Node

    /// Connected nodes
    public var connections: [Node] { [input] }

    /// Underlying AVAudioNode
    public var avAudioNode: AVAudioNode
    
    /// globalGain (Default 0) -96 -> 24
    public var globalGain: AUValue = 0 {
        didSet {
            equalizerAU.globalGain = globalGain
        }
    }

    public init(_ input: Node, globalGain: AUValue = 0) {
        self.input = input
        avAudioNode = equalizerAU
    }
}

class AppleEQConductor: ObservableObject, ProcessesPlayerInput {
    let engine = AudioEngine()
    let player = AudioPlayer()
    let filter: AppleEQ
    let dryWetMixer: DryWetMixer
    let buffer: AVAudioPCMBuffer
    
    @Published var frequency : Float = 0.0 {
        didSet {
            for i in 0..<5 {
                filter.equalizerAU.bands[i].frequency = frequency * Float(i)
            }
        }
    }
    
    init() {
        buffer = Cookbook.sourceBuffer
        player.buffer = buffer
        player.isLooping = true

        filter = AppleEQ(player)
        dryWetMixer = DryWetMixer(player, filter)
        engine.output = dryWetMixer
        
        for i in 0..<5 {
            filter.equalizerAU.bands[i].frequency = Float(100*i)
            filter.equalizerAU.bands[i].gain = 20
            filter.equalizerAU.bands[i].bypass = false
            filter.equalizerAU.bands[i].filterType = .parametric
        }
    }
}

struct AppleEQView: View {
    @StateObject var conductor = AppleEQConductor()

    var body: some View {
        VStack {
            PlayerControls(conductor: conductor)
            HStack {
                CookbookKnob(text: "Frequency", parameter: $conductor.frequency, range: 20...20000)
                DryWetMixView(dry: conductor.player,
                              wet: conductor.filter,
                              mix: conductor.dryWetMixer)
            }
        }
        .padding()
        .cookbookNavBarTitle("Equalizer Filter")
        .onAppear {
            conductor.start()
        }
        .onDisappear {
            conductor.stop()
        }
    }
}

from audiokit.

Volodymyr-13 avatar Volodymyr-13 commented on June 2, 2024

@NickCulbertson Thanks! I will try!

I just thought that AudioKit was designed to make life easier for the developer) but it turns out I need to suffer so much more)

from audiokit.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.