/** @function ******************************************************************************** <PRE> 函数名: JudgeTrainFrame2() 功能: 判断预增强后的数据是否可以作为训练帧(去除静寂语音的多段连接起来) 用法: 参数: [IN] pDiffVoice: 增强(差分)后的语音数据 [IN] iSampleNum: 语音样本数 [IN] train_frame_num: 训练帧帧数 返回: 非空: 可以作为训练帧的信号首地址 NULL: 不可作为训练帧 调用: HalfFrameEnergy() 主调函数: voiceToMFCC() 备注: 返回的内存需要用户在voiceToMFCC()中自行释放 </PRE> *******************************************************************************/ static double * JudgeTrainFrame2(double * pDiffVoice, int iSampleNum, int train_frame_num) { int len = 0; int iNum; // 合格的语音帧数 int iFrame; // 帧序号 int iFrameNum = (iSampleNum>>7) - 1; // 帧总数=2*(样本数/256)-1 double PriorHalfFrame = 0; // 前半帧能量(前128B) double NextHalfFrame = 0; // 后半帧能量(后128B) double FrameEnergy = 0; // 一帧的累积能量 double * pTranDiff = NULL; // 合格语音 double * pSave; // 合格语音存储地址 double * pDiffHead = pDiffVoice; double * pDiffNext = pDiffVoice; if (iFrameNum < train_frame_num) { return NULL; } pTranDiff = (double *)calloc((train_frame_num/2 + 1) * FRAME_LEN, sizeof(double)); if (!pTranDiff) { return NULL; } pSave = pTranDiff; PriorHalfFrame = HalfFrameEnergy(pDiffHead); for (iFrame=1, iNum=0; iFrame<iFrameNum && iNum<train_frame_num; ++iFrame) { pDiffNext += (FRAME_LEN/2); // 指向iFrame号帧的后半帧 NextHalfFrame = HalfFrameEnergy(pDiffNext); FrameEnergy = PriorHalfFrame + NextHalfFrame; if (FrameEnergy < SILENCE_VALUE) // 是静寂语音 { if (iFrameNum-iFrame < train_frame_num-iNum) // 剩下的帧不足以作为训练帧 { free(pTranDiff); return NULL; } len = (int)(pDiffNext - pDiffHead - FRAME_LEN/2); if (len > 0) { memcpy(pSave, pDiffHead, len * sizeof(double)); pSave += len; } pDiffNext += FRAME_LEN/2; // 重新定位可用作训练的帧 pDiffHead= pDiffNext; NextHalfFrame = HalfFrameEnergy(pDiffHead); ++iFrame; } else { ++iNum; } PriorHalfFrame = NextHalfFrame; } // end: for(;;) len = (int)(pDiffNext - pDiffHead + FRAME_LEN/2); if (len > 0) { memcpy(pSave, pDiffHead, len * sizeof(double)); } return pTranDiff; }
/** @function ******************************************************************************** <PRE> 函数名: JudgeTrainFrame2() 功能: 判断预增强后的数据是否可以作为训练帧(去除静寂语音的多段连接起来) 用法: 参数: [IN] pDiffVoice: 增强(差分)后的语音数据 [IN] iSampleNum: 语音样本数 返回: 非空: 可以作为训练帧的信号首地址 NULL: 不可作为训练帧 调用: HalfFrameEnergy() 主调函数: voiceToMFCC() 备注: 返回的内存需要用户在voiceToMFCC()中自行释放 </PRE> *******************************************************************************/ static double * JudgeTrainFrame2(double * pDiffVoice, int iSampleNum) { int len = 0; int iNum; //合格的语音帧数 int iFrame; //帧序号 int iFrameNum = (iSampleNum>>7) - 1; //帧总数=2*(样本数/256)-1 double PrHalfFrame = 0; //前半帧能量(前128B) double NextHalfFrame = 0; //后半帧能量(后128B) double FrameEnergy = 0; //一帧的累积能量 double * pTranDiff = NULL; //合格语音 double * pSave; //合格语音存储地址 double * pDiffHead = pDiffVoice; double * pDiffNext = pDiffVoice; pTranDiff = (double *)calloc((GOOD_FRAME_NUM / 2 + 1)*FRAME_LEN, sizeof(double)); if (!pTranDiff) { return NULL; } //pTranDiff = (double *)malloc((GOOD_FRAME_NUM/2 + 1)*sizeof(double)); pSave = pTranDiff; PrHalfFrame = HalfFrameEnergy(pDiffHead); for (iFrame=1,iNum=0; iFrame<iFrameNum && iNum<GOOD_FRAME_NUM; ++iFrame) { // 指针的加减法是按步长来算 pDiffNext += FRAME_LEN / 2; // 指针后移128 NextHalfFrame = HalfFrameEnergy(pDiffNext); FrameEnergy = PrHalfFrame + NextHalfFrame; if (FrameEnergy < SILENCE_VALUE) // 是静寂语音 { if (iFrameNum-iFrame < GOOD_FRAME_NUM-iNum) // 剩下的帧不足以作为训练帧 { free(pTranDiff); return NULL; } len = pDiffNext - pDiffHead - FRAME_LEN / 2; if (len > 0) { memcpy(pSave, pDiffHead, len * sizeof(double)); pSave += len; } pDiffHead = pDiffNext + FRAME_LEN / 2; // 重新定位可用作训练的帧 pDiffNext = pDiffHead; NextHalfFrame = HalfFrameEnergy(pDiffHead); } else { ++iNum; } PrHalfFrame = NextHalfFrame; } len = pDiffNext - pDiffHead + FRAME_LEN / 2; if (len > 0) { //TODO 把分配的内存损坏了 memcpy(pSave, pDiffHead, len * sizeof(double)); } return pTranDiff; }