我是否正确地将分贝从-120 – 0转换为0 – 120

我会喜欢测量周围的音量,不太确定我是否做正确的事情。

我想创build一个范围从0(安静)到120(非常嘈杂)的VU表。

我获得了峰值和平均功率,但是在正常的安静环境中非常高。 请给我一些指针。

- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //creating an audio CAF file in the temporary directory, this isn't ideal but it's the only way to get this class functioning (the temporary directory is erased once the app quits). Here we also specifying a sample rate of 44.1kHz (which is capable of representing 22 kHz of sound frequencies according to the Nyquist theorem), and 1 channel (we do not need stereo to measure noise). NSDictionary* recorderSettings = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:kAudioFormatLinearPCM],AVFormatIDKey, [NSNumber numberWithInt:44100],AVSampleRateKey, [NSNumber numberWithInt:1],AVNumberOfChannelsKey, [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey, [NSNumber numberWithBool:NO],AVLinearPCMIsBigEndianKey, [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey, nil]; NSError* error; NSURL *url = [NSURL fileURLWithPath:@"/dev/null"]; recorder = [[AVAudioRecorder alloc] initWithURL:url settings:recorderSettings error:&error]; //enable measuring //tell the recorder to start recording: [recorder record]; if (recorder) { [recorder prepareToRecord]; recorder.meteringEnabled = YES; [recorder record]; levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self selector: @selector(levelTimerCallback:) userInfo: nil repeats: YES]; } else { NSLog(@"%@",[error description]); } } - (void)levelTimerCallback:(NSTimer *)timer { [recorder updateMeters]; const double ALPHA = 0.05; double peakPowerForChannel = pow(10, (0.05 * [recorder averagePowerForChannel:0])); lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults; NSLog(@"Average input: %f Peak input: %f Low pass results: %f", [recorder averagePowerForChannel:0], [recorder peakPowerForChannel:0], lowPassResults); float tavgPow =[recorder averagePowerForChannel:0] + 120.0; float tpPow = [recorder peakPowerForChannel:0] + 120.0; float avgPow = tavgPow;//(float)abs([recorder averagePowerForChannel:0]); float pPow = tpPow;//(float)abs([recorder peakPowerForChannel:0]); NSString *tempAvg = [NSString stringWithFormat:@"%0.2f",avgPow]; NSString *temppeak = [NSString stringWithFormat:@"%0.2f",pPow]; [avg setText:tempAvg]; [peak setText:temppeak]; NSLog(@"Average input: %f Peak input: %f Low pass results: %f", avgPow,pPow , lowPassResults); } 

当你想使用1.0作为参考(对于0db)时,将线性幅度转换为分贝的公式是

 20 * log10(amp); 

所以我不确定看你的代码的意图,但你可能想要

 float db = 20 * log10([recorder averagePowerForChannel:0]); 

这将从幅度为零的无穷大到幅度为1的0db。如果您确实需要它在0到120之间,则可以添加120,并在零处使用最大值函数。

所以,在上面的行之后:

 db += 120; db = db < 0 ? 0 : db; 

你使用的公式似乎是将数据库转换为放大器的公式,我认为这与你想要的相反。

编辑:我重读,似乎你可能已经有了分贝价值。

如果是这种情况,只是不要转换为幅度,并添加120。

所以改变

 double peakPowerForChannel = pow(10, (0.05 * [recorder averagePowerForChannel:0])); 

 double peakPowerForChannel = [recorder averagePowerForChannel:0]; 

你应该可以走了。

Apple在他们的SpeakHere示例中使用了一个查找表,将dB转换为电平表上显示的线性值。 这是为了节省设备电源(我猜)。

我也需要这个,但是没有想到每隔1 / 10s(我的刷新率)计算浮点数就会花费太多的设备功耗。 所以,我没有build立一张桌子,而是将他们的代码塑造成:

 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); } 

我正在使用AVAudioRecorder ,因此您可以看到AVAudioRecorder获得dB,但是您可以在那里填写自己的dB值。

苹果公司的例子使用double计算,我不明白,因为audio测量float精度绰绰有余,成本较低的设备功耗。

不用说,你现在可以用一个简单的level * 120.0f这个计算出来的level扩展到你的0 .. 120范围。

通过用sqrtf(adjAmp)replacepowf(adjAmp, 1.0f / root) ,可以加速上面的代码。 但这是一个小问题,一个非常好的编译器可能能够为我们做到这一点。 我几乎可以肯定, inverseAmpRange将在编译时计算一次。

实际上,分贝的范围是从-160到0,但是它可以变成正值( AVAudioRecorder类参考 – averagePowerForChannel:方法)

那么最好写db += 160; 而不是db += 120; 。 当然,你也可以把一个偏移来纠正它。

我做了一个回归模型来转换NSRecorder生成的wav数据和NSRecorder的分贝数据之间的映射关系

NSRecorder.averagePowerForChannel (dB)= -80 + 6 log2( wav_RMS

其中wav_RMS是短时间内wav数据的均方根值,即0.1秒。

只需设置您的最大值和最小值。 就像你得到0-120的范围 如果你想要0-60的范围。 简单地把价值分成一半来得到半价等等。

Interesting Posts