VU meter AUAudioUnit

Let's say we want to add a VU meter to the FilterDemo audiounit v3, what is the good practice to retrieve the audio buffer in the view? I'm only intersted in that not on how to design the VU meter itself.

Fo sure most of the code should be in the view and not in the kernel or AudioUnit, but I don't understand how to retrieve from the view the buffer populated in the audio unit itself (AUInternalRenderBlock). Should I use KVO on outputBus? But how to get the buffer itself :s Thanks in advance

Accepted Reply

Good practice might not be to retreive audio buffers directly into a view or view controller (thus breaking MVC partitioning), but in some separate audio model object or computation block. That audio object could retrieve audio buffers of the desired length, if available, from a lock-free circular fifo/buffer, compute the desired type of meter value, and, if changed, let the view controller know it needs to do a set-needs-display on the view. No need to compute at the audio tap rate, as the output can only be updated at the view's display frame rate (60 Hz or perhaps even lower). Thus the reason for an intermediate lock-free circular fifo/buffer to decouple rates. The fifo also minimized processor time spent in the audio tap or callback, since all it needs to do is a quick buffer copy into the fifo.

Replies

Hey there. You should be able to install a tap on the effect's output bus. Something like this:


//assumes you have a reference to the AudioUnit node
let bufferSize: AVAudioFrameCount = 4096
let busFormat = self.effect.outputFormatForBus(0)

self.effect.installTapOnBus(0, bufferSize: bufferSize, format: busFormat, block: { (buffer, when) -> Void in
              //do whatever you want with the buffer inside the callback
 }) 

Good practice might not be to retreive audio buffers directly into a view or view controller (thus breaking MVC partitioning), but in some separate audio model object or computation block. That audio object could retrieve audio buffers of the desired length, if available, from a lock-free circular fifo/buffer, compute the desired type of meter value, and, if changed, let the view controller know it needs to do a set-needs-display on the view. No need to compute at the audio tap rate, as the output can only be updated at the view's display frame rate (60 Hz or perhaps even lower). Thus the reason for an intermediate lock-free circular fifo/buffer to decouple rates. The fifo also minimized processor time spent in the audio tap or callback, since all it needs to do is a quick buffer copy into the fifo.

Hi, your solution is suitable for a AVAudioUnit, so in a AVAudioEngine scenario. I'm looking for a solution on the AUAudioUnit. Thx anyway!

Mummm I think you put me on the right track with the circular buffer! Could you confirm that the following steps are suitable for an AuAudioUnit:


  • Add a circular buffer (from apple example or anything else) member in AUAudioUnit (objective-c)
  • In internalRenderBlock (AUInternalRenderBlock) create a weak self and in the returned block put data in the circular buffer
  • On the other hand in the controller (swift) create a timer for a given frequency, get the circular buffer from the AudioUnit and consume the circular buffer, then do what ever you want with the data (any interaction with the main thread via dispatch_async)


Am I right?

The exact details of how to reference the lock-free circular fifo/buffer may differ. But your basic partitioning of the process seems correct: Audio callback copies audio buffer data; timer-based worker thread processes any new audio data if available; UI thread updates view if needed.

I've got it! Thx a lot!