Tap Mic Input Using AVAudioEngine in Swift

匿名 (未验证) 提交于 2019-12-03 01:18:02

问题:

I'm really excited about the new AVAudioEngine. It seems like a good API wrapper around audio unit. Unfortunately the documentation is so far nonexistent, and I'm having problems getting a simple graph to work.

Using the following simple code to set up an audio engine graph, the tap block is never called. It mimics some of the sample code floating around the web, though those also did not work.

let inputNode = audioEngine.inputNode var error: NSError? let bus = 0  inputNode.installTapOnBus(bus, bufferSize: 2048, format: inputNode.inputFormatForBus(bus)) {      (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in     println("sfdljk") }  audioEngine.prepare() if audioEngine.startAndReturnError(&error) {     println("started audio") } else {     if let engineStartError = error {         println("error starting audio: \(engineStartError.localizedDescription)")     } }

All I'm looking for is the raw pcm buffer for analysis. I don't need any effects or output. According to the WWDC talk "502 Audio Engine in Practice", this setup should work.

Now if you want to capture data from the input node, you can install a node tap and we've talked about that.

But what's interesting about this particular example is, if I wanted to work with just the input node, say just capture data from the microphone and maybe examine it, analyze it in real time or maybe write it out to file, I can directly install a tap on the input node.

And the tap will do the work of pulling the input node for data, stuffing it in buffers and then returning that back to the application.

Once you have that data you can do whatever you need to do with it.

Here are some links I tried:

  1. http://hondrouthoughts.blogspot.com/2014/09/avfoundation-audio-monitoring.html
  2. http://jamiebullock.com/post/89243252529/live-coding-audio-with-swift-playgrounds (SIGABRT in playground on startAndReturnError)

Edit: This is the implementation based on Thorsten Karrer's suggestion. It unfortunately does not work.

class AudioProcessor {     let audioEngine = AVAudioEngine()      init(){         let inputNode = audioEngine.inputNode         let bus = 0         var error: NSError?          inputNode.installTapOnBus(bus, bufferSize: 2048, format:inputNode.inputFormatForBus(bus)) {             (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in                 println("sfdljk")         }          audioEngine.prepare()         audioEngine.startAndReturnError(nil)         println("started audio")     } }

回答1:

It might be the case that your AVAudioEngine is going out of scope and is released by ARC ("If you liked it then you should have put retain on it...").

The following code (engine is moved to an ivar and thus sticks around) fires the tap:

class AppDelegate: NSObject, NSApplicationDelegate {      let audioEngine  = AVAudioEngine()      func applicationDidFinishLaunching(aNotification: NSNotification) {         let inputNode = audioEngine.inputNode         let bus = 0         inputNode.installTapOnBus(bus, bufferSize: 2048, format: inputNode.inputFormatForBus(bus)) {             (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in             println("sfdljk")         }          audioEngine.prepare()         audioEngine.startAndReturnError(nil)     } }

(I removed the error handling for brevity)



回答2:

UPDATED: I have implemented a complete working example of Recording mic input, applying some effects (reverbs, delay, distortion) at runtime, and save all these effects to an output file.

var engine = AVAudioEngine() var distortion = AVAudioUnitDistortion() var reverb = AVAudioUnitReverb() var audioBuffer = AVAudioPCMBuffer() var outputFile = AVAudioFile() var delay = AVAudioUnitDelay()

//Initialize the audio engine

func initializeAudioEngine() {      engine.stop()     engine.reset()     engine = AVAudioEngine()      isRealTime = true             
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!