当前位置:网站首页>音频PCM数据计算声音分贝值,实现简单VAD功能

音频PCM数据计算声音分贝值,实现简单VAD功能

2022-06-24 20:36:00 SongYuLong的博客

计算音频数据PCM分贝值,计算公式:
L p = 20 ∗ L o g 10 ( P r m s / P r e f ) d B L_p=20*Log_{10}(Prms/Pref)dB Lp=20Log10(Prms/Pref)dB

P r m s Prms Prms:当前声音振幅值;
P r e f Pref Pref:声音振幅最大值(即PCM数据表示的最大值);
对于16bitsPCM数据,一个声音采样点为2个字节最大( 2 16 − 1 = 65535 2^{16}-1=65535 2161=65535
我们对n个采样点数据求和然后取其平均值,作为 P r m s / P r e f Prms/Pref Prms/Pref

/** * @brief 获取PCM数据分贝值 * * @param pcm : pcm数据指针 * @param len : pcm数据长度 * @return int : 分贝值 = 20*log10(pcm数据平均值) * @note Lp = 20*log10(Prms/Pref)dB | Lp:计算结果音频分贝值, Prms:当前声音振幅值,Pref:声音振幅最大值(16bit=65535), 16Bit最大分贝值=20*log10(65535)=96.32(dB)。 * */
static int komijbox_sound_dB(const uint8_t *pcm, int len)
{
    
	int sum = 0;
	int dB = 0;
	short tmp = 0;
	short* pcmaddr = (short*)pcm;

	for (int i=0; i<len; i+=2) {
    
		memcpy(&tmp, pcmaddr+i, sizeof(short)); // 获取2字节PCM数据
		sum += abs(tmp); // 绝对值求和累加
	}
	
	sum = sum / (len /2); // 求PCM数据的平均值,2个字节表示一个16Bit PCM采样数据
	if (sum) {
    
		dB = (int)(20*log10(sum));
	}

	return dB;
}

通过音频分贝值实现简单VAD功能:

#define D_VAD_VALID_dB_Max 75 // VAD 有效分贝值 最大值 大于此值认为VAD有效
#define D_VAD_VALID_dB_Min 58 // VAD 无效分贝值 最小值 小于此值认为VAD无效
#define D_VAD_VALID_UP_COUNT 2 // VAD 拉起计数(连续有效值计数),大于此值触发 VAD_UP事件
#define D_VAD_VALID_DOWN_COUNT 30 // VAD 拉起计数(连续无效值计数),大于此值触发 VAD_DOWN事件

/** * @brief VAD 状态类型 * */
enum {
    
	E_VAD_STATUS_NONE = 0,
	E_VAD_STATUS_UP,	 		// Up
	E_VAD_STATUS_LISTENING,	 	// Listening
	E_VAD_STATUS_DOWN			// Down
};

typedef void (*vad_callback)(int vad_status);

struct __vad_t{
    
	int status;
	int up_count;
	int down_count;
	vad_callback up_cb;
	vad_callback down_cb;
	vad_callback listening_cb;
};


// TODO:计算音频PCM数据音频分贝值
int dB = komijbox_sound_dB((uint8_t*)data, len);
	// printf("pcmdB:%d\n", dB);

	// TODO:通过音频分贝值判断VAD状态,实现声控开关功能
	if (dB >= D_VAD_VALID_dB_Max) {
    
		__this->vad.up_count += 1;
		__this->vad.down_count = 0;
		if (__this->vad.up_count >= D_VAD_VALID_UP_COUNT) {
    
			// __this->vad.down_count = 0;

			if (__this->vad.status != E_VAD_STATUS_UP) {
    
				__this->vad.status = E_VAD_STATUS_UP;
			
				// TODO: VAD UP
				printf("=============== VAD Up\n");
				if (__this->vad.up_cb != NULL) {
    
					__this->vad.up_cb(__this->vad.status);
				}

			} else {
    
				// TODO: VAD LISTENING // listening
				printf("=============== VAD Listening\n");
			}			
		}
	} else if (dB <= D_VAD_VALID_dB_Min) {
    
		__this->vad.down_count += 1;
		__this->vad.up_count = 0;
		if (__this->vad.down_count >= D_VAD_VALID_DOWN_COUNT) {
    
			// __this->vad.up_count = 0;

			if (__this->vad.status != E_VAD_STATUS_DOWN) {
    
				__this->vad.status = E_VAD_STATUS_DOWN;

				// TODO: VAD DOWN
				printf("=============== VAD Down\n");
				if (__this->vad.down_cb != NULL) {
    
					__this->vad.down_cb(__this->vad.status);
				}
			}			
		}
	}
原网站

版权声明
本文为[SongYuLong的博客]所创,转载请带上原文链接,感谢
https://blog.csdn.net/u013420428/article/details/125440664