Can someone explain how this code converts volume to decibels using the Accelerate Framework?
accelerate-framework, ezaudio, ios, objective-c
Solution
I'll explain how one would compute a dB value for a signal using code and then show how that relates to the vDSP example.
First, compute the RMS sum of a chunk of data
double sumSquared = 0;
for (int i = 0 ; i < numSamples ; i++)
{
sumSquared += samples[i]*samples[i];
}
double rms = sumSquared/numSamples;
For more information on RMS
Next convert the RMS value to dB
double dBvalue = 20*log10(rms);
How this relates to the example code
vDSP_vsq(buffer[0], 1, buffer[0], 1, bufferSize);
This line loops over the buffer and computes squares all of the elements in the buffer. If buffer contained the values `[1,2,3,4]` before the call then after the call it would contain the values `[1,4,9,16]`
vDSP_meanv(buffer[0], 1, &meanVal, bufferSize);
This line loops over the buffer, summing the values in the buffer and then returning the sum divided by the number of elements. So for the input buffer `[1,4,9,16]` in computes the sum `30`, divides by `4` and returns the result `7.5`.
vDSP_vdbcon(&meanVal, 1, &one, &meanVal, 1, 1, 0);
This line converts the `meanVal` to decibels. There is really no point in calling a vectorized function here since it is only operating on a single element. What it is doing however is plugging the parameters into the following formula:
meanVal = n*log10(meanVal/one)
where `n` is either `10` or `20` depending on the last parameter. In this case it is `10`. `10` is used for power measurements and `20` is used for amplitudes. I think `20` would make more sense for you to use.
The last little bit of code looks to be doing some simple smoothing of the result to make the meter a little less bouncy.
Problem
I'm building an iOS app using EZAudio. It's delegate returns back a `float**` buffer, which contains float values indicating the volume detected. This delegate is called constantly and it's work is done a different thread. What I am trying to do is to take the float value from EZAudio and convert it into decibels. EZAudioDelegate Here's my simplified EZAudio Delegate for getting Microphone Data: ``` - (void)microphone:(EZMicrophone *)microphone hasAudioReceived:(float **)buffer withBufferSize:(UInt32)bufferSize withNumberOfChannels:(UInt32)numberOfChannels { /* * Returns a float array called buffer that contains the stereo signal data * buffer[0] is the left audio channel * buffer[1] is the right audio channel */ // Using a separate audio thread to not block the main UI thread dispatch_async(dispatch_get_main_queue(), ^{ float decibels = [self getDecibelsFromVolume:buffer withBufferSize:bufferSize]; NSLog(@"Decibels: %f", decibels); }); } ``` The Problem The problem is that after implementing solutions from the links below, I do not understand how it works. If someone could explain how it converts volume to decibels I would be very grateful How to convert audio input to DB? #85 How to change the buffer size to increase FFT window? #50 Changing Buffer Size #84 The Code The solution uses the following methods from the Accelerate Framework to convert the volume into decibels: - vDSP_vsq - vDSP_meanv - vDSP_vdbcon Below is the method `getDecibelsFromVolume` that is called from the EZAudio Delegate. It is passed the `float** buffer` and `bufferSize` from the delegate. ``` - (float)getDecibelsFromVolume:(float**)buffer withBufferSize:(UInt32)bufferSize { // Decibel Calculation. float one = 1.0; float meanVal = 0.0; float tiny = 0.1; float lastdbValue = 0.0; vDSP_vsq(buffer[0], 1, buffer[0], 1, bufferSize); vDSP_meanv(buffer[0], 1, &meanVal, bufferSize); vDSP_vdbcon(&meanVal, 1, &one, &meanVal, 1, 1, 0); // Exponential moving average to dB level to only get continous sounds. float currentdb = 1.0 - (fabs(meanVal) / 100); if (lastdbValue == INFINITY || lastdbValue == -INFINITY || isnan(lastdbValue)) { lastdbValue = 0.0; } float dbValue = ((1.0 - tiny) * lastdbValue) + tiny * currentdb; lastdbValue = dbValue; return dbValue; } ```