我会喜欢测量周围的音量,不太确定我做的是否正确。
我想创建一个范围为 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/