xcode 我做正确的事情将分贝从 -120 - 0 转换为 0 - 120
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9247255/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Am I doing the right thing to convert decibel from -120 - 0 to 0 - 120
提问by Desmond
I will like to measure the sound volume of the surrounding, not too sure if I am doing the right thing.
我想测量周围的音量,不太确定我是否做对了。
I will like to create a VU meter of a range of 0(quiet) to 120(very noisy).
我想创建一个范围为 0(安静)到 120(非常嘈杂)的 VU 表。
I gotten the Peak and Avg power but are very high in normal quiet environment. Do give me some pointer.
我获得了峰值和平均功率,但在正常安静的环境中非常高。给我一些指点。
- (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);
}
采纳答案by Michael Chinen
The formula for converting a linear amplitude to decibels when you want to use 1.0 as your reference (for 0db), is
当您想使用 1.0 作为参考(对于 0db)时,将线性幅度转换为分贝的公式是
20 * log10(amp);
So I'm not sure about the intent from looking at your code, but you probably want
所以我不确定查看你的代码的意图,但你可能想要
float db = 20 * log10([recorder averagePowerForChannel:0]);
This will go from -infinity at an amplitude of zero, to 0db at an amplitude of 1. If you really need it to go up to between 0 and 120 you can add 120 and use a max function at zero.
这将从幅度为零的 -infinity 到幅度为 1 的 0db。如果您确实需要将其提高到 0 到 120 之间,您可以添加 120 并在零处使用 max 函数。
So, after the above line:
因此,在上述行之后:
db += 120;
db = db < 0 ? 0 : db;
The formula you are using appears to be the formula for converting DB to amp, which I think is the opposite of what you want.
您使用的公式似乎是将 DB 转换为 amp 的公式,我认为这与您想要的相反。
Edit: I reread and it seems you may already have the decibel value.
编辑:我重读了,看来您可能已经有了分贝值。
If this is the case, just don't convert to amplitude and add 120.
如果是这种情况,请不要转换为幅度并添加 120。
So Change
所以改变
double peakPowerForChannel = pow(10, (0.05 * [recorder averagePowerForChannel:0]));
to
到
double peakPowerForChannel = [recorder averagePowerForChannel:0];
and you should be okay to go.
你应该可以走了。
回答by meaning-matters
Apple uses a lookup table in their SpeakHeresample that converts from dB to a linear value displayed on a level meter. This is to save device power (I guess).
Apple 在他们的SpeakHere示例中使用了一个查找表,可以将 dB 转换为电平表上显示的线性值。这是为了节省设备电源(我猜)。
I also needed this, but didn't think a couple of float calculations every 1/10s (my refresh rate) would cost so much device power. So, instead of building up a table I moulded their code into:
我也需要这个,但没想到每 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);
}
I'm using an AVAudioRecorder
, hence you see getting the dB's with averagePowerForChannel:
, but you can fill your own dB value there.
我正在使用AVAudioRecorder
,因此您会看到使用 获得 dB averagePowerForChannel:
,但您可以在那里填充自己的 dB 值。
Apple's example used double
calculations, which I don't understand because for audio metering float
accuracy is more than sufficient, and costs less device power.
Apple 的示例使用了double
计算,我不明白这float
是因为音频计量精度绰绰有余,并且设备功耗更低。
Needless to say, you can now scale this calculated level
to your 0 .. 120 range with a simple level * 120.0f
.
不用说,您现在可以level
使用简单的level * 120.0f
.
The above code can be sped up when we fix root
at 2.0f
, by replacing powf(adjAmp, 1.0f / root)
with sqrtf(adjAmp)
; but that's a minor thing, and a very good compiler might be able to do this for us. And I'm almost sure that inverseAmpRange
will be calculated once at compile-time.
当我们修复root
at 时2.0f
,可以通过替换powf(adjAmp, 1.0f / root)
为sqrtf(adjAmp)
;来加快上述代码的速度。但这只是小事,一个非常好的编译器或许能为我们做到这一点。而且我几乎肯定inverseAmpRange
会在编译时计算一次。
回答by Vellozo
Actually, the range of decibels is from -160 to 0, but it can go to positive values.(AVAudioRecorder Class Reference- averagePowerForChannel: method)
实际上,分贝的范围是从 -160 到 0,但它可以变为正值。(AVAudioRecorder Class Reference- averagePowerForChannel: 方法)
Then is better write db += 160;
instead of db += 120;
. Of course you can also put an offset to correct it.
那么最好写db += 160;
而不是db += 120;
. 当然,您也可以放置一个偏移量来纠正它。
回答by David X. Lau
I make a regression model to convert the mapping relation between the wav data generated from NSRecorder
and the decibel data from NSRecorder.averagePowerForChannel
我做了一个回归模型来转换生成的 wav 数据NSRecorder
和来自的分贝数据之间的映射关系NSRecorder.averagePowerForChannel
NSRecorder.averagePowerForChannel
(dB) = -80+6 log2(wav_RMS
)
NSRecorder.averagePowerForChannel
(dB) = -80+6 log2( wav_RMS
)
Where wav_RMS
is root mean square value of wav data in a short time, i.e. 0.1 sec.
wav_RMS
wav数据在短时间内,即0.1秒的均方根值在哪里。
回答by Ritu Dalal
Simply set your maximum and minimum value. Like you getting range of 0-120. If you want range of 0-60. Simply divide value to half to get the half range and so on..
只需设置您的最大值和最小值。就像你得到 0-120 的范围一样。如果你想要0-60的范围。只需将值除以一半即可得到一半范围等。