Paul Stewart
Paul Stewart

Reputation: 31

AudioKit (iOS). Can I actually set the microphone gain at the hardware level?

I'm new to all of this (Xcode, AudioKit), but what I want to create is an app that is capable of recording really loud audio (for example, acoustic drums). The deal is that I need to be able to set the microphone's gain down, probably significantly. That is, it will likely not be nearly enough to simply do some sort of multiplication on the received samples, so I want to set the gain at the hardware level.

I realize that there will be limitations on exactly what I can do with iPhone/iPad internal mic; at least some mics will have physical limitations, especially on older/cheaper models. What I do know at this point is that apps like GarageBand are capable of setting input gain on some devices. Using GB on my old iPad, I'm only able to set the gain if an external mic is connected (and it works perfectly). I've seen some YouTube vids where folks use GB to set gain on an internal mic.

So far I've played around with a variety of examples, including Xamarin and Xcode stuff. Using AVAudioSession.inputGainSettable returns true, oddly enough, on my iPad's internal mic. What's weird is that setInputGain works fine if the range is between 0.7 and 1.0. Anything lower doesn't produce any errors, but inputGain is set to 0.7. At 0.7, there is a noticeable difference than at 1.0, but I still don't really know what is happening under the covers: is the actual input level lower or are the samples "pre-processed" to lower absolute values?

I've had other problems with AVFoundation for audio capture. On the old iPad, except for the gain setting limitation described above, AVFoundation audio capture works well, especially when I use an external mic (I can set the gain to anything between 0 and 1, and the recorded audio is what I expect). On an iPhone XR, inputGainSettable always returns false, even with an external mic, and setInputGain always fails.

So it looks like I need to drop down to a lower level. This is all rather fuzzy to me at the moment, but I suppose that I could use AudioUnits and a mixer, then maybe set the gain on the input? That brings me to AudioKit.

I'm working with the Recorder sample in AudioKit. I can play around with AKBooster to set the gain on an AKNode instance. But it isn't clear to me if I am to set the gain on the AKMicrophone or the AKMixer (for the instance created by AKStereoFieldLimiter). They seem to have the same effect. The result is that my input levels are lower, but there is still clipping. So my questions is: Is this really setting the microphone's gain at the hardware level (and what I'm seeing is just a physical limitation of the internal mic), or do I not understand the proper use of an AKNode in a mixer?

If the answer is "setting the gain down so that you can record acoustic drums isn't possible", how do you suppose something like GarageBand does it?

Thanks!

Upvotes: 1

Views: 1282

Answers (1)

Paul Stewart
Paul Stewart

Reputation: 31

OK, some things learned and a mistery...

First, I was wrong when I said that I'm not able to set the "input" level (gain) in GarageBand on my old iPad. I can, but the range is 0.7 to 1.0. More on that later...

I have been experimenting with the AudioKit Recorder example project. As far as I can tell, the following have no effect on actually setting the microphone's gain at the hardware level:

let mic = AKMicrophone()
mic.volume = volumeSetting

and...

let mic = AKMicrophone()
let gainedMic = AKBooster(mic)
gainedMic.gain = gainSetting

Although I'm not certain of this, it appears that there is a correlation between AKMicrophone.volume and AKBooster.gain. So let's say I have this:

let mic = AKMicrophone()
let gainedMic = AKBooster(mic)

if I do this...

mic.volume = 5.0
gainedMic.gain = 1.0

the output seems to be the same as if I do this instead:

mic.volume = 10.0
gainedMic.gain = 0.5

So it looks like (unless I'm missing something here) that AKMicrophone.volume and AKBooster.gain are not going to be something I'm going to be able to use to adjust the mic's gain so I can record acoustic drums. What I didn't get, though, was why I could use my modified Recorder example app and play around with AKMicrophone and/or AKBooster and get a good recording of my acoustic drums if I used an external mic? I was expecting it to clip. Then I realized that if I set AKBooster gain to 1.0 and AKMicrophone to 10, the output was clipping, but not nearly as much as I expected.

Then I took a look at AKSettings.session.inputGain. AKSettings.session is a thin wrapper for AVAudioSession. In my modified Recorder app, I set up the mic and mixer without setting either AKMicrophone.volume and AKBooster.gain. Then I inspected AKSettings.session.inputGain. On the old iPad, I get 0.75 for the internal mic. When I connect the external mic and launch the modified Recorder app, the AKSettings.session.inputGain value varies. The inputGain setting appears to be whatever it was last set via AVAudioSession.setInputGain(). That is, if I load GB, set mic "input" to max, unload GB, load Recorder, then AKSettings.session.inputGain is 1.0.

What's really strange here is that if I set the mic gain via AVAudioSession.setInputGain() in a non-AudioKit example app or in GB, then shut down the iPad, start the iPad again and launch the modified Recorder app, AKSettings.session.inputGain reports the last gain set by the other app prior to shutdown. What is saving this hardware gain value? The iPad? The extermal mic (Blue Snowball)?

As it turns out, during my tests with the external mic and the modified Recorder app, I didn't get any clipping because AKSettings.session.inputGain was somewhere around 0.2 during the tests. The comments in "AVAudioSession.h" state that the iOS device will set AKSettings.session.inputGain to the mic's default if it has a default, but some mics don't have a default value. So I suppose that either my Blue Snowball either doesn't have a default gain value, or it defines the default as the last gain AVAudioSession.setInputGain() it received.

At any rate, I'm quite surprised I couldn't find any discussion on AKMicrophone.volume and AKBooster.gain, especially when dealing with external mics. For internal mics, in my small test scenario (an old iPad with a mic gain range of 0.7 and 1.0 and an iPhone XR with no ability to change gain) I have two devices that perform somewhat significantly different. This is because the underlying hardware is such that for the iPad I start off with an internal mic whos gain is set to 0.75 and iPhone with a mic gain set to 1.0. So if I were developing a voice recording app with AudioKit, it's likely that the starting point of my app would either be set so that I'd have proper recording levels for the iPad and have clipping problems on the iPhone, or it would be proper for the iPhone but too quiet for the iPad. As for external mics, how is it that no one has brought up that using different external mics on various iOS devices produced wildly different experiences?

I think I may be back to the point where I'm still missing something important in AudioKit as it relates to AKMicrophone.volume, AKBooster.gain and AKSettings.session.inputGain. Can someone please shed some light on this? Thanks!

Upvotes: 2

Related Questions