// 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 } } } } }
void WebRtcIsacfix_GetVars(const WebRtc_Word16 *input, const WebRtc_Word16 *pitchGains_Q12, WebRtc_UWord32 *oldEnergy, WebRtc_Word16 *varscale) { int k; WebRtc_UWord32 nrgQ[4]; WebRtc_Word16 nrgQlog[4]; WebRtc_Word16 tmp16, chng1, chng2, chng3, chng4, tmp, chngQ, oldNrgQlog, pgQ, pg3; WebRtc_Word32 expPg32; WebRtc_Word16 expPg, divVal; WebRtc_Word16 tmp16_1, tmp16_2; /* Calculate energies of first and second frame halfs */ nrgQ[0]=0; for (k = QLOOKAHEAD/2; k < (FRAMESAMPLES/4 + QLOOKAHEAD) / 2; k++) { nrgQ[0] +=WEBRTC_SPL_MUL_16_16(input[k],input[k]); } nrgQ[1]=0; for ( ; k < (FRAMESAMPLES/2 + QLOOKAHEAD) / 2; k++) { nrgQ[1] +=WEBRTC_SPL_MUL_16_16(input[k],input[k]); } nrgQ[2]=0; for ( ; k < (WEBRTC_SPL_MUL_16_16(FRAMESAMPLES, 3)/4 + QLOOKAHEAD) / 2; k++) { nrgQ[2] +=WEBRTC_SPL_MUL_16_16(input[k],input[k]); } nrgQ[3]=0; for ( ; k < (FRAMESAMPLES + QLOOKAHEAD) / 2; k++) { nrgQ[3] +=WEBRTC_SPL_MUL_16_16(input[k],input[k]); } for ( k=0; k<4; k++) { nrgQlog[k] = (WebRtc_Word16)log2_Q8_LPC(nrgQ[k]); /* log2(nrgQ) */ } oldNrgQlog = (WebRtc_Word16)log2_Q8_LPC(*oldEnergy); /* Calculate average level change */ chng1 = WEBRTC_SPL_ABS_W16(nrgQlog[3]-nrgQlog[2]); chng2 = WEBRTC_SPL_ABS_W16(nrgQlog[2]-nrgQlog[1]); chng3 = WEBRTC_SPL_ABS_W16(nrgQlog[1]-nrgQlog[0]); chng4 = WEBRTC_SPL_ABS_W16(nrgQlog[0]-oldNrgQlog); tmp = chng1+chng2+chng3+chng4; chngQ = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp, kChngFactor, 10); /* Q12 */ chngQ += 2926; /* + 1.0/1.4 in Q12 */ /* Find average pitch gain */ pgQ = 0; for (k=0; k<4; k++) { pgQ += pitchGains_Q12[k]; } pg3 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(pgQ, pgQ,11); /* pgQ in Q(12+2)=Q14. Q14*Q14>>11 => Q17 */ pg3 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(pgQ, pg3,13); /* Q17*Q14>>13 =>Q18 */ pg3 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(pg3, kMulPitchGain ,5); /* Q10 kMulPitchGain = -25 = -200 in Q-3. */ tmp16=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(kExp2,pg3,13);/* Q13*Q10>>13 => Q10*/ if (tmp16<0) { tmp16_2 = (0x0400 | (tmp16 & 0x03FF)); tmp16_1 = (WEBRTC_SPL_RSHIFT_W16((WebRtc_UWord16)(tmp16 ^ 0xFFFF), 10)-3); /* Gives result in Q14 */ if (tmp16_1<0) expPg=(WebRtc_Word16) -WEBRTC_SPL_LSHIFT_W16(tmp16_2, -tmp16_1); else expPg=(WebRtc_Word16) -WEBRTC_SPL_RSHIFT_W16(tmp16_2, tmp16_1); } else expPg = (WebRtc_Word16) -16384; /* 1 in Q14, since 2^0=1 */ expPg32 = (WebRtc_Word32)WEBRTC_SPL_LSHIFT_W16((WebRtc_Word32)expPg, 8); /* Q22 */ divVal = WebRtcSpl_DivW32W16ResW16(expPg32, chngQ); /* Q22/Q12=Q10 */ tmp16=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(kExp2,divVal,13);/* Q13*Q10>>13 => Q10*/ if (tmp16<0) { tmp16_2 = (0x0400 | (tmp16 & 0x03FF)); tmp16_1 = (WEBRTC_SPL_RSHIFT_W16((WebRtc_UWord16)(tmp16 ^ 0xFFFF), 10)-3); /* Gives result in Q14 */ if (tmp16_1<0) expPg=(WebRtc_Word16) WEBRTC_SPL_LSHIFT_W16(tmp16_2, -tmp16_1); else expPg=(WebRtc_Word16) WEBRTC_SPL_RSHIFT_W16(tmp16_2, tmp16_1); } else expPg = (WebRtc_Word16) 16384; /* 1 in Q14, since 2^0=1 */ *varscale = expPg-1; *oldEnergy = nrgQ[3]; }
/* * Signals the MCU that DSP status data is available. */ int WebRtcNetEQ_SignalMcu(MCUInst_t *inst) { int i_bufferpos, i_res; WebRtc_UWord16 uw16_instr; DSP2MCU_info_t dspInfo; WebRtc_Word16 *blockPtr, blockLen; WebRtc_UWord32 uw32_availableTS; RTPPacket_t temp_pkt; WebRtc_Word32 w32_bufsize, w32_tmp; WebRtc_Word16 payloadType = -1; WebRtc_Word16 wantedNoOfTimeStamps; WebRtc_Word32 totalTS; WebRtc_Word16 oldPT, latePacketExist = 0; WebRtc_UWord32 oldTS, prevTS, uw32_tmp; WebRtc_UWord16 prevSeqNo; WebRtc_Word16 nextSeqNoAvail; WebRtc_Word16 fs_mult, w16_tmp; WebRtc_Word16 lastModeBGNonly = 0; #ifdef NETEQ_DELAY_LOGGING int temp_var; #endif int playDtmf = 0; fs_mult = WebRtcSpl_DivW32W16ResW16(inst->fs, 8000); /* Increment counter since last statistics report */ inst->lastReportTS += inst->timestampsPerCall; /* Increment waiting time for all packets. */ WebRtcNetEQ_IncrementWaitingTimes(&inst->PacketBuffer_inst); /* Read info from DSP so we now current status */ WEBRTC_SPL_MEMCPY_W8(&dspInfo,inst->pw16_readAddress,sizeof(DSP2MCU_info_t)); /* Set blockPtr to first payload block */ blockPtr = &inst->pw16_writeAddress[3]; /* Clear instruction word and number of lost samples (2*WebRtc_Word16) */ inst->pw16_writeAddress[0] = 0; inst->pw16_writeAddress[1] = 0; inst->pw16_writeAddress[2] = 0; if ((dspInfo.lastMode & MODE_AWAITING_CODEC_PTR) != 0) { /* * Make sure state is adjusted so that a codec update is * performed when first packet arrives. */ if (inst->new_codec != 1) { inst->current_Codec = -1; } dspInfo.lastMode = (dspInfo.lastMode ^ MODE_AWAITING_CODEC_PTR); } #ifdef NETEQ_STEREO if ((dspInfo.lastMode & MODE_MASTER_DTMF_SIGNAL) != 0) { playDtmf = 1; /* force DTMF decision */ dspInfo.lastMode = (dspInfo.lastMode ^ MODE_MASTER_DTMF_SIGNAL); } if ((dspInfo.lastMode & MODE_USING_STEREO) != 0) { if (inst->usingStereo == 0) { /* stereo mode changed; reset automode instance to re-synchronize statistics */ WebRtcNetEQ_ResetAutomode(&(inst->BufferStat_inst.Automode_inst), inst->PacketBuffer_inst.maxInsertPositions); } inst->usingStereo = 1; dspInfo.lastMode = (dspInfo.lastMode ^ MODE_USING_STEREO); } else { inst->usingStereo = 0; } #endif /* detect if BGN_ONLY flag is set in lastMode */ if ((dspInfo.lastMode & MODE_BGN_ONLY) != 0) { lastModeBGNonly = 1; /* remember flag */ dspInfo.lastMode ^= MODE_BGN_ONLY; /* clear the flag */ } if ((dspInfo.lastMode == MODE_RFC3389CNG) || (dspInfo.lastMode == MODE_CODEC_INTERNAL_CNG) || (dspInfo.lastMode == MODE_EXPAND)) { /* * If last mode was CNG (or Expand, since this could be covering up for a lost CNG * packet), increase the CNGplayedTS counter. */ inst->BufferStat_inst.uw32_CNGplayedTS += inst->timestampsPerCall; if (dspInfo.lastMode == MODE_RFC3389CNG) { /* remember that RFC3389CNG is on (needed if CNG is interrupted by DTMF) */ inst->BufferStat_inst.w16_cngOn = CNG_RFC3389_ON; } else if (dspInfo.lastMode == MODE_CODEC_INTERNAL_CNG) { /* remember that internal CNG is on (needed if CNG is interrupted by DTMF) */ inst->BufferStat_inst.w16_cngOn = CNG_INTERNAL_ON; } } /* Update packet size from previously decoded packet */ if (dspInfo.frameLen > 0) { inst->PacketBuffer_inst.packSizeSamples = dspInfo.frameLen; } /* Look for late packet (unless codec has changed) */ if (inst->new_codec != 1) { if (WebRtcNetEQ_DbIsMDCodec((enum WebRtcNetEQDecoder) inst->current_Codec)) { WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst, inst->timeStamp, &uw32_availableTS, &i_bufferpos, 1, &payloadType); if ((inst->new_codec != 1) && (inst->timeStamp == uw32_availableTS) && (inst->timeStamp < dspInfo.playedOutTS) && (i_bufferpos != -1) && (WebRtcNetEQ_DbGetPayload(&(inst->codec_DB_inst), (enum WebRtcNetEQDecoder) inst->current_Codec) == payloadType)) { int waitingTime; temp_pkt.payload = blockPtr + 1; i_res = WebRtcNetEQ_PacketBufferExtract(&inst->PacketBuffer_inst, &temp_pkt, i_bufferpos, &waitingTime); if (i_res < 0) { /* error returned */ return i_res; } WebRtcNetEQ_StoreWaitingTime(inst, waitingTime); *blockPtr = temp_pkt.payloadLen; /* set the flag if this is a redundant payload */ if (temp_pkt.rcuPlCntr > 0) { *blockPtr = (*blockPtr) | (DSP_CODEC_RED_FLAG); } blockPtr += ((temp_pkt.payloadLen + 1) >> 1) + 1; /* * Close the data with a zero size block, in case we will not write any * more data. */ *blockPtr = 0; inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0xf0ff) | DSP_CODEC_ADD_LATE_PKT; latePacketExist = 1; } }