Search code examples
iosswiftavaudioengine

My AVAudioUnitEQ does not works unlike AVAudioUnitTimePitch for AVAudioEngine()


I was playing with AVAudioEngine to use it in an app. I am changing pitch and equalizer (gain) parameters with sliders while music was playing.

Pitch works but equalizer is not working. I could not find the cause.

var audioEngine = AVAudioEngine()
var audioFilePlayer = AVAudioPlayerNode()
let auTimePitch = AVAudioUnitTimePitch()
var equalizer = AVAudioUnitEQ()

func startEngine(){
 guard let filePath: String = Bundle.main.path(forResource: "testMusic", ofType: "mp3") else{ return }
    let fileURL: URL = URL(fileURLWithPath: filePath)
    guard let audioFile = try? AVAudioFile(forReading: fileURL) else { return }
    
    
    let audioFormat = audioFile.processingFormat
    let audioFrameCount = UInt32(audioFile.length)
    guard let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat,
                                                 frameCapacity: audioFrameCount)  else {  return }
    
    do{
        try audioFile.read(into: audioFileBuffer)
    } catch{
        print("over")
    }
    
    let mainMixer = audioEngine.mainMixerNode
    



    auTimePitch.pitch = 1
    auTimePitch.rate = 1 


    equalizer = AVAudioUnitEQ(numberOfBands: 5)
    let bands = equalizer.bands
    let freqs = [60, 230, 910, 4000, 14000]
    
    for i in 0..<bands.count {
        bands[i].frequency  = Float(freqs[i])
        bands[i].bypass     = false
        bands[i].filterType = .parametric
        bands[i].gain = 0
        bands[i].bandwidth = 1
    }


    let format = mainMixer.outputFormat(forBus: 0)
    
    audioEngine.attach(audioFilePlayer)
    audioEngine.attach(auTimePitch)
    audioEngine.attach(equalizer)
    
    
    audioEngine.connect(audioFilePlayer,
                        to: equalizer,
                        format: format)
    
    audioEngine.connect(audioFilePlayer,
                        to:auTimePitch,
                        format: format)
    
    
    
  
    audioEngine.connect(equalizer,
                        to: mainMixer,
                        format: format)
    
    audioEngine.connect(auTimePitch,
                        to: mainMixer,
                        format: format)
    

   
        
    try? audioEngine.start()
    audioFilePlayer.play()
    
    audioFilePlayer.scheduleBuffer(audioFileBuffer, at: nil,
                                   options:AVAudioPlayerNodeBufferOptions.loops)
    
 }   

enter image description here


Solution

  • Your AVAudioEngine graph looks a little weird (can AVAudioPlayerNode have two outputs?), but if you attach your nodes:

    audioEngine.attach(audioFilePlayer)
    audioEngine.attach(equalizer)
    audioEngine.attach(auTimePitch)
    

    and use the file processing format, letting mainMixerNode do format conversion

    let format = audioFile.processingFormat
    

    and connect the nodes in a more linear fashion:

    audioEngine.connect(audioFilePlayer,
                            to: equalizer,
                            format: format)
    
    audioEngine.connect(equalizer,
                            to:auTimePitch,
                            format: format)
    
    audioEngine.connect(auTimePitch,
                            to: mainMixer,
                            format: format)
    

    you can manipulate your equalizer, e.g suppressing lower frequencies and emphasizing higher ones:

    bands[0].gain = -50
    bands[4].gain = 24