Apple uses the lookup table in its SpeakHere sample, which converts from dB to the linear value displayed on the level meter. This is necessary to save the power of the device (I think).
I also needed this, but I did not think that a couple of floating calculations every 1 / 10s (my refresh rate) would cost that much power of the device. So, instead of creating a table, I formatted their code:
float level; // The linear 0.0 .. 1.0 value we need. const float minDecibels = -80.0f; // Or use -60dB, which I measured in a silent room. float decibels = [audioRecorder averagePowerForChannel:0]; if (decibels < minDecibels) { level = 0.0f; } else if (decibels >= 0.0f) { level = 1.0f; } else { float root = 2.0f; float minAmp = powf(10.0f, 0.05f * minDecibels); float inverseAmpRange = 1.0f / (1.0f - minAmp); float amp = powf(10.0f, 0.05f * decibels); float adjAmp = (amp - minAmp) * inverseAmpRange; level = powf(adjAmp, 1.0f / root); }
I use AVAudioRecorder , so you see that dB with averagePowerForChannel: but you can fill in your own dB value there.
Apple’s example used double calculations, which I don’t understand, because the accuracy of measuring a float sound is more than sufficient and costs less than the device’s power.
Needless to say, you can now scale this calculated level to a range of 0 .. 120 with a simple level * 120.0f .
The above code can be accelerated when we fix root in 2.0f by replacing powf(adjAmp, 1.0f / root) with sqrtf(adjAmp) ; but this is a minor thing, and a very good compiler can do this for us. And I'm pretty sure that inverseAmpRange will be computed once at compile time.
meaning-matters
source share