void WebRtcIlbcfix_CreateAugmentedVec( size_t index, /* (i) Index for the augmented vector to be created */ const int16_t* buffer, /* (i) Pointer to the end of the codebook memory that is used for creation of the augmented codebook */ int16_t* cbVec) { /* (o) The constructed codebook vector */ size_t ilow; const int16_t *ppo, *ppi; int16_t cbVecTmp[4]; /* Interpolation starts 4 elements before cbVec+index, but must not start outside |cbVec|; clamping interp_len to stay within |cbVec|. */ size_t interp_len = WEBRTC_SPL_MIN(index, 4); ilow = index - interp_len; /* copy the first noninterpolated part */ ppo = buffer-index; WEBRTC_SPL_MEMCPY_W16(cbVec, ppo, index); /* interpolation */ ppo = buffer - interp_len; ppi = buffer - index - interp_len; /* perform cbVec[ilow+k] = ((ppi[k]*alphaTbl[k])>>15) + ((ppo[k]*alphaTbl[interp_len-1-k])>>15); for k = 0..interp_len-1 */ WebRtcSpl_ElementwiseVectorMult(&cbVec[ilow], ppi, WebRtcIlbcfix_kAlpha, interp_len, 15); WebRtcSpl_ReverseOrderMultArrayElements( cbVecTmp, ppo, &WebRtcIlbcfix_kAlpha[interp_len - 1], interp_len, 15); WebRtcSpl_AddVectorsAndShift(&cbVec[ilow], &cbVec[ilow], cbVecTmp, interp_len, 0); /* copy the second noninterpolated part */ ppo = buffer - index; /* |tempbuff2| is declared in WebRtcIlbcfix_GetCbVec and is SUBL+5 elements long. |buffer| points one element past the end of that vector, i.e., at tempbuff2+SUBL+5. Since ppo=buffer-index, we cannot read any more than |index| elements from |ppo|. |cbVec| is declared to be SUBL elements long in WebRtcIlbcfix_CbConstruct. Therefore, we can only write SUBL-index elements to cbVec+index. These two conditions limit the number of elements to copy. */ WEBRTC_SPL_MEMCPY_W16(cbVec+index, ppo, WEBRTC_SPL_MIN(SUBL-index, index)); }
// Maximum absolute value of word32 vector. C version for generic platforms. int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t* vector, size_t length) { // Use uint32_t for the local variables, to accommodate the return value // of abs(0x80000000), which is 0x80000000. uint32_t absolute = 0, maximum = 0; size_t i = 0; assert(length > 0); for (i = 0; i < length; i++) { absolute = abs((int)vector[i]); if (absolute > maximum) { maximum = absolute; } } maximum = WEBRTC_SPL_MIN(maximum, WEBRTC_SPL_WORD32_MAX); return (int32_t)maximum; }
// Maximum absolute value of word32 vector. int32_t WebRtcSpl_MaxAbsValueW32(const int32_t* vector, int length) { // Use uint32_t for the local variables, to accommodate the return value // of abs(0x80000000), which is 0x80000000. uint32_t absolute = 0, maximum = 0; int i = 0; if (vector == NULL || length <= 0) { return -1; } for (i = 0; i < length; i++) { absolute = abs((int)vector[i]); if (absolute > maximum) { maximum = absolute; } } maximum = WEBRTC_SPL_MIN(maximum, WEBRTC_SPL_WORD32_MAX); return (int32_t)maximum; }
void WebRtcIlbcfix_EncodeImpl( WebRtc_UWord16 *bytes, /* (o) encoded data bits iLBC */ const WebRtc_Word16 *block, /* (i) speech vector to encode */ iLBC_Enc_Inst_t *iLBCenc_inst /* (i/o) the general encoder state */ ){ int n, meml_gotten, Nfor, Nback; WebRtc_Word16 diff, start_pos; int index; int subcount, subframe; WebRtc_Word16 start_count, end_count; WebRtc_Word16 *residual; WebRtc_Word32 en1, en2; WebRtc_Word16 scale, max; WebRtc_Word16 *syntdenum; WebRtc_Word16 *decresidual; WebRtc_Word16 *reverseResidual; WebRtc_Word16 *reverseDecresidual; /* Stack based */ WebRtc_Word16 weightdenum[(LPC_FILTERORDER + 1)*NSUB_MAX]; WebRtc_Word16 dataVec[BLOCKL_MAX + LPC_FILTERORDER]; WebRtc_Word16 memVec[CB_MEML+CB_FILTERLEN]; WebRtc_Word16 bitsMemory[sizeof(iLBC_bits)/sizeof(WebRtc_Word16)]; iLBC_bits *iLBCbits_inst = (iLBC_bits*)bitsMemory; #ifdef SPLIT_10MS WebRtc_Word16 *weightdenumbuf = iLBCenc_inst->weightdenumbuf; WebRtc_Word16 last_bit; #endif WebRtc_Word16 *data = &dataVec[LPC_FILTERORDER]; WebRtc_Word16 *mem = &memVec[CB_HALFFILTERLEN]; /* Reuse som buffers to save stack memory */ residual = &iLBCenc_inst->lpc_buffer[LPC_LOOKBACK+BLOCKL_MAX-iLBCenc_inst->blockl]; syntdenum = mem; /* syntdenum[(LPC_FILTERORDER + 1)*NSUB_MAX] and mem are used non overlapping in the code */ decresidual = residual; /* Already encoded residual is overwritten by the decoded version */ reverseResidual = data; /* data and reverseResidual are used non overlapping in the code */ reverseDecresidual = reverseResidual; /* Already encoded residual is overwritten by the decoded version */ #ifdef SPLIT_10MS WebRtcSpl_MemSetW16 ( (WebRtc_Word16 *) iLBCbits_inst, 0, (WebRtc_Word16) (sizeof(iLBC_bits) / sizeof(WebRtc_Word16)) ); start_pos = iLBCenc_inst->start_pos; diff = iLBCenc_inst->diff; if (iLBCenc_inst->section != 0){ WEBRTC_SPL_MEMCPY_W16 (weightdenum, weightdenumbuf, SCRATCH_ENCODE_DATAVEC - SCRATCH_ENCODE_WEIGHTDENUM); /* Un-Packetize the frame into parameters */ last_bit = WebRtcIlbcfix_UnpackBits (iLBCenc_inst->bytes, iLBCbits_inst, iLBCenc_inst->mode); if (last_bit) return; /* adjust index */ WebRtcIlbcfix_IndexConvDec (iLBCbits_inst->cb_index); if (iLBCenc_inst->section == 1){ /* Save first 80 samples of a 160/240 sample frame for 20/30msec */ WEBRTC_SPL_MEMCPY_W16 (iLBCenc_inst->past_samples, block, 80); } else{ // iLBCenc_inst->section == 2 AND mode = 30ms /* Save second 80 samples of a 240 sample frame for 30msec */ WEBRTC_SPL_MEMCPY_W16 (iLBCenc_inst->past_samples + 80, block, 80); } } else{ // iLBCenc_inst->section == 0 /* form a complete frame of 160/240 for 20msec/30msec mode */ WEBRTC_SPL_MEMCPY_W16 (data + (iLBCenc_inst->mode * 8) - 80, block, 80); WEBRTC_SPL_MEMCPY_W16 (data, iLBCenc_inst->past_samples, (iLBCenc_inst->mode * 8) - 80); iLBCenc_inst->Nfor_flag = 0; iLBCenc_inst->Nback_flag = 0; #else /* copy input block to data*/ WEBRTC_SPL_MEMCPY_W16(data,block,iLBCenc_inst->blockl); #endif /* high pass filtering of input signal and scale down the residual (*0.5) */ WebRtcIlbcfix_HpInput(data, (WebRtc_Word16*)WebRtcIlbcfix_kHpInCoefs, iLBCenc_inst->hpimemy, iLBCenc_inst->hpimemx, iLBCenc_inst->blockl); /* LPC of hp filtered input data */ WebRtcIlbcfix_LpcEncode(syntdenum, weightdenum, iLBCbits_inst->lsf, data, iLBCenc_inst); /* Set up state */ WEBRTC_SPL_MEMCPY_W16(dataVec, iLBCenc_inst->anaMem, LPC_FILTERORDER); /* inverse filter to get residual */ for (n=0; n<iLBCenc_inst->nsub; n++ ) { WebRtcSpl_FilterMAFastQ12( &data[n*SUBL], &residual[n*SUBL], &syntdenum[n*(LPC_FILTERORDER+1)], LPC_FILTERORDER+1, SUBL); } /* Copy the state for next frame */ WEBRTC_SPL_MEMCPY_W16(iLBCenc_inst->anaMem, &data[iLBCenc_inst->blockl-LPC_FILTERORDER], LPC_FILTERORDER); /* find state location */ iLBCbits_inst->startIdx = WebRtcIlbcfix_FrameClassify(iLBCenc_inst,residual); /* check if state should be in first or last part of the two subframes */ index = (iLBCbits_inst->startIdx-1)*SUBL; max=WebRtcSpl_MaxAbsValueW16(&residual[index], 2*SUBL); scale=WebRtcSpl_GetSizeInBits(WEBRTC_SPL_MUL_16_16(max,max)); /* Scale to maximum 25 bits so that the MAC won't cause overflow */ scale = scale - 25; if(scale < 0) { scale = 0; } diff = STATE_LEN - iLBCenc_inst->state_short_len; en1=WebRtcSpl_DotProductWithScale(&residual[index], &residual[index], iLBCenc_inst->state_short_len, scale); index += diff; en2=WebRtcSpl_DotProductWithScale(&residual[index], &residual[index], iLBCenc_inst->state_short_len, scale); if (en1 > en2) { iLBCbits_inst->state_first = 1; start_pos = (iLBCbits_inst->startIdx-1)*SUBL; } else { iLBCbits_inst->state_first = 0; start_pos = (iLBCbits_inst->startIdx-1)*SUBL + diff; } /* scalar quantization of state */ WebRtcIlbcfix_StateSearch(iLBCenc_inst, iLBCbits_inst, &residual[start_pos], &syntdenum[(iLBCbits_inst->startIdx-1)*(LPC_FILTERORDER+1)], &weightdenum[(iLBCbits_inst->startIdx-1)*(LPC_FILTERORDER+1)]); WebRtcIlbcfix_StateConstruct(iLBCbits_inst->idxForMax, iLBCbits_inst->idxVec, &syntdenum[(iLBCbits_inst->startIdx-1)*(LPC_FILTERORDER+1)], &decresidual[start_pos], iLBCenc_inst->state_short_len ); /* predictive quantization in state */ if (iLBCbits_inst->state_first) { /* put adaptive part in the end */ /* setup memory */ WebRtcSpl_MemSetW16(mem, 0, (WebRtc_Word16)(CB_MEML-iLBCenc_inst->state_short_len)); WEBRTC_SPL_MEMCPY_W16(mem+CB_MEML-iLBCenc_inst->state_short_len, decresidual+start_pos, iLBCenc_inst->state_short_len); /* encode subframes */ WebRtcIlbcfix_CbSearch(iLBCenc_inst, iLBCbits_inst->cb_index, iLBCbits_inst->gain_index, &residual[start_pos+iLBCenc_inst->state_short_len], mem+CB_MEML-ST_MEM_L_TBL, ST_MEM_L_TBL, diff, &weightdenum[iLBCbits_inst->startIdx*(LPC_FILTERORDER+1)], 0); /* construct decoded vector */ WebRtcIlbcfix_CbConstruct(&decresidual[start_pos+iLBCenc_inst->state_short_len], iLBCbits_inst->cb_index, iLBCbits_inst->gain_index, mem+CB_MEML-ST_MEM_L_TBL, ST_MEM_L_TBL, diff ); } else { /* put adaptive part in the beginning */ /* create reversed vectors for prediction */ WebRtcSpl_MemCpyReversedOrder(&reverseResidual[diff-1], &residual[(iLBCbits_inst->startIdx+1)*SUBL-STATE_LEN], diff); /* setup memory */ meml_gotten = iLBCenc_inst->state_short_len; WebRtcSpl_MemCpyReversedOrder(&mem[CB_MEML-1], &decresidual[start_pos], meml_gotten); WebRtcSpl_MemSetW16(mem, 0, (WebRtc_Word16)(CB_MEML-iLBCenc_inst->state_short_len)); /* encode subframes */ WebRtcIlbcfix_CbSearch(iLBCenc_inst, iLBCbits_inst->cb_index, iLBCbits_inst->gain_index, reverseResidual, mem+CB_MEML-ST_MEM_L_TBL, ST_MEM_L_TBL, diff, &weightdenum[(iLBCbits_inst->startIdx-1)*(LPC_FILTERORDER+1)], 0); /* construct decoded vector */ WebRtcIlbcfix_CbConstruct(reverseDecresidual, iLBCbits_inst->cb_index, iLBCbits_inst->gain_index, mem+CB_MEML-ST_MEM_L_TBL, ST_MEM_L_TBL, diff ); /* get decoded residual from reversed vector */ WebRtcSpl_MemCpyReversedOrder(&decresidual[start_pos-1], reverseDecresidual, diff); } #ifdef SPLIT_10MS iLBCenc_inst->start_pos = start_pos; iLBCenc_inst->diff = diff; iLBCenc_inst->section++; /* adjust index */ WebRtcIlbcfix_IndexConvEnc (iLBCbits_inst->cb_index); /* Packetize the parameters into the frame */ WebRtcIlbcfix_PackBits (iLBCenc_inst->bytes, iLBCbits_inst, iLBCenc_inst->mode); WEBRTC_SPL_MEMCPY_W16 (weightdenumbuf, weightdenum, SCRATCH_ENCODE_DATAVEC - SCRATCH_ENCODE_WEIGHTDENUM); return; } #endif /* forward prediction of subframes */ Nfor = iLBCenc_inst->nsub-iLBCbits_inst->startIdx-1; /* counter for predicted subframes */ #ifdef SPLIT_10MS if (iLBCenc_inst->mode == 20) { subcount = 1; } if (iLBCenc_inst->mode == 30) { if (iLBCenc_inst->section == 1) { subcount = 1; } if (iLBCenc_inst->section == 2) { subcount = 3; } } #else subcount=1; #endif if( Nfor > 0 ){ /* setup memory */ WebRtcSpl_MemSetW16(mem, 0, CB_MEML-STATE_LEN); WEBRTC_SPL_MEMCPY_W16(mem+CB_MEML-STATE_LEN, decresidual+(iLBCbits_inst->startIdx-1)*SUBL, STATE_LEN); #ifdef SPLIT_10MS if (iLBCenc_inst->Nfor_flag > 0) { for (subframe = 0; subframe < WEBRTC_SPL_MIN (Nfor, 2); subframe++) { /* update memory */ WEBRTC_SPL_MEMCPY_W16 (mem, mem + SUBL, (CB_MEML - SUBL)); WEBRTC_SPL_MEMCPY_W16 (mem + CB_MEML - SUBL, &decresidual[(iLBCbits_inst->startIdx + 1 + subframe) * SUBL], SUBL); } } iLBCenc_inst->Nfor_flag++; if (iLBCenc_inst->mode == 20) { start_count = 0; end_count = Nfor; } if (iLBCenc_inst->mode == 30) { if (iLBCenc_inst->section == 1) { start_count = 0; end_count = WEBRTC_SPL_MIN (Nfor, 2); } if (iLBCenc_inst->section == 2) { start_count = WEBRTC_SPL_MIN (Nfor, 2); end_count = Nfor; } } #else start_count = 0; end_count = (WebRtc_Word16)Nfor; #endif /* loop over subframes to encode */ for (subframe = start_count; subframe < end_count; subframe++){ /* encode subframe */ WebRtcIlbcfix_CbSearch(iLBCenc_inst, iLBCbits_inst->cb_index+subcount*CB_NSTAGES, iLBCbits_inst->gain_index+subcount*CB_NSTAGES, &residual[(iLBCbits_inst->startIdx+1+subframe)*SUBL], mem, MEM_LF_TBL, SUBL, &weightdenum[(iLBCbits_inst->startIdx+1+subframe)*(LPC_FILTERORDER+1)], (WebRtc_Word16)subcount); /* construct decoded vector */ WebRtcIlbcfix_CbConstruct(&decresidual[(iLBCbits_inst->startIdx+1+subframe)*SUBL], iLBCbits_inst->cb_index+subcount*CB_NSTAGES, iLBCbits_inst->gain_index+subcount*CB_NSTAGES, mem, MEM_LF_TBL, SUBL ); /* update memory */ WEBRTC_SPL_MEMMOVE_W16(mem, mem+SUBL, (CB_MEML-SUBL)); WEBRTC_SPL_MEMCPY_W16(mem+CB_MEML-SUBL, &decresidual[(iLBCbits_inst->startIdx+1+subframe)*SUBL], SUBL); subcount++; } } #ifdef SPLIT_10MS if ((iLBCenc_inst->section == 1) && (iLBCenc_inst->mode == 30) && (Nfor > 0) && (end_count == 2)) { iLBCenc_inst->section++; /* adjust index */ WebRtcIlbcfix_IndexConvEnc (iLBCbits_inst->cb_index); /* Packetize the parameters into the frame */ WebRtcIlbcfix_PackBits (iLBCenc_inst->bytes, iLBCbits_inst, iLBCenc_inst->mode); WEBRTC_SPL_MEMCPY_W16 (weightdenumbuf, weightdenum, SCRATCH_ENCODE_DATAVEC - SCRATCH_ENCODE_WEIGHTDENUM); return; } #endif /* backward prediction of subframes */ Nback = iLBCbits_inst->startIdx-1; if( Nback > 0 ){ /* create reverse order vectors (The decresidual does not need to be copied since it is contained in the same vector as the residual) */ WebRtcSpl_MemCpyReversedOrder(&reverseResidual[Nback*SUBL-1], residual, Nback*SUBL); /* setup memory */ meml_gotten = SUBL*(iLBCenc_inst->nsub+1-iLBCbits_inst->startIdx); if( meml_gotten > CB_MEML ) { meml_gotten=CB_MEML; } WebRtcSpl_MemCpyReversedOrder(&mem[CB_MEML-1], &decresidual[Nback*SUBL], meml_gotten); WebRtcSpl_MemSetW16(mem, 0, (WebRtc_Word16)(CB_MEML-meml_gotten)); #ifdef SPLIT_10MS if (iLBCenc_inst->Nback_flag > 0) { for (subframe = 0; subframe < WEBRTC_SPL_MAX (2 - Nfor, 0); subframe++) { /* update memory */ WEBRTC_SPL_MEMCPY_W16 (mem, mem + SUBL, (CB_MEML - SUBL)); WEBRTC_SPL_MEMCPY_W16 (mem + CB_MEML - SUBL, &reverseDecresidual[subframe * SUBL], SUBL); } } iLBCenc_inst->Nback_flag++; if (iLBCenc_inst->mode == 20) { start_count = 0; end_count = Nback; } if (iLBCenc_inst->mode == 30) { if (iLBCenc_inst->section == 1) { start_count = 0; end_count = WEBRTC_SPL_MAX (2 - Nfor, 0); } if (iLBCenc_inst->section == 2) { start_count = WEBRTC_SPL_MAX (2 - Nfor, 0); end_count = Nback; } } #else start_count = 0; end_count = (WebRtc_Word16)Nback; #endif /* loop over subframes to encode */ for (subframe = start_count; subframe < end_count; subframe++){ /* encode subframe */ WebRtcIlbcfix_CbSearch(iLBCenc_inst, iLBCbits_inst->cb_index+subcount*CB_NSTAGES, iLBCbits_inst->gain_index+subcount*CB_NSTAGES, &reverseResidual[subframe*SUBL], mem, MEM_LF_TBL, SUBL, &weightdenum[(iLBCbits_inst->startIdx-2-subframe)*(LPC_FILTERORDER+1)], (WebRtc_Word16)subcount); /* construct decoded vector */ WebRtcIlbcfix_CbConstruct(&reverseDecresidual[subframe*SUBL], iLBCbits_inst->cb_index+subcount*CB_NSTAGES, iLBCbits_inst->gain_index+subcount*CB_NSTAGES, mem, MEM_LF_TBL, SUBL ); /* update memory */ WEBRTC_SPL_MEMMOVE_W16(mem, mem+SUBL, (CB_MEML-SUBL)); WEBRTC_SPL_MEMCPY_W16(mem+CB_MEML-SUBL, &reverseDecresidual[subframe*SUBL], SUBL); subcount++; } /* get decoded residual from reversed vector */ WebRtcSpl_MemCpyReversedOrder(&decresidual[SUBL*Nback-1], reverseDecresidual, SUBL*Nback); } /* end encoding part */ /* adjust index */ WebRtcIlbcfix_IndexConvEnc(iLBCbits_inst->cb_index); /* Packetize the parameters into the frame */ #ifdef SPLIT_10MS if( (iLBCenc_inst->mode==30) && (iLBCenc_inst->section==1) ){ WebRtcIlbcfix_PackBits(iLBCenc_inst->bytes, iLBCbits_inst, iLBCenc_inst->mode); } else{ WebRtcIlbcfix_PackBits(bytes, iLBCbits_inst, iLBCenc_inst->mode); } #else WebRtcIlbcfix_PackBits(bytes, iLBCbits_inst, iLBCenc_inst->mode); #endif #ifndef WEBRTC_BIG_ENDIAN /* Swap bytes for LITTLE ENDIAN since the packbits() function assumes BIG_ENDIAN machine */ #ifdef SPLIT_10MS if (( (iLBCenc_inst->section == 1) && (iLBCenc_inst->mode == 20) ) || ( (iLBCenc_inst->section == 2) && (iLBCenc_inst->mode == 30) )){ WebRtcIlbcfix_SwapBytes(bytes, iLBCenc_inst->no_of_words, bytes); } #else WebRtcIlbcfix_SwapBytes(bytes, iLBCenc_inst->no_of_words, bytes); #endif #endif #ifdef SPLIT_10MS if (subcount == (iLBCenc_inst->nsub - 1)) { iLBCenc_inst->section = 0; } else { iLBCenc_inst->section++; WEBRTC_SPL_MEMCPY_W16 (weightdenumbuf, weightdenum, SCRATCH_ENCODE_DATAVEC - SCRATCH_ENCODE_WEIGHTDENUM); } #endif }
int WebRtcIlbcfix_XcorrCoef( WebRtc_Word16 *target, /* (i) first array */ WebRtc_Word16 *regressor, /* (i) second array */ WebRtc_Word16 subl, /* (i) dimension arrays */ WebRtc_Word16 searchLen, /* (i) the search lenght */ WebRtc_Word16 offset, /* (i) samples offset between arrays */ WebRtc_Word16 step /* (i) +1 or -1 */ ){ int k; WebRtc_Word16 maxlag; WebRtc_Word16 pos; WebRtc_Word16 max; WebRtc_Word16 crossCorrScale, Energyscale; WebRtc_Word16 crossCorrSqMod, crossCorrSqMod_Max; WebRtc_Word32 crossCorr, Energy; WebRtc_Word16 crossCorrmod, EnergyMod, EnergyMod_Max; WebRtc_Word16 *tp, *rp; WebRtc_Word16 *rp_beg, *rp_end; WebRtc_Word16 totscale, totscale_max; WebRtc_Word16 scalediff; WebRtc_Word32 newCrit, maxCrit; int shifts; /* Initializations, to make sure that the first one is selected */ crossCorrSqMod_Max=0; EnergyMod_Max=WEBRTC_SPL_WORD16_MAX; totscale_max=-500; maxlag=0; pos=0; /* Find scale value and start position */ if (step==1) { max=WebRtcSpl_MaxAbsValueW16(regressor, (WebRtc_Word16)(subl+searchLen-1)); rp_beg = regressor; rp_end = ®ressor[subl]; } else { /* step==-1 */ max=WebRtcSpl_MaxAbsValueW16(®ressor[-searchLen], (WebRtc_Word16)(subl+searchLen-1)); rp_beg = ®ressor[-1]; rp_end = ®ressor[subl-1]; } /* Introduce a scale factor on the Energy in WebRtc_Word32 in order to make sure that the calculation does not overflow */ if (max>5000) { shifts=2; } else { shifts=0; } /* Calculate the first energy, then do a +/- to get the other energies */ Energy=WebRtcSpl_DotProductWithScale(regressor, regressor, subl, shifts); for (k=0;k<searchLen;k++) { tp = target; rp = ®ressor[pos]; crossCorr=WebRtcSpl_DotProductWithScale(tp, rp, subl, shifts); if ((Energy>0)&&(crossCorr>0)) { /* Put cross correlation and energy on 16 bit word */ crossCorrScale=(WebRtc_Word16)WebRtcSpl_NormW32(crossCorr)-16; crossCorrmod=(WebRtc_Word16)WEBRTC_SPL_SHIFT_W32(crossCorr, crossCorrScale); Energyscale=(WebRtc_Word16)WebRtcSpl_NormW32(Energy)-16; EnergyMod=(WebRtc_Word16)WEBRTC_SPL_SHIFT_W32(Energy, Energyscale); /* Square cross correlation and store upper WebRtc_Word16 */ crossCorrSqMod=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(crossCorrmod, crossCorrmod, 16); /* Calculate the total number of (dynamic) right shifts that have been performed on (crossCorr*crossCorr)/energy */ totscale=Energyscale-(crossCorrScale<<1); /* Calculate the shift difference in order to be able to compare the two (crossCorr*crossCorr)/energy in the same domain */ scalediff=totscale-totscale_max; scalediff=WEBRTC_SPL_MIN(scalediff,31); scalediff=WEBRTC_SPL_MAX(scalediff,-31); /* Compute the cross multiplication between the old best criteria and the new one to be able to compare them without using a division */ if (scalediff<0) { newCrit = ((WebRtc_Word32)crossCorrSqMod*EnergyMod_Max)>>(-scalediff); maxCrit = ((WebRtc_Word32)crossCorrSqMod_Max*EnergyMod); } else {
static void NonLinearProcessing(aec_t *aec, int *ip, float *wfft, short *output, short *outputH) { float efw[2][PART_LEN1], dfw[2][PART_LEN1]; complex_t xfw[PART_LEN1]; complex_t comfortNoiseHband[PART_LEN1]; float fft[PART_LEN2]; float scale, dtmp; float nlpGainHband; int i, j, pos; // Coherence and non-linear filter float cohde[PART_LEN1], cohxd[PART_LEN1]; float hNlDeAvg, hNlXdAvg; float hNl[PART_LEN1]; float hNlPref[PREF_BAND_SIZE]; float hNlFb = 0, hNlFbLow = 0; const float prefBandQuant = 0.75f, prefBandQuantLow = 0.5f; const int prefBandSize = PREF_BAND_SIZE / aec->mult; const int minPrefBand = 4 / aec->mult; // Near and error power sums float sdSum = 0, seSum = 0; // Power estimate smoothing coefficients const float gCoh[2][2] = {{0.9f, 0.1f}, {0.93f, 0.07f}}; const float *ptrGCoh = gCoh[aec->mult - 1]; // Filter energey float wfEnMax = 0, wfEn = 0; const int delayEstInterval = 10 * aec->mult; aec->delayEstCtr++; if (aec->delayEstCtr == delayEstInterval) { aec->delayEstCtr = 0; } // initialize comfort noise for H band memset(comfortNoiseHband, 0, sizeof(comfortNoiseHband)); nlpGainHband = (float)0.0; dtmp = (float)0.0; // Measure energy in each filter partition to determine delay. // TODO: Spread by computing one partition per block? if (aec->delayEstCtr == 0) { wfEnMax = 0; aec->delayIdx = 0; for (i = 0; i < NR_PART; i++) { pos = i * PART_LEN1; wfEn = 0; for (j = 0; j < PART_LEN1; j++) { wfEn += aec->wfBuf[0][pos + j] * aec->wfBuf[0][pos + j] + aec->wfBuf[1][pos + j] * aec->wfBuf[1][pos + j]; } if (wfEn > wfEnMax) { wfEnMax = wfEn; aec->delayIdx = i; } } } // NLP // Windowed far fft for (i = 0; i < PART_LEN; i++) { fft[i] = aec->xBuf[i] * sqrtHanning[i]; fft[PART_LEN + i] = aec->xBuf[PART_LEN + i] * sqrtHanning[PART_LEN - i]; } aec_rdft_128(1, fft, ip, wfft); xfw[0][1] = 0; xfw[PART_LEN][1] = 0; xfw[0][0] = fft[0]; xfw[PART_LEN][0] = fft[1]; for (i = 1; i < PART_LEN; i++) { xfw[i][0] = fft[2 * i]; xfw[i][1] = fft[2 * i + 1]; } // Buffer far. memcpy(aec->xfwBuf, xfw, sizeof(xfw)); // Use delayed far. memcpy(xfw, aec->xfwBuf + aec->delayIdx * PART_LEN1, sizeof(xfw)); // Windowed near fft for (i = 0; i < PART_LEN; i++) { fft[i] = aec->dBuf[i] * sqrtHanning[i]; fft[PART_LEN + i] = aec->dBuf[PART_LEN + i] * sqrtHanning[PART_LEN - i]; } aec_rdft_128(1, fft, ip, wfft); dfw[1][0] = 0; dfw[1][PART_LEN] = 0; dfw[0][0] = fft[0]; dfw[0][PART_LEN] = fft[1]; for (i = 1; i < PART_LEN; i++) { dfw[0][i] = fft[2 * i]; dfw[1][i] = fft[2 * i + 1]; } // Windowed error fft for (i = 0; i < PART_LEN; i++) { fft[i] = aec->eBuf[i] * sqrtHanning[i]; fft[PART_LEN + i] = aec->eBuf[PART_LEN + i] * sqrtHanning[PART_LEN - i]; } aec_rdft_128(1, fft, ip, wfft); efw[1][0] = 0; efw[1][PART_LEN] = 0; efw[0][0] = fft[0]; efw[0][PART_LEN] = fft[1]; for (i = 1; i < PART_LEN; i++) { efw[0][i] = fft[2 * i]; efw[1][i] = fft[2 * i + 1]; } // Smoothed PSD for (i = 0; i < PART_LEN1; i++) { aec->sd[i] = ptrGCoh[0] * aec->sd[i] + ptrGCoh[1] * (dfw[0][i] * dfw[0][i] + dfw[1][i] * dfw[1][i]); aec->se[i] = ptrGCoh[0] * aec->se[i] + ptrGCoh[1] * (efw[0][i] * efw[0][i] + efw[1][i] * efw[1][i]); // We threshold here to protect against the ill-effects of a zero farend. // The threshold is not arbitrarily chosen, but balances protection and // adverse interaction with the algorithm's tuning. // TODO: investigate further why this is so sensitive. aec->sx[i] = ptrGCoh[0] * aec->sx[i] + ptrGCoh[1] * WEBRTC_SPL_MAX(xfw[i][0] * xfw[i][0] + xfw[i][1] * xfw[i][1], 15); aec->sde[i][0] = ptrGCoh[0] * aec->sde[i][0] + ptrGCoh[1] * (dfw[0][i] * efw[0][i] + dfw[1][i] * efw[1][i]); aec->sde[i][1] = ptrGCoh[0] * aec->sde[i][1] + ptrGCoh[1] * (dfw[0][i] * efw[1][i] - dfw[1][i] * efw[0][i]); aec->sxd[i][0] = ptrGCoh[0] * aec->sxd[i][0] + ptrGCoh[1] * (dfw[0][i] * xfw[i][0] + dfw[1][i] * xfw[i][1]); aec->sxd[i][1] = ptrGCoh[0] * aec->sxd[i][1] + ptrGCoh[1] * (dfw[0][i] * xfw[i][1] - dfw[1][i] * xfw[i][0]); sdSum += aec->sd[i]; seSum += aec->se[i]; } // Divergent filter safeguard. if (aec->divergeState == 0) { if (seSum > sdSum) { aec->divergeState = 1; } } else { if (seSum * 1.05f < sdSum) { aec->divergeState = 0; } } if (aec->divergeState == 1) { memcpy(efw, dfw, sizeof(efw)); } // Reset if error is significantly larger than nearend (13 dB). if (seSum > (19.95f * sdSum)) { memset(aec->wfBuf, 0, sizeof(aec->wfBuf)); } // Subband coherence for (i = 0; i < PART_LEN1; i++) { cohde[i] = (aec->sde[i][0] * aec->sde[i][0] + aec->sde[i][1] * aec->sde[i][1]) / (aec->sd[i] * aec->se[i] + 1e-10f); cohxd[i] = (aec->sxd[i][0] * aec->sxd[i][0] + aec->sxd[i][1] * aec->sxd[i][1]) / (aec->sx[i] * aec->sd[i] + 1e-10f); } hNlXdAvg = 0; for (i = minPrefBand; i < prefBandSize + minPrefBand; i++) { hNlXdAvg += cohxd[i]; } hNlXdAvg /= prefBandSize; hNlXdAvg = 1 - hNlXdAvg; hNlDeAvg = 0; for (i = minPrefBand; i < prefBandSize + minPrefBand; i++) { hNlDeAvg += cohde[i]; } hNlDeAvg /= prefBandSize; if (hNlXdAvg < 0.75f && hNlXdAvg < aec->hNlXdAvgMin) { aec->hNlXdAvgMin = hNlXdAvg; } if (hNlDeAvg > 0.98f && hNlXdAvg > 0.9f) { aec->stNearState = 1; } else if (hNlDeAvg < 0.95f || hNlXdAvg < 0.8f) { aec->stNearState = 0; } if (aec->hNlXdAvgMin == 1) { aec->echoState = 0; aec->overDrive = aec->minOverDrive; if (aec->stNearState == 1) { memcpy(hNl, cohde, sizeof(hNl)); hNlFb = hNlDeAvg; hNlFbLow = hNlDeAvg; } else { for (i = 0; i < PART_LEN1; i++) { hNl[i] = 1 - cohxd[i]; } hNlFb = hNlXdAvg; hNlFbLow = hNlXdAvg; } } else { if (aec->stNearState == 1) { aec->echoState = 0; memcpy(hNl, cohde, sizeof(hNl)); hNlFb = hNlDeAvg; hNlFbLow = hNlDeAvg; } else { aec->echoState = 1; for (i = 0; i < PART_LEN1; i++) { hNl[i] = WEBRTC_SPL_MIN(cohde[i], 1 - cohxd[i]); } // Select an order statistic from the preferred bands. // TODO: Using quicksort now, but a selection algorithm may be preferred. memcpy(hNlPref, &hNl[minPrefBand], sizeof(float) * prefBandSize); qsort(hNlPref, prefBandSize, sizeof(float), CmpFloat); hNlFb = hNlPref[(int)floor(prefBandQuant * (prefBandSize - 1))]; hNlFbLow = hNlPref[(int)floor(prefBandQuantLow * (prefBandSize - 1))]; } } // Track the local filter minimum to determine suppression overdrive. if (hNlFbLow < 0.6f && hNlFbLow < aec->hNlFbLocalMin) { aec->hNlFbLocalMin = hNlFbLow; aec->hNlFbMin = hNlFbLow; aec->hNlNewMin = 1; aec->hNlMinCtr = 0; } aec->hNlFbLocalMin = WEBRTC_SPL_MIN(aec->hNlFbLocalMin + 0.0008f / aec->mult, 1); aec->hNlXdAvgMin = WEBRTC_SPL_MIN(aec->hNlXdAvgMin + 0.0006f / aec->mult, 1); if (aec->hNlNewMin == 1) { aec->hNlMinCtr++; } if (aec->hNlMinCtr == 2) { aec->hNlNewMin = 0; aec->hNlMinCtr = 0; aec->overDrive = WEBRTC_SPL_MAX(aec->targetSupp / ((float)log(aec->hNlFbMin + 1e-10f) + 1e-10f), aec->minOverDrive); } // Smooth the overdrive. if (aec->overDrive < aec->overDriveSm) { aec->overDriveSm = 0.99f * aec->overDriveSm + 0.01f * aec->overDrive; } else { aec->overDriveSm = 0.9f * aec->overDriveSm + 0.1f * aec->overDrive; } WebRtcAec_OverdriveAndSuppress(aec, hNl, hNlFb, efw); #ifdef G167 if (aec->cnToggle) { ComfortNoise(aec, efw, comfortNoiseHband, aec->noisePow, hNl); } #else // Add comfort noise. ComfortNoise(aec, efw, comfortNoiseHband, aec->noisePow, hNl); #endif // Inverse error fft. fft[0] = efw[0][0]; fft[1] = efw[0][PART_LEN]; for (i = 1; i < PART_LEN; i++) { fft[2*i] = efw[0][i]; // Sign change required by Ooura fft. fft[2*i + 1] = -efw[1][i]; } aec_rdft_128(-1, fft, ip, wfft); // Overlap and add to obtain output. scale = 2.0f / PART_LEN2; for (i = 0; i < PART_LEN; i++) { fft[i] *= scale; // fft scaling fft[i] = fft[i]*sqrtHanning[i] + aec->outBuf[i]; // Saturation protection output[i] = (short)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, fft[i], WEBRTC_SPL_WORD16_MIN); fft[PART_LEN + i] *= scale; // fft scaling aec->outBuf[i] = fft[PART_LEN + i] * sqrtHanning[PART_LEN - i]; } // For H band if (aec->sampFreq == 32000) { // H band gain // average nlp over low band: average over second half of freq spectrum // (4->8khz) GetHighbandGain(hNl, &nlpGainHband); // Inverse comfort_noise if (flagHbandCn == 1) { fft[0] = comfortNoiseHband[0][0]; fft[1] = comfortNoiseHband[PART_LEN][0]; for (i = 1; i < PART_LEN; i++) { fft[2*i] = comfortNoiseHband[i][0]; fft[2*i + 1] = comfortNoiseHband[i][1]; } aec_rdft_128(-1, fft, ip, wfft); scale = 2.0f / PART_LEN2; } // compute gain factor for (i = 0; i < PART_LEN; i++) { dtmp = (float)aec->dBufH[i]; dtmp = (float)dtmp * nlpGainHband; // for variable gain // add some comfort noise where Hband is attenuated if (flagHbandCn == 1) { fft[i] *= scale; // fft scaling dtmp += cnScaleHband * fft[i]; } // Saturation protection outputH[i] = (short)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, dtmp, WEBRTC_SPL_WORD16_MIN); } } // Copy the current block to the old position. memcpy(aec->xBuf, aec->xBuf + PART_LEN, sizeof(float) * PART_LEN); memcpy(aec->dBuf, aec->dBuf + PART_LEN, sizeof(float) * PART_LEN); memcpy(aec->eBuf, aec->eBuf + PART_LEN, sizeof(float) * PART_LEN); // Copy the current block to the old position for H band if (aec->sampFreq == 32000) { memcpy(aec->dBufH, aec->dBufH + PART_LEN, sizeof(float) * PART_LEN); } memmove(aec->xfwBuf + PART_LEN1, aec->xfwBuf, sizeof(aec->xfwBuf) - sizeof(complex_t) * PART_LEN1); }
int32_t WebRtcAec_Process(void *aecInst, const int16_t *nearend, const int16_t *nearendH, int16_t *out, int16_t *outH, int16_t nrOfSamples, int16_t msInSndCardBuf, int32_t skew) { aecpc_t *aecpc = aecInst; int32_t retVal = 0; short i; short nBlocks10ms; short nFrames; // Limit resampling to doubling/halving of signal const float minSkewEst = -0.5f; const float maxSkewEst = 1.0f; if (aecpc == NULL) { return -1; } if (nearend == NULL) { aecpc->lastError = AEC_NULL_POINTER_ERROR; return -1; } if (out == NULL) { aecpc->lastError = AEC_NULL_POINTER_ERROR; return -1; } if (aecpc->initFlag != initCheck) { aecpc->lastError = AEC_UNINITIALIZED_ERROR; return -1; } // number of samples == 160 for SWB input if (nrOfSamples != 80 && nrOfSamples != 160) { aecpc->lastError = AEC_BAD_PARAMETER_ERROR; return -1; } // Check for valid pointers based on sampling rate if (aecpc->sampFreq == 32000 && nearendH == NULL) { aecpc->lastError = AEC_NULL_POINTER_ERROR; return -1; } if (msInSndCardBuf < 0) { msInSndCardBuf = 0; aecpc->lastError = AEC_BAD_PARAMETER_WARNING; retVal = -1; } else if (msInSndCardBuf > 500) { msInSndCardBuf = 500; aecpc->lastError = AEC_BAD_PARAMETER_WARNING; retVal = -1; } // TODO(andrew): we need to investigate if this +10 is really wanted. msInSndCardBuf += 10; aecpc->msInSndCardBuf = msInSndCardBuf; if (aecpc->skewMode == kAecTrue) { if (aecpc->skewFrCtr < 25) { aecpc->skewFrCtr++; } else { retVal = WebRtcAec_GetSkew(aecpc->resampler, skew, &aecpc->skew); if (retVal == -1) { aecpc->skew = 0; aecpc->lastError = AEC_BAD_PARAMETER_WARNING; } aecpc->skew /= aecpc->sampFactor*nrOfSamples; if (aecpc->skew < 1.0e-3 && aecpc->skew > -1.0e-3) { aecpc->resample = kAecFalse; } else { aecpc->resample = kAecTrue; } if (aecpc->skew < minSkewEst) { aecpc->skew = minSkewEst; } else if (aecpc->skew > maxSkewEst) { aecpc->skew = maxSkewEst; } #ifdef WEBRTC_AEC_DEBUG_DUMP (void)fwrite(&aecpc->skew, sizeof(aecpc->skew), 1, aecpc->skewFile); #endif } } nFrames = nrOfSamples / FRAME_LEN; nBlocks10ms = nFrames / aecpc->rate_factor; if (aecpc->ECstartup) { if (nearend != out) { // Only needed if they don't already point to the same place. memcpy(out, nearend, sizeof(short) * nrOfSamples); } // The AEC is in the start up mode // AEC is disabled until the system delay is OK // Mechanism to ensure that the system delay is reasonably stable. if (aecpc->checkBuffSize) { aecpc->checkBufSizeCtr++; // Before we fill up the far-end buffer we require the system delay // to be stable (+/-8 ms) compared to the first value. This // comparison is made during the following 6 consecutive 10 ms // blocks. If it seems to be stable then we start to fill up the // far-end buffer. if (aecpc->counter == 0) { aecpc->firstVal = aecpc->msInSndCardBuf; aecpc->sum = 0; } if (abs(aecpc->firstVal - aecpc->msInSndCardBuf) < WEBRTC_SPL_MAX(0.2 * aecpc->msInSndCardBuf, sampMsNb)) { aecpc->sum += aecpc->msInSndCardBuf; aecpc->counter++; } else { aecpc->counter = 0; } if (aecpc->counter * nBlocks10ms >= 6) { // The far-end buffer size is determined in partitions of // PART_LEN samples. Use 75% of the average value of the system // delay as buffer size to start with. aecpc->bufSizeStart = WEBRTC_SPL_MIN((3 * aecpc->sum * aecpc->rate_factor * 8) / (4 * aecpc->counter * PART_LEN), kMaxBufSizeStart); // Buffer size has now been determined. aecpc->checkBuffSize = 0; } if (aecpc->checkBufSizeCtr * nBlocks10ms > 50) { // For really bad systems, don't disable the echo canceller for // more than 0.5 sec. aecpc->bufSizeStart = WEBRTC_SPL_MIN((aecpc->msInSndCardBuf * aecpc->rate_factor * 3) / 40, kMaxBufSizeStart); aecpc->checkBuffSize = 0; } } // If |checkBuffSize| changed in the if-statement above. if (!aecpc->checkBuffSize) { // The system delay is now reasonably stable (or has been unstable // for too long). When the far-end buffer is filled with // approximately the same amount of data as reported by the system // we end the startup phase. int overhead_elements = WebRtcAec_system_delay(aecpc->aec) / PART_LEN - aecpc->bufSizeStart; if (overhead_elements == 0) { // Enable the AEC aecpc->ECstartup = 0; } else if (overhead_elements > 0) { // TODO(bjornv): Do we need a check on how much we actually // moved the read pointer? It should always be possible to move // the pointer |overhead_elements| since we have only added data // to the buffer and no delay compensation nor AEC processing // has been done. WebRtcAec_MoveFarReadPtr(aecpc->aec, overhead_elements); // Enable the AEC aecpc->ECstartup = 0; } } } else { // AEC is enabled. EstBufDelay(aecpc); // Note that 1 frame is supported for NB and 2 frames for WB. for (i = 0; i < nFrames; i++) { // Call the AEC. WebRtcAec_ProcessFrame(aecpc->aec, &nearend[FRAME_LEN * i], &nearendH[FRAME_LEN * i], aecpc->knownDelay, &out[FRAME_LEN * i], &outH[FRAME_LEN * i]); // TODO(bjornv): Re-structure such that we don't have to pass // |aecpc->knownDelay| as input. Change name to something like // |system_buffer_diff|. } } #ifdef WEBRTC_AEC_DEBUG_DUMP { int16_t far_buf_size_ms = (int16_t)(WebRtcAec_system_delay(aecpc->aec) / (sampMsNb * aecpc->rate_factor)); (void)fwrite(&far_buf_size_ms, 2, 1, aecpc->bufFile); (void)fwrite(&aecpc->knownDelay, sizeof(aecpc->knownDelay), 1, aecpc->delayFile); } #endif return retVal; }
void WebRtcIlbcfix_CbSearch( IlbcEncoder *iLBCenc_inst, /* (i) the encoder state structure */ int16_t *index, /* (o) Codebook indices */ int16_t *gain_index, /* (o) Gain quantization indices */ int16_t *intarget, /* (i) Target vector for encoding */ int16_t *decResidual,/* (i) Decoded residual for codebook construction */ int16_t lMem, /* (i) Length of buffer */ int16_t lTarget, /* (i) Length of vector */ int16_t *weightDenum,/* (i) weighting filter coefficients in Q12 */ int16_t block /* (i) the subblock number */ ) { int16_t i, j, stage, range; int16_t *pp, scale, tmp; int16_t bits, temp1, temp2; int16_t base_size; int32_t codedEner, targetEner; int16_t gains[CB_NSTAGES+1]; int16_t *cb_vecPtr; int16_t indexOffset, sInd, eInd; int32_t CritMax=0; int16_t shTotMax=WEBRTC_SPL_WORD16_MIN; int16_t bestIndex=0; int16_t bestGain=0; int16_t indexNew, CritNewSh; int32_t CritNew; int32_t *cDotPtr; int16_t noOfZeros; int16_t *gainPtr; int32_t t32, tmpW32; int16_t *WebRtcIlbcfix_kGainSq5_ptr; /* Stack based */ int16_t CBbuf[CB_MEML+LPC_FILTERORDER+CB_HALFFILTERLEN]; int32_t cDot[128]; int32_t Crit[128]; int16_t targetVec[SUBL+LPC_FILTERORDER]; int16_t cbvectors[CB_MEML + 1]; /* Adding one extra position for Coverity warnings. */ int16_t codedVec[SUBL]; int16_t interpSamples[20*4]; int16_t interpSamplesFilt[20*4]; int16_t energyW16[CB_EXPAND*128]; int16_t energyShifts[CB_EXPAND*128]; int16_t *inverseEnergy=energyW16; /* Reuse memory */ int16_t *inverseEnergyShifts=energyShifts; /* Reuse memory */ int16_t *buf = &CBbuf[LPC_FILTERORDER]; int16_t *target = &targetVec[LPC_FILTERORDER]; int16_t *aug_vec = (int16_t*)cDot; /* length [SUBL], reuse memory */ /* Determine size of codebook sections */ base_size=lMem-lTarget+1; if (lTarget==SUBL) { base_size=lMem-19; } /* weighting of the CB memory */ noOfZeros=lMem-WebRtcIlbcfix_kFilterRange[block]; WebRtcSpl_MemSetW16(&buf[-LPC_FILTERORDER], 0, noOfZeros+LPC_FILTERORDER); WebRtcSpl_FilterARFastQ12( decResidual+noOfZeros, buf+noOfZeros, weightDenum, LPC_FILTERORDER+1, WebRtcIlbcfix_kFilterRange[block]); /* weighting of the target vector */ WEBRTC_SPL_MEMCPY_W16(&target[-LPC_FILTERORDER], buf+noOfZeros+WebRtcIlbcfix_kFilterRange[block]-LPC_FILTERORDER, LPC_FILTERORDER); WebRtcSpl_FilterARFastQ12( intarget, target, weightDenum, LPC_FILTERORDER+1, lTarget); /* Store target, towards the end codedVec is calculated as the initial target minus the remaining target */ WEBRTC_SPL_MEMCPY_W16(codedVec, target, lTarget); /* Find the highest absolute value to calculate proper vector scale factor (so that it uses 12 bits) */ temp1 = WebRtcSpl_MaxAbsValueW16(buf, (int16_t)lMem); temp2 = WebRtcSpl_MaxAbsValueW16(target, (int16_t)lTarget); if ((temp1>0)&&(temp2>0)) { temp1 = WEBRTC_SPL_MAX(temp1, temp2); scale = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_MUL_16_16(temp1, temp1)); } else { /* temp1 or temp2 is negative (maximum was -32768) */ scale = 30; } /* Scale to so that a mul-add 40 times does not overflow */ scale = scale - 25; scale = WEBRTC_SPL_MAX(0, scale); /* Compute energy of the original target */ targetEner = WebRtcSpl_DotProductWithScale(target, target, lTarget, scale); /* Prepare search over one more codebook section. This section is created by filtering the original buffer with a filter. */ WebRtcIlbcfix_FilteredCbVecs(cbvectors, buf, lMem, WebRtcIlbcfix_kFilterRange[block]); range = WebRtcIlbcfix_kSearchRange[block][0]; if(lTarget == SUBL) { /* Create the interpolated samples and store them for use in all stages */ /* First section, non-filtered half of the cb */ WebRtcIlbcfix_InterpolateSamples(interpSamples, buf, lMem); /* Second section, filtered half of the cb */ WebRtcIlbcfix_InterpolateSamples(interpSamplesFilt, cbvectors, lMem); /* Compute the CB vectors' energies for the first cb section (non-filtered) */ WebRtcIlbcfix_CbMemEnergyAugmentation(interpSamples, buf, scale, 20, energyW16, energyShifts); /* Compute the CB vectors' energies for the second cb section (filtered cb) */ WebRtcIlbcfix_CbMemEnergyAugmentation(interpSamplesFilt, cbvectors, scale, (int16_t)(base_size+20), energyW16, energyShifts); /* Compute the CB vectors' energies and store them in the vector * energyW16. Also the corresponding shift values are stored. The * energy values are used in all three stages. */ WebRtcIlbcfix_CbMemEnergy(range, buf, cbvectors, lMem, lTarget, energyW16+20, energyShifts+20, scale, base_size); } else { /* Compute the CB vectors' energies and store them in the vector * energyW16. Also the corresponding shift values are stored. The * energy values are used in all three stages. */ WebRtcIlbcfix_CbMemEnergy(range, buf, cbvectors, lMem, lTarget, energyW16, energyShifts, scale, base_size); /* Set the energy positions 58-63 and 122-127 to zero (otherwise they are uninitialized) */ WebRtcSpl_MemSetW16(energyW16+range, 0, (base_size-range)); WebRtcSpl_MemSetW16(energyW16+range+base_size, 0, (base_size-range)); } /* Calculate Inverse Energy (energyW16 is already normalized and will contain the inverse energy in Q29 after this call */ WebRtcIlbcfix_EnergyInverse(energyW16, base_size*CB_EXPAND); /* The gain value computed in the previous stage is used * as an upper limit to what the next stage gain value * is allowed to be. In stage 0, 16384 (1.0 in Q14) is used as * the upper limit. */ gains[0] = 16384; for (stage=0; stage<CB_NSTAGES; stage++) { /* Set up memories */ range = WebRtcIlbcfix_kSearchRange[block][stage]; /* initialize search measures */ CritMax=0; shTotMax=-100; bestIndex=0; bestGain=0; /* loop over lags 40+ in the first codebook section, full search */ cb_vecPtr = buf+lMem-lTarget; /* Calculate all the cross correlations (augmented part of CB) */ if (lTarget==SUBL) { WebRtcIlbcfix_AugmentedCbCorr(target, buf+lMem, interpSamples, cDot, 20, 39, scale); cDotPtr=&cDot[20]; } else { cDotPtr=cDot; } /* Calculate all the cross correlations (main part of CB) */ WebRtcSpl_CrossCorrelation(cDotPtr, target, cb_vecPtr, lTarget, range, scale, -1); /* Adjust the search range for the augmented vectors */ if (lTarget==SUBL) { range=WebRtcIlbcfix_kSearchRange[block][stage]+20; } else { range=WebRtcIlbcfix_kSearchRange[block][stage]; } indexOffset=0; /* Search for best index in this part of the vector */ WebRtcIlbcfix_CbSearchCore( cDot, range, stage, inverseEnergy, inverseEnergyShifts, Crit, &indexNew, &CritNew, &CritNewSh); /* Update the global best index and the corresponding gain */ WebRtcIlbcfix_CbUpdateBestIndex( CritNew, CritNewSh, (int16_t)(indexNew+indexOffset), cDot[indexNew+indexOffset], inverseEnergy[indexNew+indexOffset], inverseEnergyShifts[indexNew+indexOffset], &CritMax, &shTotMax, &bestIndex, &bestGain); sInd=bestIndex-(int16_t)(CB_RESRANGE>>1); eInd=sInd+CB_RESRANGE; if (sInd<0) { eInd-=sInd; sInd=0; } if (eInd>=range) { eInd=range-1; sInd=eInd-CB_RESRANGE; } range = WebRtcIlbcfix_kSearchRange[block][stage]; if (lTarget==SUBL) { i=sInd; if (sInd<20) { WebRtcIlbcfix_AugmentedCbCorr(target, cbvectors+lMem, interpSamplesFilt, cDot, (int16_t)(sInd+20), (int16_t)(WEBRTC_SPL_MIN(39, (eInd+20))), scale); i=20; } cDotPtr=&cDot[WEBRTC_SPL_MAX(0,(20-sInd))]; cb_vecPtr = cbvectors+lMem-20-i; /* Calculate the cross correlations (main part of the filtered CB) */ WebRtcSpl_CrossCorrelation(cDotPtr, target, cb_vecPtr, lTarget, (int16_t)(eInd-i+1), scale, -1); } else { cDotPtr = cDot; cb_vecPtr = cbvectors+lMem-lTarget-sInd; /* Calculate the cross correlations (main part of the filtered CB) */ WebRtcSpl_CrossCorrelation(cDotPtr, target, cb_vecPtr, lTarget, (int16_t)(eInd-sInd+1), scale, -1); } /* Adjust the search range for the augmented vectors */ indexOffset=base_size+sInd; /* Search for best index in this part of the vector */ WebRtcIlbcfix_CbSearchCore( cDot, (int16_t)(eInd-sInd+1), stage, inverseEnergy+indexOffset, inverseEnergyShifts+indexOffset, Crit, &indexNew, &CritNew, &CritNewSh); /* Update the global best index and the corresponding gain */ WebRtcIlbcfix_CbUpdateBestIndex( CritNew, CritNewSh, (int16_t)(indexNew+indexOffset), cDot[indexNew], inverseEnergy[indexNew+indexOffset], inverseEnergyShifts[indexNew+indexOffset], &CritMax, &shTotMax, &bestIndex, &bestGain); index[stage] = bestIndex; bestGain = WebRtcIlbcfix_GainQuant(bestGain, (int16_t)WEBRTC_SPL_ABS_W16(gains[stage]), stage, &gain_index[stage]); /* Extract the best (according to measure) codebook vector Also adjust the index, so that the augmented vectors are last. Above these vectors were first... */ if(lTarget==(STATE_LEN-iLBCenc_inst->state_short_len)) { if(index[stage]<base_size) { pp=buf+lMem-lTarget-index[stage]; } else { pp=cbvectors+lMem-lTarget- index[stage]+base_size; } } else { if (index[stage]<base_size) { if (index[stage]>=20) { /* Adjust index and extract vector */ index[stage]-=20; pp=buf+lMem-lTarget-index[stage]; } else { /* Adjust index and extract vector */ index[stage]+=(base_size-20); WebRtcIlbcfix_CreateAugmentedVec((int16_t)(index[stage]-base_size+40), buf+lMem, aug_vec); pp = aug_vec; } } else { if ((index[stage] - base_size) >= 20) { /* Adjust index and extract vector */ index[stage]-=20; pp=cbvectors+lMem-lTarget- index[stage]+base_size; } else { /* Adjust index and extract vector */ index[stage]+=(base_size-20); WebRtcIlbcfix_CreateAugmentedVec((int16_t)(index[stage]-2*base_size+40), cbvectors+lMem, aug_vec); pp = aug_vec; } } } /* Subtract the best codebook vector, according to measure, from the target vector */ WebRtcSpl_AddAffineVectorToVector(target, pp, (int16_t)(-bestGain), (int32_t)8192, (int16_t)14, (int)lTarget); /* record quantized gain */ gains[stage+1] = bestGain; } /* end of Main Loop. for (stage=0;... */ /* Calculte the coded vector (original target - what's left) */ for (i=0;i<lTarget;i++) { codedVec[i]-=target[i]; } /* Gain adjustment for energy matching */ codedEner = WebRtcSpl_DotProductWithScale(codedVec, codedVec, lTarget, scale); j=gain_index[0]; temp1 = (int16_t)WebRtcSpl_NormW32(codedEner); temp2 = (int16_t)WebRtcSpl_NormW32(targetEner); if(temp1 < temp2) { bits = 16 - temp1; } else { bits = 16 - temp2; } tmp = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(gains[1],gains[1], 14); targetEner = WEBRTC_SPL_MUL_16_16( WEBRTC_SPL_SHIFT_W32(targetEner, -bits), tmp); tmpW32 = ((int32_t)(gains[1]-1))<<1; /* Pointer to the table that contains gain_sq5TblFIX * gain_sq5TblFIX in Q14 */ gainPtr=(int16_t*)WebRtcIlbcfix_kGainSq5Sq+gain_index[0]; temp1 = (int16_t)WEBRTC_SPL_SHIFT_W32(codedEner, -bits); WebRtcIlbcfix_kGainSq5_ptr = (int16_t*)&WebRtcIlbcfix_kGainSq5[j]; /* targetEner and codedEner are in Q(-2*scale) */ for (i=gain_index[0];i<32;i++) { /* Change the index if (codedEnergy*gainTbl[i]*gainTbl[i])<(targetEn*gain[0]*gain[0]) AND gainTbl[i] < 2*gain[0] */ t32 = WEBRTC_SPL_MUL_16_16(temp1, (*gainPtr)); t32 = t32 - targetEner; if (t32 < 0) { if ((*WebRtcIlbcfix_kGainSq5_ptr) < tmpW32) { j=i; WebRtcIlbcfix_kGainSq5_ptr = (int16_t*)&WebRtcIlbcfix_kGainSq5[i]; } } gainPtr++; } gain_index[0]=j; return; }
int WebRtcNetEQ_UpdateIatStatistics(AutomodeInst_t *inst, int maxBufLen, uint16_t seqNumber, uint32_t timeStamp, int32_t fsHz, int mdCodec, int streamingMode) { uint32_t timeIat; /* inter-arrival time */ int i; int32_t tempsum = 0; /* temp summation */ int32_t tempvar; /* temporary variable */ int retval = 0; /* return value */ int16_t packetLenSamp; /* packet speech length in samples */ /****************/ /* Sanity check */ /****************/ if (maxBufLen <= 1 || fsHz <= 0) { /* maxBufLen must be at least 2 and fsHz must both be strictly positive */ return -1; } /****************************/ /* Update packet statistics */ /****************************/ /* Try calculating packet length from current and previous timestamps */ if (!WebRtcNetEQ_IsNewerTimestamp(timeStamp, inst->lastTimeStamp) || !WebRtcNetEQ_IsNewerSequenceNumber(seqNumber, inst->lastSeqNo)) { /* Wrong timestamp or sequence order; revert to backup plan */ packetLenSamp = inst->packetSpeechLenSamp; /* use stored value */ } else { /* calculate timestamps per packet */ packetLenSamp = (int16_t) WebRtcSpl_DivU32U16(timeStamp - inst->lastTimeStamp, seqNumber - inst->lastSeqNo); } /* Check that the packet size is positive; if not, the statistics cannot be updated. */ if (inst->firstPacketReceived && packetLenSamp > 0) { /* packet size ok */ /* calculate inter-arrival time in integer packets (rounding down) */ timeIat = WebRtcSpl_DivW32W16(inst->packetIatCountSamp, packetLenSamp); /* Special operations for streaming mode */ if (streamingMode != 0) { /* * Calculate IAT in Q8, including fractions of a packet (i.e., more accurate * than timeIat). */ int16_t timeIatQ8 = (int16_t) WebRtcSpl_DivW32W16( WEBRTC_SPL_LSHIFT_W32(inst->packetIatCountSamp, 8), packetLenSamp); /* * Calculate cumulative sum iat with sequence number compensation (ideal arrival * times makes this sum zero). */ inst->cSumIatQ8 += (timeIatQ8 - WEBRTC_SPL_LSHIFT_W32(seqNumber - inst->lastSeqNo, 8)); /* subtract drift term */ inst->cSumIatQ8 -= CSUM_IAT_DRIFT; /* ensure not negative */ inst->cSumIatQ8 = WEBRTC_SPL_MAX(inst->cSumIatQ8, 0); /* remember max */ if (inst->cSumIatQ8 > inst->maxCSumIatQ8) { inst->maxCSumIatQ8 = inst->cSumIatQ8; inst->maxCSumUpdateTimer = 0; } /* too long since the last maximum was observed; decrease max value */ if (inst->maxCSumUpdateTimer > (uint32_t) WEBRTC_SPL_MUL_32_16(fsHz, MAX_STREAMING_PEAK_PERIOD)) { inst->maxCSumIatQ8 -= 4; /* remove 1000*4/256 = 15.6 ms/s */ } } /* end of streaming mode */ /* check for discontinuous packet sequence and re-ordering */ if (WebRtcNetEQ_IsNewerSequenceNumber(seqNumber, inst->lastSeqNo + 1)) { /* Compensate for gap in the sequence numbers. * Reduce IAT with expected extra time due to lost packets, but ensure that * the IAT is not negative. */ timeIat -= WEBRTC_SPL_MIN(timeIat, (uint16_t) (seqNumber - (uint16_t) (inst->lastSeqNo + 1))); } else if (!WebRtcNetEQ_IsNewerSequenceNumber(seqNumber, inst->lastSeqNo)) { /* compensate for re-ordering */ timeIat += (uint16_t) (inst->lastSeqNo + 1 - seqNumber); } /* saturate IAT at maximum value */ timeIat = WEBRTC_SPL_MIN( timeIat, MAX_IAT ); /* update iatProb = forgetting_factor * iatProb for all elements */ for (i = 0; i <= MAX_IAT; i++) { int32_t tempHi, tempLo; /* Temporary variables */ /* * Multiply iatProbFact (Q15) with iatProb (Q30) and right-shift 15 steps * to come back to Q30. The operation is done in two steps: */ /* * 1) Multiply the high 16 bits (15 bits + sign) of iatProb. Shift iatProb * 16 steps right to get the high 16 bits in a int16_t prior to * multiplication, and left-shift with 1 afterwards to come back to * Q30 = (Q15 * (Q30>>16)) << 1. */ tempHi = WEBRTC_SPL_MUL_16_16(inst->iatProbFact, (int16_t) WEBRTC_SPL_RSHIFT_W32(inst->iatProb[i], 16)); tempHi = WEBRTC_SPL_LSHIFT_W32(tempHi, 1); /* left-shift 1 step */ /* * 2) Isolate and multiply the low 16 bits of iatProb. Right-shift 15 steps * afterwards to come back to Q30 = (Q15 * Q30) >> 15. */ tempLo = inst->iatProb[i] & 0x0000FFFF; /* sift out the 16 low bits */ tempLo = WEBRTC_SPL_MUL_16_U16(inst->iatProbFact, (uint16_t) tempLo); tempLo = WEBRTC_SPL_RSHIFT_W32(tempLo, 15); /* Finally, add the high and low parts */ inst->iatProb[i] = tempHi + tempLo; /* Sum all vector elements while we are at it... */ tempsum += inst->iatProb[i]; } /* * Increase the probability for the currently observed inter-arrival time * with 1 - iatProbFact. The factor is in Q15, iatProb in Q30; * hence, left-shift 15 steps to obtain result in Q30. */ inst->iatProb[timeIat] += (32768 - inst->iatProbFact) << 15; tempsum += (32768 - inst->iatProbFact) << 15; /* add to vector sum */ /* * Update iatProbFact (changes only during the first seconds after reset) * The factor converges to IAT_PROB_FACT. */ inst->iatProbFact += (IAT_PROB_FACT - inst->iatProbFact + 3) >> 2; /* iatProb should sum up to 1 (in Q30). */ tempsum -= 1 << 30; /* should be zero */ /* Check if it does, correct if it doesn't. */ if (tempsum > 0) { /* tempsum too large => decrease a few values in the beginning */ i = 0; while (i <= MAX_IAT && tempsum > 0) { /* Remove iatProb[i] / 16 from iatProb, but not more than tempsum */ tempvar = WEBRTC_SPL_MIN(tempsum, inst->iatProb[i] >> 4); inst->iatProb[i++] -= tempvar; tempsum -= tempvar; } }
void WebRtcIlbcfix_CbSearchCore( int32_t *cDot, /* (i) Cross Correlation */ int16_t range, /* (i) Search range */ int16_t stage, /* (i) Stage of this search */ int16_t *inverseEnergy, /* (i) Inversed energy */ int16_t *inverseEnergyShift, /* (i) Shifts of inversed energy with the offset 2*16-29 */ int32_t *Crit, /* (o) The criteria */ int16_t *bestIndex, /* (o) Index that corresponds to maximum criteria (in this vector) */ int32_t *bestCrit, /* (o) Value of critera for the chosen index */ int16_t *bestCritSh) /* (o) The domain of the chosen criteria */ { int32_t maxW32, tmp32; int16_t max, sh, tmp16; int i; int32_t *cDotPtr; int16_t cDotSqW16; int16_t *inverseEnergyPtr; int32_t *critPtr; int16_t *inverseEnergyShiftPtr; /* Don't allow negative values for stage 0 */ if (stage==0) { cDotPtr=cDot; for (i=0;i<range;i++) { *cDotPtr=WEBRTC_SPL_MAX(0, (*cDotPtr)); cDotPtr++; } } /* Normalize cDot to int16_t, calculate the square of cDot and store the upper int16_t */ maxW32 = WebRtcSpl_MaxAbsValueW32(cDot, range); sh = (int16_t)WebRtcSpl_NormW32(maxW32); cDotPtr = cDot; inverseEnergyPtr = inverseEnergy; critPtr = Crit; inverseEnergyShiftPtr=inverseEnergyShift; max=WEBRTC_SPL_WORD16_MIN; for (i=0;i<range;i++) { /* Calculate cDot*cDot and put the result in a int16_t */ tmp32 = WEBRTC_SPL_LSHIFT_W32(*cDotPtr,sh); tmp16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32,16); cDotSqW16 = (int16_t)(((int32_t)(tmp16)*(tmp16))>>16); /* Calculate the criteria (cDot*cDot/energy) */ *critPtr=WEBRTC_SPL_MUL_16_16(cDotSqW16, (*inverseEnergyPtr)); /* Extract the maximum shift value under the constraint that the criteria is not zero */ if ((*critPtr)!=0) { max = WEBRTC_SPL_MAX((*inverseEnergyShiftPtr), max); } inverseEnergyPtr++; inverseEnergyShiftPtr++; critPtr++; cDotPtr++; } /* If no max shifts still at initialization value, set shift to zero */ if (max==WEBRTC_SPL_WORD16_MIN) { max = 0; } /* Modify the criterias, so that all of them use the same Q domain */ critPtr=Crit; inverseEnergyShiftPtr=inverseEnergyShift; for (i=0;i<range;i++) { /* Guarantee that the shift value is less than 16 in order to simplify for DSP's (and guard against >31) */ tmp16 = WEBRTC_SPL_MIN(16, max-(*inverseEnergyShiftPtr)); (*critPtr)=WEBRTC_SPL_SHIFT_W32((*critPtr),-tmp16); critPtr++; inverseEnergyShiftPtr++; } /* Find the index of the best value */ *bestIndex = WebRtcSpl_MaxIndexW32(Crit, range); *bestCrit = Crit[*bestIndex]; /* Calculate total shifts of this criteria */ *bestCritSh = 32 - 2*sh + max; return; }
// Compute speech/noise probability // speech/noise probability is returned in: probSpeechFinal //snrLocPrior is the prior SNR for each frequency (in Q11) //snrLocPost is the post SNR for each frequency (in Q11) void WebRtcNsx_SpeechNoiseProb(NsxInst_t* inst, uint16_t* nonSpeechProbFinal, uint32_t* priorLocSnr, uint32_t* postLocSnr) { uint32_t zeros, num, den, tmpU32no1, tmpU32no2, tmpU32no3; int32_t invLrtFX, indPriorFX, tmp32, tmp32no1, tmp32no2, besselTmpFX32; int32_t frac32, logTmp; int32_t logLrtTimeAvgKsumFX; int16_t indPriorFX16; int16_t tmp16, tmp16no1, tmp16no2, tmpIndFX, tableIndex, frac, intPart; int i, normTmp, normTmp2, nShifts; // compute feature based on average LR factor // this is the average over all frequencies of the smooth log LRT logLrtTimeAvgKsumFX = 0; for (i = 0; i < inst->magnLen; i++) { besselTmpFX32 = (int32_t)postLocSnr[i]; // Q11 normTmp = WebRtcSpl_NormU32(postLocSnr[i]); num = WEBRTC_SPL_LSHIFT_U32(postLocSnr[i], normTmp); // Q(11+normTmp) if (normTmp > 10) { den = WEBRTC_SPL_LSHIFT_U32(priorLocSnr[i], normTmp - 11); // Q(normTmp) } else { den = WEBRTC_SPL_RSHIFT_U32(priorLocSnr[i], 11 - normTmp); // Q(normTmp) } if (den > 0) { besselTmpFX32 -= WEBRTC_SPL_UDIV(num, den); // Q11 } else { besselTmpFX32 -= num; // Q11 } // inst->logLrtTimeAvg[i] += LRT_TAVG * (besselTmp - log(snrLocPrior) // - inst->logLrtTimeAvg[i]); // Here, LRT_TAVG = 0.5 zeros = WebRtcSpl_NormU32(priorLocSnr[i]); frac32 = (int32_t)(((priorLocSnr[i] << zeros) & 0x7FFFFFFF) >> 19); tmp32 = WEBRTC_SPL_MUL(frac32, frac32); tmp32 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(tmp32, -43), 19); tmp32 += WEBRTC_SPL_MUL_16_16_RSFT((int16_t)frac32, 5412, 12); frac32 = tmp32 + 37; // tmp32 = log2(priorLocSnr[i]) tmp32 = (int32_t)(((31 - zeros) << 12) + frac32) - (11 << 12); // Q12 logTmp = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(tmp32, 178), 8); // log2(priorLocSnr[i])*log(2) tmp32no1 = WEBRTC_SPL_RSHIFT_W32(logTmp + inst->logLrtTimeAvgW32[i], 1); // Q12 inst->logLrtTimeAvgW32[i] += (besselTmpFX32 - tmp32no1); // Q12 logLrtTimeAvgKsumFX += inst->logLrtTimeAvgW32[i]; // Q12 } inst->featureLogLrt = WEBRTC_SPL_RSHIFT_W32(logLrtTimeAvgKsumFX * 5, inst->stages + 10); // 5 = BIN_SIZE_LRT / 2 // done with computation of LR factor // //compute the indicator functions // // average LRT feature // FLOAT code // indicator0 = 0.5 * (tanh(widthPrior * // (logLrtTimeAvgKsum - threshPrior0)) + 1.0); tmpIndFX = 16384; // Q14(1.0) tmp32no1 = logLrtTimeAvgKsumFX - inst->thresholdLogLrt; // Q12 nShifts = 7 - inst->stages; // WIDTH_PR_MAP_SHIFT - inst->stages + 5; //use larger width in tanh map for pause regions if (tmp32no1 < 0) { tmpIndFX = 0; tmp32no1 = -tmp32no1; //widthPrior = widthPrior * 2.0; nShifts++; } tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, nShifts); // Q14 // compute indicator function: sigmoid map tableIndex = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 14); if ((tableIndex < 16) && (tableIndex >= 0)) { tmp16no2 = kIndicatorTable[tableIndex]; tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; frac = (int16_t)(tmp32no1 & 0x00003fff); // Q14 tmp16no2 += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, frac, 14); if (tmpIndFX == 0) { tmpIndFX = 8192 - tmp16no2; // Q14 } else { tmpIndFX = 8192 + tmp16no2; // Q14 } } indPriorFX = WEBRTC_SPL_MUL_16_16(inst->weightLogLrt, tmpIndFX); // 6*Q14 //spectral flatness feature if (inst->weightSpecFlat) { tmpU32no1 = WEBRTC_SPL_UMUL(inst->featureSpecFlat, 400); // Q10 tmpIndFX = 16384; // Q14(1.0) //use larger width in tanh map for pause regions tmpU32no2 = inst->thresholdSpecFlat - tmpU32no1; //Q10 nShifts = 4; if (inst->thresholdSpecFlat < tmpU32no1) { tmpIndFX = 0; tmpU32no2 = tmpU32no1 - inst->thresholdSpecFlat; //widthPrior = widthPrior * 2.0; nShifts++; } tmp32no1 = (int32_t)WebRtcSpl_DivU32U16(WEBRTC_SPL_LSHIFT_U32(tmpU32no2, nShifts), 25); //Q14 tmpU32no1 = WebRtcSpl_DivU32U16(WEBRTC_SPL_LSHIFT_U32(tmpU32no2, nShifts), 25); //Q14 // compute indicator function: sigmoid map // FLOAT code // indicator1 = 0.5 * (tanh(sgnMap * widthPrior * // (threshPrior1 - tmpFloat1)) + 1.0); tableIndex = (int16_t)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 14); if (tableIndex < 16) { tmp16no2 = kIndicatorTable[tableIndex]; tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; frac = (int16_t)(tmpU32no1 & 0x00003fff); // Q14 tmp16no2 += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, frac, 14); if (tmpIndFX) { tmpIndFX = 8192 + tmp16no2; // Q14 } else { tmpIndFX = 8192 - tmp16no2; // Q14 } } indPriorFX += WEBRTC_SPL_MUL_16_16(inst->weightSpecFlat, tmpIndFX); // 6*Q14 } //for template spectral-difference if (inst->weightSpecDiff) { tmpU32no1 = 0; if (inst->featureSpecDiff) { normTmp = WEBRTC_SPL_MIN(20 - inst->stages, WebRtcSpl_NormU32(inst->featureSpecDiff)); tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(inst->featureSpecDiff, normTmp); // Q(normTmp-2*stages) tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(inst->timeAvgMagnEnergy, 20 - inst->stages - normTmp); if (tmpU32no2 > 0) { // Q(20 - inst->stages) tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); } else { tmpU32no1 = (uint32_t)(0x7fffffff); } } tmpU32no3 = WEBRTC_SPL_UDIV(WEBRTC_SPL_LSHIFT_U32(inst->thresholdSpecDiff, 17), 25); tmpU32no2 = tmpU32no1 - tmpU32no3; nShifts = 1; tmpIndFX = 16384; // Q14(1.0) //use larger width in tanh map for pause regions if (tmpU32no2 & 0x80000000) { tmpIndFX = 0; tmpU32no2 = tmpU32no3 - tmpU32no1; //widthPrior = widthPrior * 2.0; nShifts--; } tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, nShifts); // compute indicator function: sigmoid map /* FLOAT code indicator2 = 0.5 * (tanh(widthPrior * (tmpFloat1 - threshPrior2)) + 1.0); */ tableIndex = (int16_t)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 14); if (tableIndex < 16) { tmp16no2 = kIndicatorTable[tableIndex]; tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; frac = (int16_t)(tmpU32no1 & 0x00003fff); // Q14 tmp16no2 += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( tmp16no1, frac, 14); if (tmpIndFX) { tmpIndFX = 8192 + tmp16no2; } else { tmpIndFX = 8192 - tmp16no2; } } indPriorFX += WEBRTC_SPL_MUL_16_16(inst->weightSpecDiff, tmpIndFX); // 6*Q14 } //combine the indicator function with the feature weights // FLOAT code // indPrior = 1 - (weightIndPrior0 * indicator0 + weightIndPrior1 * // indicator1 + weightIndPrior2 * indicator2); indPriorFX16 = WebRtcSpl_DivW32W16ResW16(98307 - indPriorFX, 6); // Q14 // done with computing indicator function //compute the prior probability // FLOAT code // inst->priorNonSpeechProb += PRIOR_UPDATE * // (indPriorNonSpeech - inst->priorNonSpeechProb); tmp16 = indPriorFX16 - inst->priorNonSpeechProb; // Q14 inst->priorNonSpeechProb += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( PRIOR_UPDATE_Q14, tmp16, 14); // Q14 //final speech probability: combine prior model with LR factor: memset(nonSpeechProbFinal, 0, sizeof(uint16_t) * inst->magnLen); if (inst->priorNonSpeechProb > 0) { for (i = 0; i < inst->magnLen; i++) { // FLOAT code // invLrt = exp(inst->logLrtTimeAvg[i]); // invLrt = inst->priorSpeechProb * invLrt; // nonSpeechProbFinal[i] = (1.0 - inst->priorSpeechProb) / // (1.0 - inst->priorSpeechProb + invLrt); // invLrt = (1.0 - inst->priorNonSpeechProb) * invLrt; // nonSpeechProbFinal[i] = inst->priorNonSpeechProb / // (inst->priorNonSpeechProb + invLrt); if (inst->logLrtTimeAvgW32[i] < 65300) { tmp32no1 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL( inst->logLrtTimeAvgW32[i], 23637), 14); // Q12 intPart = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 12); if (intPart < -8) { intPart = -8; } frac = (int16_t)(tmp32no1 & 0x00000fff); // Q12 // Quadratic approximation of 2^frac tmp32no2 = WEBRTC_SPL_RSHIFT_W32(frac * frac * 44, 19); // Q12 tmp32no2 += WEBRTC_SPL_MUL_16_16_RSFT(frac, 84, 7); // Q12 invLrtFX = WEBRTC_SPL_LSHIFT_W32(1, 8 + intPart) + WEBRTC_SPL_SHIFT_W32(tmp32no2, intPart - 4); // Q8 normTmp = WebRtcSpl_NormW32(invLrtFX); normTmp2 = WebRtcSpl_NormW16((16384 - inst->priorNonSpeechProb)); if (normTmp + normTmp2 >= 7) { if (normTmp + normTmp2 < 15) { invLrtFX = WEBRTC_SPL_RSHIFT_W32(invLrtFX, 15 - normTmp2 - normTmp); // Q(normTmp+normTmp2-7) tmp32no1 = WEBRTC_SPL_MUL_32_16(invLrtFX, (16384 - inst->priorNonSpeechProb)); // Q(normTmp+normTmp2+7) invLrtFX = WEBRTC_SPL_SHIFT_W32(tmp32no1, 7 - normTmp - normTmp2); // Q14 } else { tmp32no1 = WEBRTC_SPL_MUL_32_16(invLrtFX, (16384 - inst->priorNonSpeechProb)); // Q22 invLrtFX = WEBRTC_SPL_RSHIFT_W32(tmp32no1, 8); // Q14 } tmp32no1 = WEBRTC_SPL_LSHIFT_W32((int32_t)inst->priorNonSpeechProb, 8); // Q22 nonSpeechProbFinal[i] = (uint16_t)WEBRTC_SPL_DIV(tmp32no1, (int32_t)inst->priorNonSpeechProb + invLrtFX); // Q8 } } } } }
int WebRtcNetEQ_RecInInternal(MCUInst_t *MCU_inst, RTPPacket_t *RTPpacketInput, WebRtc_UWord32 uw32_timeRec) { RTPPacket_t RTPpacket[2]; int i_k; int i_ok = 0, i_No_Of_Payloads = 1; WebRtc_Word16 flushed = 0; WebRtc_Word16 codecPos; WebRtc_UWord32 diffTS, uw32_tmp; int curr_Codec; WebRtc_Word16 isREDPayload = 0; WebRtc_Word32 temp_bufsize = MCU_inst->PacketBuffer_inst.numPacketsInBuffer; #ifdef NETEQ_RED_CODEC RTPPacket_t* RTPpacketPtr[2]; /* Support for redundancy up to 2 payloads */ RTPpacketPtr[0] = &RTPpacket[0]; RTPpacketPtr[1] = &RTPpacket[1]; #endif /* * Copy from input RTP packet to local copy * (mainly to enable multiple payloads using RED) */ WEBRTC_SPL_MEMCPY_W8(&RTPpacket[0], RTPpacketInput, sizeof(RTPPacket_t)); /* Reinitialize NetEq if it's needed (changed SSRC or first call) */ if ((RTPpacket[0].ssrc != MCU_inst->ssrc) || (MCU_inst->first_packet == 1)) { WebRtcNetEQ_RTCPInit(&MCU_inst->RTCP_inst, RTPpacket[0].seqNumber); MCU_inst->first_packet = 0; /* Flush the buffer */ WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst); /* Store new SSRC */ MCU_inst->ssrc = RTPpacket[0].ssrc; /* Update codecs */ MCU_inst->timeStamp = RTPpacket[0].timeStamp; MCU_inst->current_Payload = RTPpacket[0].payloadType; /*Set MCU to update codec on next SignalMCU call */ MCU_inst->new_codec = 1; /* Reset timestamp scaling */ MCU_inst->TSscalingInitialized = 0; } /* Call RTCP statistics */ i_ok |= WebRtcNetEQ_RTCPUpdate(&(MCU_inst->RTCP_inst), RTPpacket[0].seqNumber, RTPpacket[0].timeStamp, uw32_timeRec); /* If Redundancy is supported and this is the redundancy payload, separate the payloads */ #ifdef NETEQ_RED_CODEC if (RTPpacket[0].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst, kDecoderRED)) { /* Split the payload into a main and a redundancy payloads */ i_ok = WebRtcNetEQ_RedundancySplit(RTPpacketPtr, 2, &i_No_Of_Payloads); if (i_ok < 0) { /* error returned */ return i_ok; } /* * Only accept a few redundancies of the same type as the main data, * AVT events and CNG. */ if ((i_No_Of_Payloads > 1) && (RTPpacket[0].payloadType != RTPpacket[1].payloadType) && (RTPpacket[0].payloadType != WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst, kDecoderAVT)) && (RTPpacket[1].payloadType != WebRtcNetEQ_DbGetPayload( &MCU_inst->codec_DB_inst, kDecoderAVT)) && (!WebRtcNetEQ_DbIsCNGPayload( &MCU_inst->codec_DB_inst, RTPpacket[0].payloadType)) && (!WebRtcNetEQ_DbIsCNGPayload(&MCU_inst->codec_DB_inst, RTPpacket[1].payloadType))) { i_No_Of_Payloads = 1; } isREDPayload = 1; } #endif /* loop over the number of payloads */ for (i_k = 0; i_k < i_No_Of_Payloads; i_k++) { if (isREDPayload == 1) { RTPpacket[i_k].rcuPlCntr = i_k; } else { RTPpacket[i_k].rcuPlCntr = 0; } /* Force update of SplitInfo if it's iLBC because of potential change between 20/30ms */ if (RTPpacket[i_k].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst, kDecoderILBC)) { i_ok = WebRtcNetEQ_DbGetSplitInfo( &MCU_inst->PayloadSplit_inst, (enum WebRtcNetEQDecoder) WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst, RTPpacket[i_k].payloadType), RTPpacket[i_k].payloadLen); if (i_ok < 0) { /* error returned */ return i_ok; } } /* Get information about timestamp scaling for this payload type */ i_ok = WebRtcNetEQ_GetTimestampScaling(MCU_inst, RTPpacket[i_k].payloadType); if (i_ok < 0) { /* error returned */ return i_ok; } if (MCU_inst->TSscalingInitialized == 0 && MCU_inst->scalingFactor != kTSnoScaling) { /* Must initialize scaling with current timestamps */ MCU_inst->externalTS = RTPpacket[i_k].timeStamp; MCU_inst->internalTS = RTPpacket[i_k].timeStamp; MCU_inst->TSscalingInitialized = 1; } /* Adjust timestamp if timestamp scaling is needed (e.g. SILK or G.722) */ if (MCU_inst->TSscalingInitialized == 1) { WebRtc_UWord32 newTS = WebRtcNetEQ_ScaleTimestampExternalToInternal(MCU_inst, RTPpacket[i_k].timeStamp); /* save the incoming timestamp for next time */ MCU_inst->externalTS = RTPpacket[i_k].timeStamp; /* add the scaled difference to last scaled timestamp and save ... */ MCU_inst->internalTS = newTS; RTPpacket[i_k].timeStamp = newTS; } /* Is this a DTMF packet?*/ if (RTPpacket[i_k].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst, kDecoderAVT)) { #ifdef NETEQ_ATEVENT_DECODE if (MCU_inst->AVT_PlayoutOn) { i_ok = WebRtcNetEQ_DtmfInsertEvent(&MCU_inst->DTMF_inst, RTPpacket[i_k].payload, RTPpacket[i_k].payloadLen, RTPpacket[i_k].timeStamp); if (i_ok != 0) { return i_ok; } } #endif #ifdef NETEQ_STEREO if (MCU_inst->usingStereo == 0) { /* do not set this for DTMF packets when using stereo mode */ MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1; } #else MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1; #endif } else if (WebRtcNetEQ_DbIsCNGPayload(&MCU_inst->codec_DB_inst, RTPpacket[i_k].payloadType)) { /* Is this a CNG packet? how should we handle this?*/ #ifdef NETEQ_CNG_CODEC /* Get CNG sample rate */ WebRtc_UWord16 fsCng = WebRtcNetEQ_DbGetSampleRate(&MCU_inst->codec_DB_inst, RTPpacket[i_k].payloadType); if ((fsCng != MCU_inst->fs) && (fsCng > 8000)) { /* * We have received CNG with a different sample rate from what we are using * now (must be > 8000, since we may use only one CNG type (default) for all * frequencies). Flush buffer and signal new codec. */ WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst); MCU_inst->new_codec = 1; MCU_inst->current_Codec = -1; } i_ok = WebRtcNetEQ_PacketBufferInsert(&MCU_inst->PacketBuffer_inst, &RTPpacket[i_k], &flushed); if (i_ok < 0) { return RECIN_CNG_ERROR; } MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1; #else /* NETEQ_CNG_CODEC not defined */ return RECIN_UNKNOWNPAYLOAD; #endif /* NETEQ_CNG_CODEC */ } else { /* Reinitialize the splitting if the payload and/or the payload length has changed */ curr_Codec = WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst, RTPpacket[i_k].payloadType); if (curr_Codec != MCU_inst->current_Codec) { if (curr_Codec < 0) { return RECIN_UNKNOWNPAYLOAD; } MCU_inst->current_Codec = curr_Codec; MCU_inst->current_Payload = RTPpacket[i_k].payloadType; i_ok = WebRtcNetEQ_DbGetSplitInfo(&MCU_inst->PayloadSplit_inst, (enum WebRtcNetEQDecoder) MCU_inst->current_Codec, RTPpacket[i_k].payloadLen); if (i_ok < 0) { /* error returned */ return i_ok; } WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst); MCU_inst->new_codec = 1; } /* update post-call statistics */ if (MCU_inst->new_codec != 1) /* not if in codec change */ { diffTS = RTPpacket[i_k].timeStamp - MCU_inst->timeStamp; /* waiting time */ if (diffTS < 0x0FFFFFFF) /* guard against re-ordering */ { /* waiting time in ms */ diffTS = WEBRTC_SPL_UDIV(diffTS, WEBRTC_SPL_UDIV((WebRtc_UWord32) MCU_inst->fs, 1000) ); if (diffTS < MCU_inst->statInst.minPacketDelayMs) { /* new all-time low */ MCU_inst->statInst.minPacketDelayMs = diffTS; } if (diffTS > MCU_inst->statInst.maxPacketDelayMs) { /* new all-time high */ MCU_inst->statInst.maxPacketDelayMs = diffTS; } /* Update avg waiting time: * avgPacketDelayMs = * (avgPacketCount * avgPacketDelayMs + diffTS)/(avgPacketCount+1) * with proper rounding. */ uw32_tmp = WEBRTC_SPL_UMUL((WebRtc_UWord32) MCU_inst->statInst.avgPacketCount, (WebRtc_UWord32) MCU_inst->statInst.avgPacketDelayMs); uw32_tmp = WEBRTC_SPL_ADD_SAT_W32(uw32_tmp, (diffTS + (MCU_inst->statInst.avgPacketCount>>1))); uw32_tmp = WebRtcSpl_DivU32U16(uw32_tmp, (WebRtc_UWord16) (MCU_inst->statInst.avgPacketCount + 1)); MCU_inst->statInst.avgPacketDelayMs = (WebRtc_UWord16) WEBRTC_SPL_MIN(uw32_tmp, (WebRtc_UWord32) 65535); /* increase counter, but not to more than 65534 */ if (MCU_inst->statInst.avgPacketCount < (0xFFFF - 1)) { MCU_inst->statInst.avgPacketCount++; } } } /* Parse the payload and insert it into the buffer */ i_ok = WebRtcNetEQ_SplitAndInsertPayload(&RTPpacket[i_k], &MCU_inst->PacketBuffer_inst, &MCU_inst->PayloadSplit_inst, &flushed); if (i_ok < 0) { return i_ok; } if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF != 0) { /* first normal packet after CNG or DTMF */ MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = -1; } }
void WebRtcIlbcfix_CbUpdateBestIndex( WebRtc_Word32 CritNew, /* (i) New Potentially best Criteria */ WebRtc_Word16 CritNewSh, /* (i) Shift value of above Criteria */ WebRtc_Word16 IndexNew, /* (i) Index of new Criteria */ WebRtc_Word32 cDotNew, /* (i) Cross dot of new index */ WebRtc_Word16 invEnergyNew, /* (i) Inversed energy new index */ WebRtc_Word16 energyShiftNew, /* (i) Energy shifts of new index */ WebRtc_Word32 *CritMax, /* (i/o) Maximum Criteria (so far) */ WebRtc_Word16 *shTotMax, /* (i/o) Shifts of maximum criteria */ WebRtc_Word16 *bestIndex, /* (i/o) Index that corresponds to maximum criteria */ WebRtc_Word16 *bestGain) /* (i/o) Gain in Q14 that corresponds to maximum criteria */ { WebRtc_Word16 shOld, shNew, tmp16; WebRtc_Word16 scaleTmp; WebRtc_Word32 gainW32; /* Normalize the new and old Criteria to the same domain */ if (CritNewSh>(*shTotMax)) { shOld=WEBRTC_SPL_MIN(31,CritNewSh-(*shTotMax)); shNew=0; } else { shOld=0; shNew=WEBRTC_SPL_MIN(31,(*shTotMax)-CritNewSh); } /* Compare the two criterias. If the new one is better, calculate the gain and store this index as the new best one */ if (WEBRTC_SPL_RSHIFT_W32(CritNew, shNew)> WEBRTC_SPL_RSHIFT_W32((*CritMax),shOld)) { tmp16 = (WebRtc_Word16)WebRtcSpl_NormW32(cDotNew); tmp16 = 16 - tmp16; /* Calculate the gain in Q14 Compensate for inverseEnergyshift in Q29 and that the energy value was stored in a WebRtc_Word16 (shifted down 16 steps) => 29-14+16 = 31 */ scaleTmp = -energyShiftNew-tmp16+31; scaleTmp = WEBRTC_SPL_MIN(31, scaleTmp); gainW32 = WEBRTC_SPL_MUL_16_16_RSFT( ((WebRtc_Word16)WEBRTC_SPL_SHIFT_W32(cDotNew, -tmp16)), invEnergyNew, scaleTmp); /* Check if criteria satisfies Gain criteria (max 1.3) if it is larger set the gain to 1.3 (slightly different from FLP version) */ if (gainW32>21299) { *bestGain=21299; } else if (gainW32<-21299) { *bestGain=-21299; } else { *bestGain=(WebRtc_Word16)gainW32; } *CritMax=CritNew; *shTotMax=CritNewSh; *bestIndex = IndexNew; } return; }
void WebRtcIsacfix_InitialPitch(const int16_t *in, /* Q0 */ PitchAnalysisStruct *State, int16_t *lagsQ7 /* Q7 */ ) { int16_t buf_dec16[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2]; int32_t *crrvecQ8_1,*crrvecQ8_2; int32_t cv1q[PITCH_LAG_SPAN2+2],cv2q[PITCH_LAG_SPAN2+2], peakvq[PITCH_LAG_SPAN2+2]; int k; int16_t peaks_indq; int16_t peakiq[PITCH_LAG_SPAN2]; int32_t corr; int32_t corr32, corr_max32, corr_max_o32; int16_t npkq; int16_t best4q[4]={0,0,0,0}; int32_t xq[3],yq[1],fyq[1]; int32_t *fxq; int32_t best_lag1q, best_lag2q; int32_t tmp32a,tmp32b,lag32,ratq; int16_t start; int16_t oldgQ12, tmp16a, tmp16b, gain_bias16,tmp16c, tmp16d, bias16; int32_t tmp32c,tmp32d, tmp32e; int16_t old_lagQ; int32_t old_lagQ8; int32_t lagsQ8[4]; old_lagQ = State->PFstr_wght.oldlagQ7; // Q7 old_lagQ8= WEBRTC_SPL_LSHIFT_W32((int32_t)old_lagQ,1); //Q8 oldgQ12= State->PFstr_wght.oldgainQ12; crrvecQ8_1=&cv1q[1]; crrvecQ8_2=&cv2q[1]; /* copy old values from state buffer */ memcpy(buf_dec16, State->dec_buffer16, WEBRTC_SPL_MUL_16_16(sizeof(int16_t), (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2))); /* decimation; put result after the old values */ WebRtcIsacfix_DecimateAllpass32(in, State->decimator_state32, PITCH_FRAME_LEN, &buf_dec16[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2]); /* low-pass filtering */ start= PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; WebRtcSpl_FilterARFastQ12(&buf_dec16[start],&buf_dec16[start],(int16_t*)kACoefQ12,3, PITCH_FRAME_LEN/2); /* copy end part back into state buffer */ for (k = 0; k < (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2); k++) State->dec_buffer16[k] = buf_dec16[k+PITCH_FRAME_LEN/2]; /* compute correlation for first and second half of the frame */ PCorr2Q32(buf_dec16, crrvecQ8_1); PCorr2Q32(buf_dec16 + PITCH_CORR_STEP2, crrvecQ8_2); /* bias towards pitch lag of previous frame */ tmp32a = Log2Q8((uint32_t) old_lagQ8) - 2304; // log2(0.5*oldlag) in Q8 tmp32b = WEBRTC_SPL_MUL_16_16_RSFT(oldgQ12,oldgQ12, 10); //Q12 & * 4.0; gain_bias16 = (int16_t) tmp32b; //Q12 if (gain_bias16 > 3276) gain_bias16 = 3276; // 0.8 in Q12 for (k = 0; k < PITCH_LAG_SPAN2; k++) { if (crrvecQ8_1[k]>0) { tmp32b = Log2Q8((uint32_t) (k + (PITCH_MIN_LAG/2-2))); tmp16a = (int16_t) (tmp32b - tmp32a); // Q8 & fabs(ratio)<4 tmp32c = WEBRTC_SPL_MUL_16_16_RSFT(tmp16a,tmp16a, 6); //Q10 tmp16b = (int16_t) tmp32c; // Q10 & <8 tmp32d = WEBRTC_SPL_MUL_16_16_RSFT(tmp16b, 177 , 8); // mult with ln2 in Q8 tmp16c = (int16_t) tmp32d; // Q10 & <4 tmp16d = Exp2Q10((int16_t) -tmp16c); //Q10 tmp32c = WEBRTC_SPL_MUL_16_16_RSFT(gain_bias16,tmp16d,13); // Q10 & * 0.5 bias16 = (int16_t) (1024 + tmp32c); // Q10 tmp32b = Log2Q8((uint32_t) bias16) - 2560; // Q10 in -> Q8 out with 10*2^8 offset crrvecQ8_1[k] += tmp32b ; // -10*2^8 offset } } /* taper correlation functions */ for (k = 0; k < 3; k++) { crrvecQ8_1[k] += kLogLagWinQ8[k]; crrvecQ8_2[k] += kLogLagWinQ8[k]; crrvecQ8_1[PITCH_LAG_SPAN2-1-k] += kLogLagWinQ8[k]; crrvecQ8_2[PITCH_LAG_SPAN2-1-k] += kLogLagWinQ8[k]; } /* Make zeropadded corr vectors */ cv1q[0]=0; cv2q[0]=0; cv1q[PITCH_LAG_SPAN2+1]=0; cv2q[PITCH_LAG_SPAN2+1]=0; corr_max32 = 0; for (k = 1; k <= PITCH_LAG_SPAN2; k++) { corr32=crrvecQ8_1[k-1]; if (corr32 > corr_max32) corr_max32 = corr32; corr32=crrvecQ8_2[k-1]; corr32 += -4; // Compensate for later (log2(0.99)) if (corr32 > corr_max32) corr_max32 = corr32; } /* threshold value to qualify as a peak */ // corr_max32 += -726; // log(0.14)/log(2.0) in Q8 corr_max32 += -1000; // log(0.14)/log(2.0) in Q8 corr_max_o32 = corr_max32; /* find peaks in corr1 */ peaks_indq = 0; for (k = 1; k <= PITCH_LAG_SPAN2; k++) { corr32=cv1q[k]; if (corr32>corr_max32) { // Disregard small peaks if ((corr32>=cv1q[k-1]) && (corr32>cv1q[k+1])) { // Peak? peakvq[peaks_indq] = corr32; peakiq[peaks_indq++] = k; } } } /* find highest interpolated peak */ corr_max32=0; best_lag1q =0; if (peaks_indq > 0) { FindFour32(peakvq, (int16_t) peaks_indq, best4q); npkq = WEBRTC_SPL_MIN(peaks_indq, 4); for (k=0;k<npkq;k++) { lag32 = peakiq[best4q[k]]; fxq = &cv1q[peakiq[best4q[k]]-1]; xq[0]= lag32; xq[0] = WEBRTC_SPL_LSHIFT_W32(xq[0], 8); Intrp1DQ8(xq, fxq, yq, fyq); tmp32a= Log2Q8((uint32_t) *yq) - 2048; // offset 8*2^8 /* Bias towards short lags */ /* log(pow(0.8, log(2.0 * *y )))/log(2.0) */ tmp32b= WEBRTC_SPL_MUL_16_16_RSFT((int16_t) tmp32a, -42, 8); tmp32c= tmp32b + 256; *fyq += tmp32c; if (*fyq > corr_max32) { corr_max32 = *fyq; best_lag1q = *yq; } } tmp32a = best_lag1q - OFFSET_Q8; tmp32b = WEBRTC_SPL_LSHIFT_W32(tmp32a, 1); lagsQ8[0] = tmp32b + PITCH_MIN_LAG_Q8; lagsQ8[1] = lagsQ8[0]; } else { lagsQ8[0] = old_lagQ8; lagsQ8[1] = lagsQ8[0]; } /* Bias towards constant pitch */ tmp32a = lagsQ8[0] - PITCH_MIN_LAG_Q8; ratq = WEBRTC_SPL_RSHIFT_W32(tmp32a, 1) + OFFSET_Q8; for (k = 1; k <= PITCH_LAG_SPAN2; k++) { tmp32a = WEBRTC_SPL_LSHIFT_W32(k, 7); // 0.5*k Q8 tmp32b = (int32_t) (WEBRTC_SPL_LSHIFT_W32(tmp32a, 1)) - ratq; // Q8 tmp32c = WEBRTC_SPL_MUL_16_16_RSFT((int16_t) tmp32b, (int16_t) tmp32b, 8); // Q8 tmp32b = (int32_t) tmp32c + (int32_t) WEBRTC_SPL_RSHIFT_W32(ratq, 1); // (k-r)^2 + 0.5 * r Q8 tmp32c = Log2Q8((uint32_t) tmp32a) - 2048; // offset 8*2^8 , log2(0.5*k) Q8 tmp32d = Log2Q8((uint32_t) tmp32b) - 2048; // offset 8*2^8 , log2(0.5*k) Q8 tmp32e = tmp32c -tmp32d; cv2q[k] += WEBRTC_SPL_RSHIFT_W32(tmp32e, 1); } /* find peaks in corr2 */ corr_max32 = corr_max_o32; peaks_indq = 0; for (k = 1; k <= PITCH_LAG_SPAN2; k++) { corr=cv2q[k]; if (corr>corr_max32) { // Disregard small peaks if ((corr>=cv2q[k-1]) && (corr>cv2q[k+1])) { // Peak? peakvq[peaks_indq] = corr; peakiq[peaks_indq++] = k; } } } /* find highest interpolated peak */ corr_max32 = 0; best_lag2q =0; if (peaks_indq > 0) { FindFour32(peakvq, (int16_t) peaks_indq, best4q); npkq = WEBRTC_SPL_MIN(peaks_indq, 4); for (k=0;k<npkq;k++) { lag32 = peakiq[best4q[k]]; fxq = &cv2q[peakiq[best4q[k]]-1]; xq[0]= lag32; xq[0] = WEBRTC_SPL_LSHIFT_W32(xq[0], 8); Intrp1DQ8(xq, fxq, yq, fyq); /* Bias towards short lags */ /* log(pow(0.8, log(2.0f * *y )))/log(2.0f) */ tmp32a= Log2Q8((uint32_t) *yq) - 2048; // offset 8*2^8 tmp32b= WEBRTC_SPL_MUL_16_16_RSFT((int16_t) tmp32a, -82, 8); tmp32c= tmp32b + 256; *fyq += tmp32c; if (*fyq > corr_max32) { corr_max32 = *fyq; best_lag2q = *yq; } } tmp32a = best_lag2q - OFFSET_Q8; tmp32b = WEBRTC_SPL_LSHIFT_W32(tmp32a, 1); lagsQ8[2] = tmp32b + PITCH_MIN_LAG_Q8; lagsQ8[3] = lagsQ8[2]; } else { lagsQ8[2] = lagsQ8[0]; lagsQ8[3] = lagsQ8[0]; } lagsQ7[0]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[0], 1); lagsQ7[1]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[1], 1); lagsQ7[2]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[2], 1); lagsQ7[3]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[3], 1); }
static int ProcessNormal(Aec* aecpc, const float* const* nearend, int num_bands, float* const* out, int16_t nrOfSamples, int16_t msInSndCardBuf, int32_t skew) { int retVal = 0; short i; short nBlocks10ms; // Limit resampling to doubling/halving of signal const float minSkewEst = -0.5f; const float maxSkewEst = 1.0f; msInSndCardBuf = msInSndCardBuf > kMaxTrustedDelayMs ? kMaxTrustedDelayMs : msInSndCardBuf; // TODO(andrew): we need to investigate if this +10 is really wanted. msInSndCardBuf += 10; aecpc->msInSndCardBuf = msInSndCardBuf; if (aecpc->skewMode == kAecTrue) { if (aecpc->skewFrCtr < 25) { aecpc->skewFrCtr++; } else { retVal = WebRtcAec_GetSkew(aecpc->resampler, skew, &aecpc->skew); if (retVal == -1) { aecpc->skew = 0; aecpc->lastError = AEC_BAD_PARAMETER_WARNING; } aecpc->skew /= aecpc->sampFactor * nrOfSamples; if (aecpc->skew < 1.0e-3 && aecpc->skew > -1.0e-3) { aecpc->resample = kAecFalse; } else { aecpc->resample = kAecTrue; } if (aecpc->skew < minSkewEst) { aecpc->skew = minSkewEst; } else if (aecpc->skew > maxSkewEst) { aecpc->skew = maxSkewEst; } #ifdef WEBRTC_AEC_DEBUG_DUMP (void)fwrite(&aecpc->skew, sizeof(aecpc->skew), 1, aecpc->skewFile); #endif } } nBlocks10ms = nrOfSamples / (FRAME_LEN * aecpc->rate_factor); if (aecpc->startup_phase) { for (i = 0; i < num_bands; ++i) { // Only needed if they don't already point to the same place. if (nearend[i] != out[i]) { memcpy(out[i], nearend[i], sizeof(nearend[i][0]) * nrOfSamples); } } // The AEC is in the start up mode // AEC is disabled until the system delay is OK // Mechanism to ensure that the system delay is reasonably stable. if (aecpc->checkBuffSize) { aecpc->checkBufSizeCtr++; // Before we fill up the far-end buffer we require the system delay // to be stable (+/-8 ms) compared to the first value. This // comparison is made during the following 6 consecutive 10 ms // blocks. If it seems to be stable then we start to fill up the // far-end buffer. if (aecpc->counter == 0) { aecpc->firstVal = aecpc->msInSndCardBuf; aecpc->sum = 0; } if (abs(aecpc->firstVal - aecpc->msInSndCardBuf) < WEBRTC_SPL_MAX(0.2 * aecpc->msInSndCardBuf, sampMsNb)) { aecpc->sum += aecpc->msInSndCardBuf; aecpc->counter++; } else { aecpc->counter = 0; } if (aecpc->counter * nBlocks10ms >= 6) { // The far-end buffer size is determined in partitions of // PART_LEN samples. Use 75% of the average value of the system // delay as buffer size to start with. aecpc->bufSizeStart = WEBRTC_SPL_MIN((3 * aecpc->sum * aecpc->rate_factor * 8) / (4 * aecpc->counter * PART_LEN), kMaxBufSizeStart); // Buffer size has now been determined. aecpc->checkBuffSize = 0; } if (aecpc->checkBufSizeCtr * nBlocks10ms > 50) { // For really bad systems, don't disable the echo canceller for // more than 0.5 sec. aecpc->bufSizeStart = WEBRTC_SPL_MIN( (aecpc->msInSndCardBuf * aecpc->rate_factor * 3) / 40, kMaxBufSizeStart); aecpc->checkBuffSize = 0; } } // If |checkBuffSize| changed in the if-statement above. if (!aecpc->checkBuffSize) { // The system delay is now reasonably stable (or has been unstable // for too long). When the far-end buffer is filled with // approximately the same amount of data as reported by the system // we end the startup phase. int overhead_elements = WebRtcAec_system_delay(aecpc->aec) / PART_LEN - aecpc->bufSizeStart; if (overhead_elements == 0) { // Enable the AEC aecpc->startup_phase = 0; } else if (overhead_elements > 0) { // TODO(bjornv): Do we need a check on how much we actually // moved the read pointer? It should always be possible to move // the pointer |overhead_elements| since we have only added data // to the buffer and no delay compensation nor AEC processing // has been done. WebRtcAec_MoveFarReadPtr(aecpc->aec, overhead_elements); // Enable the AEC aecpc->startup_phase = 0; } } } else { // AEC is enabled. if (WebRtcAec_reported_delay_enabled(aecpc->aec)) { EstBufDelayNormal(aecpc); } // Call the AEC. // TODO(bjornv): Re-structure such that we don't have to pass // |aecpc->knownDelay| as input. Change name to something like // |system_buffer_diff|. WebRtcAec_ProcessFrames(aecpc->aec, nearend, num_bands, nrOfSamples, aecpc->knownDelay, out); } return retVal; }
WebRtc_Word16 WebRtcNetEQ_PeakDetection(WebRtc_Word16 *pw16_data, WebRtc_Word16 w16_dataLen, WebRtc_Word16 w16_nmbPeaks, WebRtc_Word16 fs_mult, WebRtc_Word16 *pw16_winIndex, WebRtc_Word16 *pw16_winValue) { /* Local variables */ int i; WebRtc_Word16 w16_tmp; WebRtc_Word16 w16_tmp2; WebRtc_Word16 indMin = 0; WebRtc_Word16 indMax = 0; /* Peak detection */ for (i = 0; i <= (w16_nmbPeaks - 1); i++) { if (w16_nmbPeaks == 1) { /* * Single peak * The parabola fit assumes that an extra point is available; worst case it gets * a zero on the high end of the signal. */ w16_dataLen++; } pw16_winIndex[i] = WebRtcSpl_MaxIndexW16(pw16_data, (WebRtc_Word16) (w16_dataLen - 1)); if (i != w16_nmbPeaks - 1) { w16_tmp = pw16_winIndex[i] - 2; /* *fs_mult; */ indMin = WEBRTC_SPL_MAX(0, w16_tmp); w16_tmp = pw16_winIndex[i] + 2; /* *fs_mult; */ w16_tmp2 = w16_dataLen - 1; indMax = WEBRTC_SPL_MIN(w16_tmp2, w16_tmp); } if ((pw16_winIndex[i] != 0) && (pw16_winIndex[i] != (w16_dataLen - 2))) { /* Parabola fit*/ WebRtcNetEQ_PrblFit(&(pw16_data[pw16_winIndex[i] - 1]), &(pw16_winIndex[i]), &(pw16_winValue[i]), fs_mult); } else { if (pw16_winIndex[i] == (w16_dataLen - 2)) { if (pw16_data[pw16_winIndex[i]] > pw16_data[pw16_winIndex[i] + 1]) { WebRtcNetEQ_PrblFit(&(pw16_data[pw16_winIndex[i] - 1]), &(pw16_winIndex[i]), &(pw16_winValue[i]), fs_mult); } else if (pw16_data[pw16_winIndex[i]] <= pw16_data[pw16_winIndex[i] + 1]) { pw16_winValue[i] = (pw16_data[pw16_winIndex[i]] + pw16_data[pw16_winIndex[i] + 1]) >> 1; /* lin approx */ pw16_winIndex[i] = (pw16_winIndex[i] * 2 + 1) * fs_mult; } } else { pw16_winValue[i] = pw16_data[pw16_winIndex[i]]; pw16_winIndex[i] = pw16_winIndex[i] * 2 * fs_mult; } }