Comments (4)
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.
from audiokit.
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.
@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)
- input bus 0 sample rate is 0 HOT 2
- AppleSequencer and MIDISampler are stuttering on the first note HOT 2
- AVAudioEngine.pause() method crashes when the app switches to the background HOT 2
- Restarting audio engine after stopping on scenePhase change HOT 2
- Make name of MusicTrackManager public HOT 3
- Using AudioKit from background thread - is it supported? HOT 3
- Unit tests failing MD5 validation HOT 3
- Unable to use renderToFile to export the output of AudioPlayer HOT 5
- Add VisionOS support HOT 4
- How to Implement a custom Audio Effect Node? HOT 8
- v4: Commit c612f44 caused linking to fail
- Audiokit MIDIListener crashes when sending a certain midi message HOT 7
- WatchOS supported HOT 1
- How to import AudioKit on a Capacitor iOS plugin HOT 4
- FFTTap crash HOT 1
- NodeRecorder audioDataCallback update interval
- FormatConverter discards 2nd channel when going from 2 to 1 channels HOT 1
- MIDISampler issue with XCode 15.3RC HOT 10
- Variable Delay operation changing the amplitude of resulting audio HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from audiokit.