很多場合我們需要動態顯示實時聲音分貝,下面列舉三種計算分貝的算法。(以雙聲道為例,也就是一個short類型,最大能量值為32767)
1:計算分貝 音頻數據與大小
首先我們分別累加每個采樣點的數值,除以采樣個數,得到聲音平均能量值。
然后再將其做100與32767之間的等比量化。得到1-100的量化值。
通常情況下,人聲分布在較低的能量范圍,這樣就會使量化后的數據大致分布在1-20的較小區間,不能夠很敏感的感知變化。
所以我們將其做了5倍的放大,當然計算后大于100的值,我們將其賦值100.
//參數為數據,采樣個數
//返回值為分貝
#define VOLUMEMAX 32767
int SimpleCalculate_DB(short* pcmData, int sample)
{
signed short ret = 0;
if (sample > 0){
int sum = 0;
signed short* pos = (signed short *)pcmData;
for (int i = 0; i < sample; i++){
sum += abs(*pos);
pos++;
}
ret = sum * 500.0 / (sample * VOLUMEMAX);
if (ret >= 100){
ret = 100;
}
}
return ret;
}
2:計算均方根(RMS) 即能量值
static const float kMaxSquaredLevel = 32768 * 32768;
constexpr float kMinLevel = 30.f;
void Process(const int16_t* data, size_t length)
{
float sum_square_ = 0;
size_t sample_count_ = 0;
for (size_t i = 0; i < length; ++i) {
sum_square_ += data[i] * data[i];
}
sample_count_ += length;.
float rms = sum_square_ / (sample_count_ * kMaxSquaredLevel);
//20log_10(x^0.5) = 10log_10(x)
rms = 10 * log10(rms);
if (rms < -kMinLevel)
rms = -kMinLevel;
rms = -rms;
return static_cast<int>(rms + 0.5);
}
3:獲取音頻數據最大的振幅(即絕對值最大)(0-32767),除以1000,得到(0-32)。從數組中獲取相應索引所對應的分貝值。(提取自webrtc)
const int8_t permutation[33] =
{0,1,2,3,4,4,5,5,5,5,6,6,6,6,6,7,7,7,7,8,8,8,9,9,9,9,9,9,9,9,9,9,9};
int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t* vector, size_t length)
{
size_t i = 0;
int absolute = 0, maximum = 0;
for (i = 0; i < length; i++) {
absolute = abs((int)vector[i]);
if (absolute > maximum) {
maximum = absolute;
}
}
if (maximum > 32767) {
maximum = 32767;
}
return (int16_t)maximum;
}
void ComputeLevel(const int16_t* data, size_t length)
{
int16_t _absMax = 0;
int16_t _count = 0;
int8_t _currentLevel = 0;
int16_t absValue(0);
absValue = WebRtcSpl_MaxAbsValueW16(data,length);
if (absValue > _absMax)
_absMax = absValue;
if (_count++ == 10) {
_count = 0;
int32_t position = _absMax/1000;
if ((position == 0) && (_absMax > 250)){
position = 1;
}
_currentLevel = permutation[position];
_absMax >>= 2;
}
}