⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 basop.cpp

📁 语音识别的端点检测程序
💻 CPP
字号:
/*******************************************************************
****	文件:		basop.cpp									****
****	功能:		计算LPCC 和 MFCC所用到的一些共同的基本函数	****
**** 			 浮点程序										****
****	最后定型01.08.20, 许海国		          				****
*******************************************************************/

#include  <math.h>

#include "cst_lib.h"
#include "basop.h"
#include "mfcc_xhg.h"

/*=====================================================
函数名称:	Initial
函数功能:	对Hanming窗系数
函数性质:	
输入参数:	OptionMode	工作模式选择, LPCC或者是MFCC, 或者其它
输出参数:	HanmingWindow[FRAME_LEN]	//hanming窗函数
备注:		每次程序运行, 只需要一次初始化就可以了,
			本函数使用到的常数有 
			FRAME_LEN			帧长 
====================================================*/
void	Initial(float	HanmingWindow[FRAME_LEN])
{
	int	wSampleCount;		//循环用变量, 样点, 倒谱
	float fDataTemp;					//中间变量
	
	//初始化hanming窗函数
	//HANMING 0.54 - 0.46 * COS( 2 * n * PI / ( N - 1) ) (N为帧长)
	fDataTemp = (float) 2.0 * PI / (FRAME_LEN - 1);
	for(wSampleCount=0; wSampleCount<FRAME_LEN; wSampleCount++)
		HanmingWindow[wSampleCount] = (float) (0.54 - 0.46 * cos( wSampleCount * fDataTemp));

}

/*=====================================================
函数名称:	PreEmphasis
函数功能:	对原始语音数据预加重
输入参数:	fOneFrameData 单帧语音数据内存头 
输出参数:	无
备注:		每帧的前一个点取第1个点的值代替  S'(n)=S(n)-0.98*S(n-1)
			用到的常数定义有
			FRAME_LEN			帧长
			PRE_EMPHASIS_FACTOR	预加重系数
====================================================*/
void PreEmphasis(float *fOneFrameData)
{
	
    int   i;
    float acc0[FRAME_LEN];	
    
   	acc0[0] = fOneFrameData[0] - PRE_EMPHASIS_FACTOR * fOneFrameData[0];
	for (i=1; i < FRAME_LEN; i++)
       	acc0[i] = fOneFrameData[i] -PRE_EMPHASIS_FACTOR * fOneFrameData[i-1];
        
	for (i=0; i < FRAME_LEN; i++)
   	 	fOneFrameData[i] = acc0[i];
}

/*=====================================================
函数名称:	sign
函数功能:	符号计算
输入参数:	x	需要计算符号的数据
输出参数:	该数据的符号位, x>0, 符号为1, x=<0, 符号位为-1
====================================================*/
int sign(float x)
{
  if(x > 0)
    return 1;
  else
    return -1;
}

/*=====================================================
函数名称:	EnergyThreshCompte
函数功能:	能量门限计算
输入参数:	EnergyArray	一句话的能量序列
			FrameNumber 一句话的语音帧数
输出参数:	EnergyTh	一句话的能量门限
====================================================*/
void	EnergyThreshCompte(float *EnergyArray, short FrameNumber, float &EnergyTh)
{
	float EnergyOneSentence	= 0;
	float EnergyFront		= 0;
	float EnergyEnd			= 0;

	static short first = 1;
//	short first = 1;
	
	//前2帧的能量进行平均
	//如果相邻2帧的能量差异太大, 则取最小值
	if(fabs(EnergyArray[0] - EnergyArray[1]) < 1.0 )
		EnergyFront = (EnergyArray[0] + EnergyArray[1]) / 2;
	else
	{
		if(EnergyArray[0] < EnergyArray[1])
			EnergyFront = EnergyArray[0];
		else
			EnergyFront = EnergyArray[1];
	}
	
	//后2帧的能量进行平均
	if(fabs(EnergyArray[FrameNumber-2] - EnergyArray[FrameNumber-1]) < 1.0)
		EnergyEnd = (EnergyArray[FrameNumber-2] + EnergyArray[FrameNumber-1]) / 2 ;
	else
	{
		if(EnergyArray[FrameNumber-2] < EnergyArray[FrameNumber-1])
			EnergyEnd = EnergyArray[FrameNumber-2];
		else
			EnergyEnd = EnergyArray[FrameNumber-1];
	}

	//前面的能量和后面的能量进行平均
	if(fabs(EnergyFront - EnergyEnd) < 2.0)
		EnergyOneSentence = (EnergyFront + EnergyEnd) / 2;
	else
	{
		if(EnergyFront < EnergyEnd)
			EnergyOneSentence = EnergyFront;
		else
			EnergyOneSentence = EnergyEnd;
	}

	if(first == 1)
	{
		EnergyTh = EnergyOneSentence ;
		first = 0;
	}
	else
		EnergyTh =(float)( ADAPTIVE_FACTOR * EnergyTh + (1-ADAPTIVE_FACTOR) * EnergyOneSentence);

}

