PCM 分貝獲取

1:計(jì)算分貝 音頻數(shù)據(jù)與大小

首先我們分別累加每個(gè)采樣點(diǎn)的數(shù)值,除以采樣個(gè)數(shù),得到聲音平均能量值。

然后再將其做100與32767之間的等比量化。得到1-100的量化值。

通常情況下,人聲分布在較低的能量范圍,這樣就會使量化后的數(shù)據(jù)大致分布在1-20的較小區(qū)間,不能夠很敏感的感知變化。

所以我們將其做了5倍的放大,當(dāng)然計(jì)算后大于100的值,我們將其賦值100.

//參數(shù)為數(shù)據(jù),采樣個(gè)數(shù)

//返回值為分貝

#define VOLUMEMAX? 32767

intSimpleCalculate_DB(short* pcmData,intsample)

{

? ? signedshortret =0;

? ? if(sample >0){

? ? ? ? intsum =0;

? ? ? ? signedshort* pos = (signedshort*)pcmData;

? ? ? ? for(inti =0; i < sample; i++){

? ? ? ? ? ? sum +=abs(*pos);

? ? ? ? ? ? pos++;

? ? ? ? }

? ? ? ? ret = sum *500.0/ (sample *VOLUMEMAX);

? ? ? ? if(ret >=100){

? ? ? ? ? ? ret =100;

? ? ? ? }

?? }

?? returnret;

}

2:計(jì)算均方根(RMS) 即能量值

static const float kMaxSquaredLevel = 32768 * 32768;

constexpr float kMinLevel = 30.f;

voidProcess(constint16_t* data,size_tlength)

{

? ? floatsum_square_ =0;

? ? size_tsample_count_ =0;

? ? for(size_ti =0; i < length; ++i) {

? ? ? ? sum_square_ += data[i] * data[i];

? ? }

? ? sample_count_ += length;.

? ? floatrms = sum_square_ / (sample_count_ * kMaxSquaredLevel);

? ? //20log_10(x^0.5) = 10log_10(x)

? ? rms =10* log10(rms);

? ? if(rms < -kMinLevel)

? ? ? ? rms = -kMinLevel;

? ? rms = -rms;

? ? returnstatic_cast<int>(rms +0.5);

}

3:獲取音頻數(shù)據(jù)最大的振幅(即絕對值最大)(0-32767),除以1000,得到(0-32)。從數(shù)組中獲取相應(yīng)索引所對應(yīng)的分貝值。(提取自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_ti =0;

? ? intabsolute =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;

}

voidComputeLevel(constint16_t* data,size_tlength)

{

? ? int16_t_absMax =0;

? ? int16_t_count =0;

? ? int8_t_currentLevel =0;

? ? int16_tabsValue(0);

? ? absValue = WebRtcSpl_MaxAbsValueW16(data,length);

? ? if(absValue> _absMax)

? ? ? ? _absMax =absValue;

? ? if(_count++ ==10) {

? ? ? ? _count =0;

? ? ? ? int32_tposition = _absMax/1000;

? ? ? ? if((position ==0) && (_absMax >250)){

? ? ? ? ? ? position =1;

? ? ? ? }

? ? ? ? _currentLevel = permutation[position];

? ? ? ? _absMax >>=2;

? ? }

}


分貝公式

參數(shù):Pref:就是聲音總的振幅最大值;Prms:就是當(dāng)前聲音的振幅值;Lp:就是我們需要的聲音分貝值了。

比如:我們聲音是無符號16bit深度的,那么其每個(gè)采樣點(diǎn)的值應(yīng)該在(0~2^16-1既:0~65535)范圍內(nèi),帶入公式我們可以計(jì)算到(不用除以最大振幅值):20*log(65535)=96.32db,所以根據(jù)這個(gè)我們只要拿到某個(gè)采樣點(diǎn)的振幅值,也就是當(dāng)前聲音采樣點(diǎn)轉(zhuǎn)成16bit后的值就可以計(jì)算出相應(yīng)的分貝值了。那么怎么求聲音采樣點(diǎn)的振幅呢?這是一個(gè)問題,不過也有解決辦法了。

獲取pcm聲音采樣點(diǎn)的振幅:

這里以我項(xiàng)目中用OpenSL來播放FFmpeg重采樣生成的PCM聲音為例,PCM聲音是重采樣為無符號16bit的深度的,然后我們需要得到某一時(shí)間(一般是零點(diǎn)幾毫秒)PCM所在內(nèi)存的地址和PCM聲音的大小,而16bit也就是16bit/8bit=2byte,在c語言中2byte用short int來表示,因此我們可以從PCM所在地址里面按順序取出2個(gè)byte的數(shù)據(jù)然后轉(zhuǎn)化成short int的值就可以拿到當(dāng)前采樣點(diǎn)的振幅了,獲取的方式是用c語言中的memcpy拷貝2個(gè)字節(jié)的數(shù)據(jù)求值就可以了。(注:因?yàn)椴捎命c(diǎn)很密集,如果每個(gè)采用點(diǎn)都計(jì)算一下分貝的話,會消耗一定的性能或者導(dǎo)致聲音播放不連貫,所這里采用取其絕對值和的平均值就可以了,因?yàn)樵谶@段時(shí)間內(nèi),我們看不出任何的區(qū)別。)

/**

* 獲取所有振幅之平均值 計(jì)算db (振幅最大值 2^16-1 = 65535 最大值是 96.32db)

* 16 bit == 2字節(jié) == short int

* 無符號16bit:96.32=20*lg(65535);

*

* @param pcmdata 轉(zhuǎn)換成char類型,才可以按字節(jié)操作

* @param size pcmdata的大小

* @return

*/

intAudio::getPcmDB(constunsignedchar*pcmdata,size_tsize) {

intdb =0;

shortintvalue =0;

doublesum =0;

for(inti =0; i < size; i +=2)

? ? {

memcpy(&value, pcmdata+i,2);//獲取2個(gè)字節(jié)的大?。ㄖ担?/p>

sum +=abs(value);//絕對值求和

? ? }

sum = sum / (size /2);//求平均值(2個(gè)字節(jié)表示一個(gè)振幅,所以振幅個(gè)數(shù)為:size/2個(gè))

if(sum >0)

? ? {

db = (int)(20.0*log10(sum));

? ? }

return db;

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容