Build a simple Equalizer
Asked Answered
G

1

10

I would like to make a 5-band audio equalizer (60Hz, 230Hz, 910Hz, 4kHz, 14kHz) using AVAudioEngine. I would like to have the user input gain per band through a vertical slider and accordingly adjust the audio that is playing. I tried using AVAudioUnitEQ to do this, but I hear no difference when playing the audio. I tried to hardcode in values to specify a gain at each frequency, but it still does not work. Here is the code I have:

var audioEngine: AVAudioEngine = AVAudioEngine()
var equalizer: AVAudioUnitEQ!
var audioPlayerNode: AVAudioPlayerNode = AVAudioPlayerNode()
var audioFile: AVAudioFile!

// in viewDidLoad():
equalizer = AVAudioUnitEQ(numberOfBands: 5)
audioEngine.attach(audioPlayerNode)
audioEngine.attach(equalizer)
let bands = equalizer.bands
let freqs = [60, 230, 910, 4000, 14000]
audioEngine.connect(audioPlayerNode, to: equalizer, format: nil)
audioEngine.connect(equalizer, to: audioEngine.outputNode, format: nil)
for i in 0...(bands.count - 1) {
    bands[i].frequency = Float(freqs[i])
}

bands[0].gain = -10.0
bands[0].filterType = .lowShelf
bands[1].gain = -10.0
bands[1].filterType = .lowShelf
bands[2].gain = -10.0
bands[2].filterType = .lowShelf
bands[3].gain = 10.0
bands[3].filterType = .highShelf
bands[4].gain = 10.0
bands[4].filterType = .highShelf

do {
    if let filepath = Bundle.main.path(forResource: "song", ofType: "mp3") {
        let filepathURL = NSURL.fileURL(withPath: filepath)
        audioFile = try AVAudioFile(forReading: filepathURL)
        audioEngine.prepare()
        try audioEngine.start()
        audioPlayerNode.scheduleFile(audioFile, at: nil, completionHandler: nil)
        audioPlayerNode.play()
    }
} catch _ {}

Since the low frequencies have a gain of -10 and the high frequencies have a gain of 10, there should be a very noticeable difference when playing any media. However, when the media starts playing, it sounds the same as if played without any equalizer attached.

I'm not sure why this is happening, but I tried several different things to debug. I thought that it might be the order of the functions so I tried switching it so that audioEngine.connect is called after adjusting all of the bands, but that did not make a difference either.

I tried this same code with using an AVAudioUnitTimePitch, and it worked perfectly, so I am dumbfounded as to why it does not work with AVAudioUnitEQ.

I do not want to use any third-party libraries or cocoa pods for this project, I would like to do it using AVFoundation alone.

Any help would be greatly appreciated!

Thanks in advance.

Grunenwald answered 29/5, 2017 at 8:52 Comment(1)
i am new to avkit can you please tell me how can i show output of equilizer on screen?Caudill
G
14

AVAudioUnitEQFilterParameters AVAudioUnitEQFilterParameters Documentation Looking through the documentation, I noticed that I had messed with all of the parameters except bypass and it seems that changing this flag fixed everything!

So, I believe the main issue here is that each AVAudioUnitEQ band must not be bypassed by the provided system values rather than the values the programmer sets.

So, I changed

for i in 0...(bands.count - 1) {
    bands[i].frequency = Float(freqs[i])
}

to

for i in 0...(bands.count - 1) {
    bands[i].frequency  = Float(freqs[i])
    bands[i].bypass     = false
    bands[i].filtertype = .parametric
}

and everything started working. Furthermore, to make an effective equalizer that allows the user to modify individual frequencies the filtertype for each band should be set to .parametric.

I am still unsure on what I should set the bandwith to, but I can probably check online for that or just mess with it until the sound matches a different equalizer application.

Grunenwald answered 29/5, 2017 at 9:33 Comment(2)
This was super helpful... but I also noticed that you're reassigning the filter type -- first as parametric then later as lowshelf/highshelf.Instigate
Thank you! I'm trying to implement a gross ReplayGain method in my macOS app. This has gotten me closer as it showed me how to access the properties of this class for globalGain. Now I just need to figure out how to determine the max gain of an audio file before applying the global Gain to increase or decrease the gain.Pervasive

© 2022 - 2024 — McMap. All rights reserved.