2012-02-12 47 views
7

我想测量周围的音量,如果我做的是正确的话,我不太确定。我是否正确地将分贝从-120 - 0转换为0 - 120

我想创建一个范围为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); 
} 

回答

8

用于将线性幅度的公式,以分贝,当你想使用1.0作为您的参考(为0分贝),是

20 * log10(amp); 

所以我不知道的意图从看你的代码,但你可能想

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

这将从-infinity走在零的幅度,以1 幅度为0dB如果你真的需要它上升到120,你在0〜可以添加120并在零处使用最大值函数。

所以,上面的行之后:

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

您使用的似乎是将DB来放,我想这是你想要的正好相反公式公式。

编辑:我重读,看起来你可能已经有了分贝值。

如果是这样的话,就是不转换幅度和增加120

所以更改

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

double peakPowerForChannel = [recorder averagePowerForChannel:0]; 

和你应该没去。

+0

嗨迈克尔,感谢您的回复。 我相信平均PowerForChannel是-x 将要转换为0 - 120值的分贝值 – Desmond 2012-02-12 08:50:05

+1

@Desmond:好的,我建议更改peakPowerForChannel以直接使用分贝值的最后一步。您稍后再添加120。你还需要通过使用max(0,db)来确保它不小于零,就像我对'db = db <0'所做的一样。 0:db;' – 2012-02-12 09:20:07

+0

感谢迈克尔,然而分贝在一个安静的房间里非常高......我下载了一个decibel10应用程序来检查它的分贝不同是巨大的。该应用程序显示约40db,我的显示70db。 我的主要目标是检查用户是否在发出噪音。如果超过阈值就会触发一些事情。 – Desmond 2012-02-12 09:39:12

1

其实分贝的范围为-160至0,但可以去正值(AVAudioRecorder Class Reference - averagePowerForChannel:法)。

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

22

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

我也需要这个,但是没有想到每隔1/10s(我的刷新率)计算浮点数会花费很多设备功耗。因此,而不是建立一个表我成型他们的代码为:

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,因此你看到获得分贝与averagePowerForChannel:,但你可以在那里填你自己的dB值。

苹果的例子使用double计算,我不明白,因为对于音频测量float准确性绰绰有余,并且成本较低的设备功耗。不用说,您现在可以使用简单的level * 120.0f将此计算的level缩放到0 .. 120范围内。

当我们修复root2.0f时,通过用sqrtf(adjAmp)代替powf(adjAmp, 1.0f/root),可以加速上述代码;但这是一件小事,而一个非常好的编译器可能能够为我们做到这一点。我几乎可以确定inverseAmpRange将在编译时计算一次。

-3

只需设置您的最大值和最小值。就像你得到0-120的范围一样。如果你想要0-60的范围。简单地划分值的一半,以获得半程等..

0

我做一个回归模型,从NSRecorder生成WAV数据和分贝数据之间的映射关系,从NSRecorder.averagePowerForChannel

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

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

相关问题