/*=====================================================
函数名称:	EnergyCompute
函数功能:	计算一句话的语音能量, 过零率
输入参数:	tmpVoiceHead			一句话的原始语音
			FrameNumber				一句话中的语音帧数
			DcLevelOneSentence		一句话的直流电平
输出参数:	EnergyArray				该帧语音的能量
			nZeroPassArray			该句话的过零率
说明:		
			常数:			FRAME_LEN
=====================================================*/
void	EnergyCompute(short *tmpVoiceHead, float *EnergyArray, short *nZeroPassArray, short FrameNumber, float DcLevelOneSentence)
{
	short wFrameCount, wSampleCount;
	float fOneFrameData[FRAME_LEN];
	
	float tmpNoise, fTmp, NoiseLevelOneSentence;
	float NoiseFront	= 0;
	float NoiseEnd		= 0;
	float tmpPointLevel[FRAME_LEN];
	float *pNoise;
	static short first = 1;
	static float NoiseLevelAll;


	//计算能量
	for(wFrameCount=0; wFrameCount<FrameNumber; wFrameCount++)
	{
		EnergyArray[wFrameCount] = 0.0 ;
		for(wSampleCount=0; wSampleCount<FRAME_LEN; wSampleCount++)
		{
			fOneFrameData[wSampleCount] = tmpVoiceHead[wSampleCount] - DcLevelOneSentence;
			EnergyArray[wFrameCount] += fOneFrameData[wSampleCount] * fOneFrameData[wSampleCount];
		}
	
		//对能量取对数
		if(EnergyArray[wFrameCount] > 1)
			EnergyArray[wFrameCount] = (float)log(EnergyArray[wFrameCount]);
		else
			EnergyArray[wFrameCount] = 0;
	
		/*------------------------------------------------------->*/
		//				过零率的计算
		//对噪声电平进行自适应
		if((wFrameCount ==0 ) || (wFrameCount==1) || (wFrameCount==FrameNumber-2) || (wFrameCount==FrameNumber-1))
		{
			//将所有点电平的绝对值取和
			tmpNoise = 0;
			for(wSampleCount=0; wSampleCount<FRAME_LEN; wSampleCount++)
				tmpNoise += (float)fabs(fOneFrameData[wSampleCount]);
			tmpNoise /= FRAME_LEN;
			if((wFrameCount == 0) || (wFrameCount == FrameNumber -2))
				NoiseLevelOneSentence = tmpNoise;
			else
			{
				//一句话的噪声电平和噪声能量都是采用前两帧的平均
				if(wFrameCount == 1)
					pNoise = &NoiseFront;
				else
					pNoise = &NoiseEnd;
				fTmp = tmpNoise / NoiseLevelOneSentence;
				if((fTmp<2) && (fTmp>0.5))
					*pNoise = (NoiseLevelOneSentence + tmpNoise) / 2;
				else if(fTmp > 2)
					*pNoise = NoiseLevelOneSentence;
				else
					*pNoise = tmpNoise;
				if(wFrameCount == 1)
				{
					if(first == 1)
						NoiseLevelAll = *pNoise;
				}
				else
				{
					fTmp = NoiseFront / NoiseEnd;
					if((fTmp<2) && (fTmp>0.5))
						NoiseLevelOneSentence = (NoiseFront + NoiseEnd) / 2;
					else if(fTmp > 2)
						NoiseLevelOneSentence = NoiseEnd;
					else
						NoiseLevelOneSentence = NoiseFront;
					//如果是第1句话, 则直接采用这句话的噪声电平和噪声能量
					if(first == 1)
					{
						NoiseLevelAll = NoiseLevelOneSentence;
						first = 0;
					}
					//如果不是, 则采用以前的噪声电平和噪声能量的加权值作为噪声电平和噪声能量
					else
						NoiseLevelAll =(float)( ADAPTIVE_FACTOR * NoiseLevelAll + (1-ADAPTIVE_FACTOR) * NoiseLevelOneSentence);
				}
			}
		}	
		
		//对样点进行滤波, 如果信号的电平小于噪声电平, 则将信号的幅度取为0
		for(wSampleCount=0; wSampleCount<FRAME_LEN; wSampleCount++)
		{
			// 如果信号大于0, 则减去噪声的门限电平, 如果它小于0, 则认为是噪声, 让它取0,
			if(sign(fOneFrameData[wSampleCount]) == 1)
			{
				tmpPointLevel[wSampleCount] = fOneFrameData[wSampleCount] - ZEROPASS_NOISE_FACT * NoiseLevelAll;
				if(sign(tmpPointLevel[wSampleCount]) == -1)
					tmpPointLevel[wSampleCount] = 0;
			}
			//如果信号小于0, 则加上噪声的门限电平, 如果它大于0, 则认为是噪声, 让它取0,
			else
			{
				tmpPointLevel[wSampleCount] = fOneFrameData[wSampleCount] + ZEROPASS_NOISE_FACT * NoiseLevelAll;
				if(sign(tmpPointLevel[wSampleCount]) == 1)
					tmpPointLevel[wSampleCount] = 0;
			}
		}

		nZeroPassArray[wFrameCount] = 0;
		for(wSampleCount=0; wSampleCount<FRAME_LEN-1; wSampleCount++)
			nZeroPassArray[wFrameCount] += (int) fabs(sign(tmpPointLevel[wSampleCount +1]) - sign(tmpPointLevel[wSampleCount]));
		nZeroPassArray[wFrameCount] /= 2;

		//tmpVoiceHead指向下一帧的起始处
		tmpVoiceHead	+= FRAME_STEP;
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -