// 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 } } } } }
/*-----------------------------------------------------------* * procedure Calc_exc_rand * * ~~~~~~~~~~~~~ * * Computes comfort noise excitation * * for SID and not-transmitted frames * *-----------------------------------------------------------*/ void WebRtcG729fix_Calc_exc_rand( int32_t L_exc_err[], int16_t cur_gain, /* (i) : target sample gain */ int16_t *exc, /* (i/o) : excitation array */ int16_t *seed, /* (i) : current Vad decision */ int flag_cod /* (i) : encoder/decoder flag */ ) { int16_t i, j, i_subfr; int16_t temp1, temp2; int16_t pos[4]; int16_t sign[4]; int16_t t0, frac; int16_t *cur_exc; int16_t g, Gp, Gp2; int16_t excg[L_SUBFR], excs[L_SUBFR]; int32_t L_acc, L_ener, L_k; int16_t max, hi, lo, inter_exc; int16_t sh; int16_t x1, x2; if (cur_gain == 0) { WebRtcSpl_ZerosArrayW16(exc, L_FRAME); Gp = 0; t0 = WebRtcSpl_AddSatW16(L_SUBFR,1); for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR) { if (flag_cod != FLAG_DEC) WebRtcG729fix_update_exc_err(L_exc_err, Gp, t0); } return; } /* Loop on subframes */ cur_exc = exc; for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR) { /* generate random adaptive codebook & fixed codebook parameters */ /*****************************************************************/ temp1 = WebRtcG729fix_Random(seed); frac = WebRtcSpl_SubSatW16((temp1 & (int16_t)0x0003), 1); if(frac == 2) frac = 0; temp1 = shr(temp1, 2); t0 = WebRtcSpl_AddSatW16((temp1 & (int16_t)0x003F), 40); temp1 = shr(temp1, 6); temp2 = temp1 & (int16_t)0x0007; pos[0] = WebRtcSpl_AddSatW16(shl(temp2, 2), temp2); /* 5 * temp2 */ temp1 = shr(temp1, 3); sign[0] = temp1 & (int16_t)0x0001; temp1 = shr(temp1, 1); temp2 = temp1 & (int16_t)0x0007; temp2 = WebRtcSpl_AddSatW16(shl(temp2, 2), temp2); pos[1] = WebRtcSpl_AddSatW16(temp2, 1); /* 5 * x + 1 */ temp1 = shr(temp1, 3); sign[1] = temp1 & (int16_t)0x0001; temp1 = WebRtcG729fix_Random(seed); temp2 = temp1 & (int16_t)0x0007; temp2 = WebRtcSpl_AddSatW16(shl(temp2, 2), temp2); pos[2] = WebRtcSpl_AddSatW16(temp2, 2); /* 5 * x + 2 */ temp1 = shr(temp1, 3); sign[2] = temp1 & (int16_t)0x0001; temp1 = shr(temp1, 1); temp2 = temp1 & (int16_t)0x000F; pos[3] = WebRtcSpl_AddSatW16((temp2 & (int16_t)1), 3); /* j+3*/ temp2 = (shr(temp2, 1)) & (int16_t)7; temp2 = WebRtcSpl_AddSatW16(shl(temp2, 2), temp2); /* 5i */ pos[3] = WebRtcSpl_AddSatW16(pos[3], temp2); temp1 = shr(temp1, 4); sign[3] = temp1 & (int16_t)0x0001; Gp = WebRtcG729fix_Random(seed) & (int16_t)0x1FFF; /* < 0.5 Q14 */ Gp2 = shl(Gp, 1); /* Q15 */ /* Generate gaussian excitation */ /********************************/ L_acc = 0L; for(i=0; i<L_SUBFR; i++) { temp1 = Gauss(seed); L_acc = L_mac(L_acc, temp1, temp1); excg[i] = temp1; } /* Compute fact = alpha x cur_gain * sqrt(L_SUBFR / Eg) with Eg = SUM(i=0->39) excg[i]^2 and alpha = 0.5 alpha x sqrt(L_SUBFR)/2 = 1 + FRAC1 */ L_acc = WebRtcG729fix_Inv_sqrt(L_shr(L_acc,1)); /* Q30 */ WebRtcG729fix_L_Extract(L_acc, &hi, &lo); /* cur_gain = cur_gainR << 3 */ temp1 = mult_r(cur_gain, FRAC1); temp1 = WebRtcSpl_AddSatW16(cur_gain, temp1); /* <=> alpha x cur_gainR x 2^2 x sqrt(L_SUBFR) */ L_acc = WebRtcG729fix_Mpy_32_16(hi, lo, temp1); /* fact << 17 */ sh = WebRtcSpl_NormW32(L_acc); temp1 = extract_h(L_shl(L_acc, sh)); /* fact << (sh+1) */ sh = WebRtcSpl_SubSatW16(sh, 14); for (i = 0; i < L_SUBFR; i++) { temp2 = mult_r(excg[i], temp1); temp2 = shr_r(temp2, sh); /* shl if sh < 0 */ excg[i] = temp2; } /* generate random adaptive excitation */ /****************************************/ WebRtcG729fix_Pred_lt_3(cur_exc, t0, frac, L_SUBFR); /* compute adaptive + gaussian exc -> cur_exc */ /**********************************************/ max = 0; for(i = 0; i < L_SUBFR; i++) { temp1 = mult_r(cur_exc[i], Gp2); temp1 = WebRtcSpl_AddSatW16(temp1, excg[i]); /* may overflow */ cur_exc[i] = temp1; temp1 = abs_s(temp1); if (temp1 > max) max = temp1; } /* rescale cur_exc -> excs */ if (max == 0) sh = 0; else { sh = WebRtcSpl_SubSatW16(3, WebRtcSpl_NormW16(max)); if (sh <= 0) sh = 0; } for (i = 0; i < L_SUBFR; i++) { excs[i] = shr(cur_exc[i], sh); } /* Compute fixed code gain */ /***************************/ /**********************************************************/ /*** Solve EQ(X) = 4 X**2 + 2 b X + c */ /**********************************************************/ L_ener = 0L; for (i = 0; i < L_SUBFR; i++) { L_ener = L_mac(L_ener, excs[i], excs[i]); } /* ener x 2^(-2sh + 1) */ /* inter_exc = b >> sh */ inter_exc = 0; for (i = 0; i < 4; i++) { j = pos[i]; if (sign[i] == 0) { inter_exc = WebRtcSpl_SubSatW16(inter_exc, excs[j]); } else { inter_exc = WebRtcSpl_AddSatW16(inter_exc, excs[j]); } } /* Compute k = cur_gainR x cur_gainR x L_SUBFR */ L_acc = L_mult(cur_gain, L_SUBFR); L_acc = L_shr(L_acc, 6); temp1 = extract_l(L_acc); /* cur_gainR x L_SUBFR x 2^(-2) */ L_k = L_mult(cur_gain, temp1); /* k << 2 */ temp1 = WebRtcSpl_AddSatW16(1, shl(sh,1)); L_acc = L_shr(L_k, temp1); /* k x 2^(-2sh+1) */ /* Compute delta = b^2 - 4 c */ L_acc = WebRtcSpl_SubSatW32(L_acc, L_ener); /* - 4 c x 2^(-2sh-1) */ inter_exc = shr(inter_exc, 1); L_acc = L_mac(L_acc, inter_exc, inter_exc); /* 2^(-2sh-1) */ sh = WebRtcSpl_AddSatW16(sh, 1); /* inter_exc = b x 2^(-sh) */ /* L_acc = delta x 2^(-2sh+1) */ if (L_acc < 0) { /* adaptive excitation = 0 */ WEBRTC_SPL_MEMCPY_W16(cur_exc, excg, L_SUBFR); temp1 = abs_s(excg[(int)pos[0]]) | abs_s(excg[(int)pos[1]]); temp2 = abs_s(excg[(int)pos[2]]) | abs_s(excg[(int)pos[3]]); temp1 = temp1 | temp2; sh = ((temp1 & (int16_t)0x4000) == 0) ? (int16_t)1 : (int16_t)2; inter_exc = 0; for(i=0; i<4; i++) { temp1 = shr(excg[(int)pos[i]], sh); if(sign[i] == 0) { inter_exc = WebRtcSpl_SubSatW16(inter_exc, temp1); } else { inter_exc = WebRtcSpl_AddSatW16(inter_exc, temp1); } } /* inter_exc = b >> sh */ WebRtcG729fix_L_Extract(L_k, &hi, &lo); L_acc = WebRtcG729fix_Mpy_32_16(hi, lo, K0); /* k x (1- alpha^2) << 2 */ temp1 = WebRtcSpl_SubSatW16(shl(sh, 1), 1); /* temp1 > 0 */ L_acc = L_shr(L_acc, temp1); /* 4k x (1 - alpha^2) << (-2sh+1) */ L_acc = L_mac(L_acc, inter_exc, inter_exc); /* delta << (-2sh+1) */ Gp = 0; } temp2 = Sqrt(L_acc); /* >> sh */ x1 = WebRtcSpl_SubSatW16(temp2, inter_exc); x2 = negate(WebRtcSpl_AddSatW16(inter_exc, temp2)); /* x 2^(-sh+2) */ if(abs_s(x2) < abs_s(x1)) x1 = x2; temp1 = WebRtcSpl_SubSatW16(2, sh); g = shr_r(x1, temp1); /* shl if temp1 < 0 */ if (g >= 0) { if (g > G_MAX) g = G_MAX; } else { if (WebRtcSpl_AddSatW16(g, G_MAX) < 0) g = negate(G_MAX); } /* Update cur_exc with ACELP excitation */ for (i = 0; i < 4; i++) { j = pos[i]; if (sign[i] != 0) { cur_exc[j] = WebRtcSpl_AddSatW16(cur_exc[j], g); } else { cur_exc[j] = WebRtcSpl_SubSatW16(cur_exc[j], g); } } if (flag_cod != FLAG_DEC) WebRtcG729fix_update_exc_err(L_exc_err, Gp, t0); cur_exc += L_SUBFR; } /* end of loop on subframes */ return; }