What I am trying to do is to take the float value from EZAudio and convert it into decibels.
EZAudioDelegate
这是我的简化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 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
该解决方案使用Accelerate Framework中的以下方法将卷转换为分贝:
> vDSP_vsq
> vDSP_meanv
> vDSP_vdbcon
以下是EZAudio Delegate所调用的getDecibelsFromVolume方法.它从委托中传递了float ** buffer和bufferSize.
- (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],bufferSize); vDSP_meanv(buffer[0],&meanVal,bufferSize); vDSP_vdbcon(&meanVal,&one,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; }
解决方法
首先,计算一个数据块的RMS和
double sumSquared = 0; for (int i = 0 ; i < numSamples ; i++) { sumSquared += samples[i]*samples[i]; } double rms = sumSquared/numSamples;
有关RMS的更多信息
接下来将RMS值转换为dB
double dBvalue = 20*log10(rms);
这与示例代码有关
vDSP_vsq(buffer[0],bufferSize);
该行循环遍历缓冲区,并计算缓冲区中所有元素的平方.如果缓冲区在调用之前包含值[1,2,3,4],则在调用后将包含值[1,4,9,16]
vDSP_meanv(buffer[0],对缓冲区中的值进行求和,然后返回总和除以元素数.所以对于输入缓冲区[1,16]计算总和30,除以4并返回结果7.5.vDSP_vdbcon(&meanVal,0);该行将meanVal转换为分贝.在这里调用矢量化函数真的没有意义,因为它只能在单个元素上运行.然而,它正在做的是将参数插入到以下公式中:
meanVal = n*log10(meanVal/one)其中n为10或20,具体取决于最后一个参数.在这种情况下,它是10. 10用于功率测量,20是用于振幅.我认为20对你来说会更有意义.
最后一点代码看起来正在做一些简单的平滑的结果,使仪表有点小的弹性.