简体   繁体   English

AVAudioEngine:过滤实时音频

[英]AVAudioEngine: filter realtime audio

I have gone through the Apple Sample Code on Equalizing Audio with vDSP , where the audio file is filtered in AVAudioSourceNode and reproduced.我已经浏览了 Apple Sample Code on Equalizing Audio with vDSP ,其中音频文件在AVAudioSourceNode中过滤并复制。

My objective is to do exactly the same, but instead of taking the audio from an audio file, take it in real-time from the microphone.我的目标是完全相同,但不是从音频文件中获取音频,而是从麦克风中实时获取。 Is it possible to do so in AVAudioEngine ?是否可以在AVAudioEngine中这样做? A couple of ways to do so are based on installTap or AVAudioSinkNode , as described in First strategy and Second strategy sections.这样做的几种方法是基于installTapAVAudioSinkNode ,如第一个策略第二个策略部分所述。

So far, I got a bit closer to my objective with the following 2 strategies.到目前为止,我通过以下 2 个策略离我的目标更近了一点。

First strategy第一个策略
// Added new class variables
private lazy var sinkNode = AVAudioSinkNode { (timestep, frames, audioBufferList) -> OSStatus in
    let ptr = audioBufferList.pointee.mBuffers.mData?.assumingMemoryBound(to: Float.self)
    var monoSamples = [Float]()
    monoSamples.append(contentsOf: UnsafeBufferPointer(start: ptr, count: Int(frames)))
    self.page = monoSamples.
    for frame in 0..<frames {
          print("sink: " + String(monoSamples[Int(frame)]))
        }
    return noErr
}
// AVAudioEngine connections

engine.attach(sinkNode)
// Audio input is passed to the AVAudioSinkNode and the [Float] array is pased to the AVAudioSourceNode through the _page_ variable
engine.connect(input, to: sinkNode, format: formatt)

engine.attach(srcNode)

engine.connect(srcNode,
                   to: engine.mainMixerNode,
                   format: format)

engine.connect(engine.mainMixerNode,
                   to: engine.outputNode,
                   format: format)

// The AVAudioSourceNode access the self.page array through the getSinalElement() function.
private func getSignalElement() -> Float {
    return page.isEmpty ? 0 : page.removeFirst()
}

This approach made it possible to play the audio through the AVAudioSourceNode, but, the audio stops playing after a few seconds (even though, I still successfully get the self.page array in AVAudioSourceNode) and the app finally crashes.这种方法可以通过 AVAudioSourceNode 播放音频,但是,音频在几秒钟后停止播放(尽管我仍然成功地在 AVAudioSourceNode 中获取了 self.page 数组)并且应用程序最终崩溃了。

2 strategy 2 策略

In a similar approach, I used installtap engine.attach(srcNode)在类似的方法中,我使用了installtap engine.attach(srcNode)

    engine.connect(srcNode,
                   to: engine.mainMixerNode,
                   format: format)

    engine.connect(engine.mainMixerNode,
                   to: engine.outputNode,
                   format: format)
    input.installTap(onBus: 0, bufferSize:1024, format:formatt, block: { [weak self] buffer, when in
        let arraySize = Int(buffer.frameLength)
        let samples = Array(UnsafeBufferPointer(start: buffer.floatChannelData![0], count:arraySize))
        self!.page = samples
    })

// The AVAudioSourceNode access the self.page array through the getSinalElement() function.
private func getSignalElement() -> Float {
    return page.isEmpty ? 0 : page.removeFirst()
}

The outcome after implementing Second strategy is the same as in First strategy .实施第二策略后的结果与第一策略相同。 Which can be the issues making these approaches fail?哪些问题可能导致这些方法失败?

You can use AvAudioEngine().inputNode like following:您可以使用AvAudioEngine().inputNode如下:

    let engine = AVAudioEngine()
    private lazy var srcNode = AVAudioSourceNode { _, _, frameCount, audioBufferList -> OSStatus in
    
    return noErr
    }
    // Attach First
    engine.attach(srcNode)
    // Then connect nodes

    let input = engine.inputNode

    engine.connect(input, to: srcNode, format: input.inputFormat(forBus: 0))

It is important to use input.inputFormat(...) as format type.使用input.inputFormat(...)作为格式类型很重要。

   do{
        try audioSession.setCategory(.playAndRecord, mode: .default, options: [.mixWithOthers, .defaultToSpeaker,.allowBluetoothA2DP,.allowAirPlay,.allowBluetooth])
        try audioSession.setActive(true)
    } catch{
        print(error.localizedDescription)
    }
    
    engine.attach(player)
    //Add this only you want putch
    let pitch = AVAudioUnitTimePitch()
    
   // pitch.pitch = 1000 //Filtered Voice
    //pitch.rate = 1 //Normal rate
    
    // engine.attach(pitch)
    engine.attach(srcNode)
    
    engine.connect(srcNode,
                   to: engine.mainMixerNode,
                   format: engine.inputNode.inputFormat(forBus: 0))
    
    engine.connect(engine.mainMixerNode,
                   to: engine.outputNode,
                   format: engine.inputNode.inputFormat(forBus: 0))
    engine.prepare()
    
    
    engine.inputNode.installTap(onBus: 0, bufferSize: 512, format: engine.inputNode.inputFormat(forBus: 0)) { (buffer, time) -> Void in
        //   self.player.scheduleBuffer(buffer)
        let arraySize = Int(buffer.frameLength)
        let samples = Array(UnsafeBufferPointer(start: buffer.floatChannelData![0], count:arraySize))
        self.page = samples
        print("samples",samples)
    }
    
    
    engine.mainMixerNode.outputVolume = 0.5
    

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM