2012-02-12 65 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秒。