iphone - 我做的是将分贝从 -120 - 0 转换为 0 - 120 的正确做法吗

标签 iphone ios xcode audio-recording decibel

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

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

最佳答案

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

我也需要这个,但没想到每 1/10 秒(我的刷新率)进行几次浮点计算会消耗如此多的设备功率。因此,我没有构建表格,而是将他们的代码塑造成:

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,但您可以在那里填写您自己的 dB 值。

Apple 的示例使用了 double 计算,我不明白这是因为对于音频计量,float 精度绰绰有余,而且设备功耗更低。

不用说,您现在可以使用简单的 level * 120.0f 将这个计算出的 level 缩放到您的 0 .. 120 范围。

当我们将 root 固定在 2.0f 时,通过替换 powf(adjAmp, 1.0f/root) 可以加快上面的代码使用 sqrtf(adjAmp);但这是一件小事,一个非常好的编译器也许能够为我们做这件事。而且我几乎可以肯定 inverseAmpRange 将在编译时计算一次。

关于iphone - 我做的是将分贝从 -120 - 0 转换为 0 - 120 的正确做法吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9247255/

相关文章:

iphone - 在 iphone 中使用 ASIHTTPRequest

swift - 使用 Storyboard中定义的自定义类

ios - Xcode 中的容器 View 被截断

ios - 多次触发 ALAssetLibraryChangedNotification

iphone - 当前位置的注释

iphone - 使用标签栏项目加载 View !

iphone - 让 iPhone 不 sleep

ios - 具有不同类的 UIViewcontroller 的直接按钮

ios - 你如何在 iOS 7 中获得 ADBannerView 的渲染宽度?

ios - 更改标题 View iOS