前段时间仔细研究了一下音量曲线的问题。众所周知,人耳对声音强度的感知不是线性的,而是具有对数关系。所以理想的音量曲线应该是音量级数调节与音量大小的对数成线性关系。即:
-20lg(y) = a * (x - b)
假设音量级数为M,则有: x = M 时 -20lg(y) = 0dB ==> b = M
由此得到: -20lg(y) = a * (x - M)
假设最大音量范围为N dB, 则有: x = 0时, -20lg(y) = -NdB ==> a = N / M
由此得: -20lg(y) = (N/M) * (x - M)
从上面的计算,我们得到两个有趣的系数:
-
- a = N / M
- a * ln(10) / 20
阅读Android代码发现M = 100, N = 50
由此得到: a = 0.5 a * ln(10) / 20 = 0.5 * 2.302585093 / 20
以下是Android中用于计算音量的函数:
//
convert volume steps to natural log scale
// change this value to change volume scaling
static const float dBPerStep = 0.5f;
// shouldn't need to touch these
static const float dBConvert = -dBPerStep * 2.302585093f / 20.0f;
static const float dBConvertInverse = 1.0f / dBConvert;
float AudioSystem::linearToLog( int volume)
{
// float v = volume ? exp(float(100 - volume) * dBConvert) : 0;
// LOGD("linearToLog(%d)=%f", volume, v);
// return v;
return volume ? exp( float( 100 - volume) * dBConvert) : 0;
}
// change this value to change volume scaling
static const float dBPerStep = 0.5f;
// shouldn't need to touch these
static const float dBConvert = -dBPerStep * 2.302585093f / 20.0f;
static const float dBConvertInverse = 1.0f / dBConvert;
float AudioSystem::linearToLog( int volume)
{
// float v = volume ? exp(float(100 - volume) * dBConvert) : 0;
// LOGD("linearToLog(%d)=%f", volume, v);
// return v;
return volume ? exp( float( 100 - volume) * dBConvert) : 0;
}