2012-02-12 14 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

あなたは(0デシベルのために)あなたの参考として1.0を使用する場合デシベルリニア振幅を変換するための式、だから私は見てからの意図についてはよく分からない

20 * log10(amp); 

ですあなたのコードが、あなたはおそらくこれは、あなたが本当にそれは0〜120まであなたを行く必要がある場合は1 の振幅で0dBまで、ゼロの振幅で-Infinityから行きます

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

をしたいです120を追加し、ゼロでmax関数を使用できます。

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

あなたは私が何をしたいの反対だと思うこれは、アンプにDBを変換するための式のように見えるを使用している式:上記の行の後にそう

、。

編集:再読し、既にデシベル値があるようです。

このような場合は、ちょうどそう

double peakPowerForChannel = [recorder averagePowerForChannel:0]; 

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

を変更し、あなたが行くように大丈夫でなければなりませんが、振幅および120

を追加するために変換できません。

+0

こんにちはマイケル、返信いただきありがとうございます。 私はaveragePowerForChannelが-x のデシベル値であると信じています。それは0から120の値に変換されます。 – Desmond

+1

@Desmond:dec.elを直接使用するようにpeakPowerForChannelを変更することをお勧めします。あなたは後で120を追加しています。また、db = db <0でどのようにしたかのように、max(0、db)を使用してゼロより小さくないことを確認する必要があります。 0:db; ' –

+0

マイケルに感謝、しかし、デシベルは静かな部屋で非常に非常に高いです....私はそれを確認するデシベル10アプリをダウンロードする別の巨大なデシベル。アプリケーションは約40db、鉱山は70dbを示します。 私の主な目標は、ユーザーがノイズを出しているかどうかを確認することです。しきい値を超えると何かがトリガーされます。 – Desmond

1

実際には、デシベルの範囲は-160から0までであるが、それは正の値に行くことができる(AVAudioRecorder Class Reference - averagePowerForChannel:方法)。

そして代わりdb += 120;の良好書き込みdb += 160;あります。もちろん、それを修正するオフセットを置くこともできます。

22

アップルは、dBからレベルメーターに表示される線形値に変換するSpeakHereサンプルのルックアップテーブルを使用します。これはデバイスの電力を節約するためです(私は推測します)。

私はこれも必要でしたが、1/10秒ごとに2回の浮動計算(私のリフレッシュレート)を行うと、デバイスの電力が非常にかかるとは思われませんでした。私はあなたがaveragePowerForChannel:でのdBの取得を参照してください、しかし、あなたがあなた自身のdB値を埋めることができ、したがって、AVAudioRecorderを使用してい

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

:だから、代わりにテーブルを構築する私はに彼らのコードを成形しました。

アップルの例ではdoubleの計算を使用していますが、これはオーディオメータリングではfloatの精度では十分ではなく、デバイスの消費電力が低くなるためわかりません。

言うまでもなく、計算されたlevelを0 ... 120の範囲に単純にlevel * 120.0fでスケーリングすることができます。我々は2.0frootを固定する際

上記のコードは、sqrtf(adjAmp)powf(adjAmp, 1.0f/root)を置き換えることによって、スピードアップすることができます。しかし、それは小さなことであり、とても良いコンパイラが私たちのためにこれを行うことができるかもしれません。そして、私はほぼinverseAmpRangeがコンパイル時に一度計算されると確信しています。

-3

最大値と最小値を設定するだけです。 0-120の範囲を取得するように。 0〜60の範囲が必要な場合。単に私はNSRecorderから生成されたWAVデータとNSRecorder.averagePowerForChannel

NSRecorder.averagePowerForChannelからデシベルデータとの間のマッピング関係を変換する回帰モデル(dB)を作る半範囲を得るために半分に値を分割しように..

0

= -80 + 6 log2(wav_RMS

ここで、wav_RMSは、短時間、すなわち0.1秒におけるwavデータの二乗平均平方根値である。

関連する問題