| /* | |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. | |
| * | |
| * Use of this source code is governed by a BSD-style license | |
| * that can be found in the LICENSE file in the root of the source | |
| * tree. An additional intellectual property rights grant can be found | |
| * in the file PATENTS. All contributing project authors may | |
| * be found in the AUTHORS file in the root of the source tree. | |
| */ | |
| /****************************************************************** | |
| iLBC Speech Coder ANSI-C Source Code | |
| WebRtcIlbcfix_DoThePlc.c | |
| ******************************************************************/ | |
| #include "modules/audio_coding/codecs/ilbc/do_plc.h" | |
| #include "modules/audio_coding/codecs/ilbc/bw_expand.h" | |
| #include "modules/audio_coding/codecs/ilbc/comp_corr.h" | |
| #include "modules/audio_coding/codecs/ilbc/constants.h" | |
| #include "modules/audio_coding/codecs/ilbc/defines.h" | |
| /*----------------------------------------------------------------* | |
| * Packet loss concealment routine. Conceals a residual signal | |
| * and LP parameters. If no packet loss, update state. | |
| *---------------------------------------------------------------*/ | |
| void WebRtcIlbcfix_DoThePlc( | |
| int16_t *PLCresidual, /* (o) concealed residual */ | |
| int16_t *PLClpc, /* (o) concealed LP parameters */ | |
| int16_t PLI, /* (i) packet loss indicator | |
| 0 - no PL, 1 = PL */ | |
| int16_t *decresidual, /* (i) decoded residual */ | |
| int16_t *lpc, /* (i) decoded LPC (only used for no PL) */ | |
| size_t inlag, /* (i) pitch lag */ | |
| IlbcDecoder *iLBCdec_inst | |
| /* (i/o) decoder instance */ | |
| ){ | |
| size_t i; | |
| int32_t cross, ener, cross_comp, ener_comp = 0; | |
| int32_t measure, maxMeasure, energy; | |
| int32_t noise_energy_threshold_30dB; | |
| int16_t max, crossSquareMax, crossSquare; | |
| size_t j, lag, randlag; | |
| int16_t tmp1, tmp2; | |
| int16_t shift1, shift2, shift3, shiftMax; | |
| int16_t scale3; | |
| size_t corrLen; | |
| int32_t tmpW32, tmp2W32; | |
| int16_t use_gain; | |
| int16_t tot_gain; | |
| int16_t max_perSquare; | |
| int16_t scale1, scale2; | |
| int16_t totscale; | |
| int32_t nom; | |
| int16_t denom; | |
| int16_t pitchfact; | |
| size_t use_lag; | |
| int ind; | |
| int16_t randvec[BLOCKL_MAX]; | |
| /* Packet Loss */ | |
| if (PLI == 1) { | |
| (*iLBCdec_inst).consPLICount += 1; | |
| /* if previous frame not lost, | |
| determine pitch pred. gain */ | |
| if (iLBCdec_inst->prevPLI != 1) { | |
| /* Maximum 60 samples are correlated, preserve as high accuracy | |
| as possible without getting overflow */ | |
| max = WebRtcSpl_MaxAbsValueW16((*iLBCdec_inst).prevResidual, | |
| iLBCdec_inst->blockl); | |
| scale3 = (WebRtcSpl_GetSizeInBits(max)<<1) - 25; | |
| if (scale3 < 0) { | |
| scale3 = 0; | |
| } | |
| /* Store scale for use when interpolating between the | |
| * concealment and the received packet */ | |
| iLBCdec_inst->prevScale = scale3; | |
| /* Search around the previous lag +/-3 to find the | |
| best pitch period */ | |
| lag = inlag - 3; | |
| /* Guard against getting outside the frame */ | |
| corrLen = (size_t)WEBRTC_SPL_MIN(60, iLBCdec_inst->blockl-(inlag+3)); | |
| WebRtcIlbcfix_CompCorr( &cross, &ener, | |
| iLBCdec_inst->prevResidual, lag, iLBCdec_inst->blockl, corrLen, scale3); | |
| /* Normalize and store cross^2 and the number of shifts */ | |
| shiftMax = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_ABS_W32(cross))-15; | |
| crossSquareMax = (int16_t)(( | |
| (int16_t)WEBRTC_SPL_SHIFT_W32(cross, -shiftMax) * | |
| (int16_t)WEBRTC_SPL_SHIFT_W32(cross, -shiftMax)) >> 15); | |
| for (j=inlag-2;j<=inlag+3;j++) { | |
| WebRtcIlbcfix_CompCorr( &cross_comp, &ener_comp, | |
| iLBCdec_inst->prevResidual, j, iLBCdec_inst->blockl, corrLen, scale3); | |
| /* Use the criteria (corr*corr)/energy to compare if | |
| this lag is better or not. To avoid the division, | |
| do a cross multiplication */ | |
| shift1 = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_ABS_W32(cross_comp))-15; | |
| crossSquare = (int16_t)(( | |
| (int16_t)WEBRTC_SPL_SHIFT_W32(cross_comp, -shift1) * | |
| (int16_t)WEBRTC_SPL_SHIFT_W32(cross_comp, -shift1)) >> 15); | |
| shift2 = WebRtcSpl_GetSizeInBits(ener)-15; | |
| measure = (int16_t)WEBRTC_SPL_SHIFT_W32(ener, -shift2) * crossSquare; | |
| shift3 = WebRtcSpl_GetSizeInBits(ener_comp)-15; | |
| maxMeasure = (int16_t)WEBRTC_SPL_SHIFT_W32(ener_comp, -shift3) * | |
| crossSquareMax; | |
| /* Calculate shift value, so that the two measures can | |
| be put in the same Q domain */ | |
| if(2 * shiftMax + shift3 > 2 * shift1 + shift2) { | |
| tmp1 = | |
| WEBRTC_SPL_MIN(31, 2 * shiftMax + shift3 - 2 * shift1 - shift2); | |
| tmp2 = 0; | |
| } else { | |
| tmp1 = 0; | |
| tmp2 = | |
| WEBRTC_SPL_MIN(31, 2 * shift1 + shift2 - 2 * shiftMax - shift3); | |
| } | |
| if ((measure>>tmp1) > (maxMeasure>>tmp2)) { | |
| /* New lag is better => record lag, measure and domain */ | |
| lag = j; | |
| crossSquareMax = crossSquare; | |
| cross = cross_comp; | |
| shiftMax = shift1; | |
| ener = ener_comp; | |
| } | |
| } | |
| /* Calculate the periodicity for the lag with the maximum correlation. | |
| Definition of the periodicity: | |
| abs(corr(vec1, vec2))/(sqrt(energy(vec1))*sqrt(energy(vec2))) | |
| Work in the Square domain to simplify the calculations | |
| max_perSquare is less than 1 (in Q15) | |
| */ | |
| tmp2W32=WebRtcSpl_DotProductWithScale(&iLBCdec_inst->prevResidual[iLBCdec_inst->blockl-corrLen], | |
| &iLBCdec_inst->prevResidual[iLBCdec_inst->blockl-corrLen], | |
| corrLen, scale3); | |
| if ((tmp2W32>0)&&(ener_comp>0)) { | |
| /* norm energies to int16_t, compute the product of the energies and | |
| use the upper int16_t as the denominator */ | |
| scale1=(int16_t)WebRtcSpl_NormW32(tmp2W32)-16; | |
| tmp1=(int16_t)WEBRTC_SPL_SHIFT_W32(tmp2W32, scale1); | |
| scale2=(int16_t)WebRtcSpl_NormW32(ener)-16; | |
| tmp2=(int16_t)WEBRTC_SPL_SHIFT_W32(ener, scale2); | |
| denom = (int16_t)((tmp1 * tmp2) >> 16); /* in Q(scale1+scale2-16) */ | |
| /* Square the cross correlation and norm it such that max_perSquare | |
| will be in Q15 after the division */ | |
| totscale = scale1+scale2-1; | |
| tmp1 = (int16_t)WEBRTC_SPL_SHIFT_W32(cross, (totscale>>1)); | |
| tmp2 = (int16_t)WEBRTC_SPL_SHIFT_W32(cross, totscale-(totscale>>1)); | |
| nom = tmp1 * tmp2; | |
| max_perSquare = (int16_t)WebRtcSpl_DivW32W16(nom, denom); | |
| } else { | |
| max_perSquare = 0; | |
| } | |
| } | |
| /* previous frame lost, use recorded lag and gain */ | |
| else { | |
| lag = iLBCdec_inst->prevLag; | |
| max_perSquare = iLBCdec_inst->perSquare; | |
| } | |
| /* Attenuate signal and scale down pitch pred gain if | |
| several frames lost consecutively */ | |
| use_gain = 32767; /* 1.0 in Q15 */ | |
| if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>320) { | |
| use_gain = 29491; /* 0.9 in Q15 */ | |
| } else if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>640) { | |
| use_gain = 22938; /* 0.7 in Q15 */ | |
| } else if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>960) { | |
| use_gain = 16384; /* 0.5 in Q15 */ | |
| } else if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>1280) { | |
| use_gain = 0; /* 0.0 in Q15 */ | |
| } | |
| /* Compute mixing factor of picth repeatition and noise: | |
| for max_per>0.7 set periodicity to 1.0 | |
| 0.4<max_per<0.7 set periodicity to (maxper-0.4)/0.7-0.4) | |
| max_per<0.4 set periodicity to 0.0 | |
| */ | |
| if (max_perSquare>7868) { /* periodicity > 0.7 (0.7^4=0.2401 in Q15) */ | |
| pitchfact = 32767; | |
| } else if (max_perSquare>839) { /* 0.4 < periodicity < 0.7 (0.4^4=0.0256 in Q15) */ | |
| /* find best index and interpolate from that */ | |
| ind = 5; | |
| while ((max_perSquare<WebRtcIlbcfix_kPlcPerSqr[ind])&&(ind>0)) { | |
| ind--; | |
| } | |
| /* pitch fact is approximated by first order */ | |
| tmpW32 = (int32_t)WebRtcIlbcfix_kPlcPitchFact[ind] + | |
| ((WebRtcIlbcfix_kPlcPfSlope[ind] * | |
| (max_perSquare - WebRtcIlbcfix_kPlcPerSqr[ind])) >> 11); | |
| pitchfact = (int16_t)WEBRTC_SPL_MIN(tmpW32, 32767); /* guard against overflow */ | |
| } else { /* periodicity < 0.4 */ | |
| pitchfact = 0; | |
| } | |
| /* avoid repetition of same pitch cycle (buzzyness) */ | |
| use_lag = lag; | |
| if (lag<80) { | |
| use_lag = 2*lag; | |
| } | |
| /* compute concealed residual */ | |
| noise_energy_threshold_30dB = (int32_t)iLBCdec_inst->blockl * 900; | |
| energy = 0; | |
| for (i=0; i<iLBCdec_inst->blockl; i++) { | |
| /* noise component - 52 < randlagFIX < 117 */ | |
| iLBCdec_inst->seed = (int16_t)(iLBCdec_inst->seed * 31821 + 13849); | |
| randlag = 53 + (iLBCdec_inst->seed & 63); | |
| if (randlag > i) { | |
| randvec[i] = | |
| iLBCdec_inst->prevResidual[iLBCdec_inst->blockl + i - randlag]; | |
| } else { | |
| randvec[i] = iLBCdec_inst->prevResidual[i - randlag]; | |
| } | |
| /* pitch repeatition component */ | |
| if (use_lag > i) { | |
| PLCresidual[i] = | |
| iLBCdec_inst->prevResidual[iLBCdec_inst->blockl + i - use_lag]; | |
| } else { | |
| PLCresidual[i] = PLCresidual[i - use_lag]; | |
| } | |
| /* Attinuate total gain for each 10 ms */ | |
| if (i<80) { | |
| tot_gain=use_gain; | |
| } else if (i<160) { | |
| tot_gain = (int16_t)((31130 * use_gain) >> 15); /* 0.95*use_gain */ | |
| } else { | |
| tot_gain = (int16_t)((29491 * use_gain) >> 15); /* 0.9*use_gain */ | |
| } | |
| /* mix noise and pitch repeatition */ | |
| PLCresidual[i] = (int16_t)((tot_gain * | |
| ((pitchfact * PLCresidual[i] + (32767 - pitchfact) * randvec[i] + | |
| 16384) >> 15)) >> 15); | |
| /* Compute energy until threshold for noise energy is reached */ | |
| if (energy < noise_energy_threshold_30dB) { | |
| energy += PLCresidual[i] * PLCresidual[i]; | |
| } | |
| } | |
| /* less than 30 dB, use only noise */ | |
| if (energy < noise_energy_threshold_30dB) { | |
| for (i=0; i<iLBCdec_inst->blockl; i++) { | |
| PLCresidual[i] = randvec[i]; | |
| } | |
| } | |
| /* use the old LPC */ | |
| WEBRTC_SPL_MEMCPY_W16(PLClpc, (*iLBCdec_inst).prevLpc, LPC_FILTERORDER+1); | |
| /* Update state in case there are multiple frame losses */ | |
| iLBCdec_inst->prevLag = lag; | |
| iLBCdec_inst->perSquare = max_perSquare; | |
| } | |
| /* no packet loss, copy input */ | |
| else { | |
| WEBRTC_SPL_MEMCPY_W16(PLCresidual, decresidual, iLBCdec_inst->blockl); | |
| WEBRTC_SPL_MEMCPY_W16(PLClpc, lpc, (LPC_FILTERORDER+1)); | |
| iLBCdec_inst->consPLICount = 0; | |
| } | |
| /* update state */ | |
| iLBCdec_inst->prevPLI = PLI; | |
| WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->prevLpc, PLClpc, (LPC_FILTERORDER+1)); | |
| WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->prevResidual, PLCresidual, iLBCdec_inst->blockl); | |
| return; | |
| } |