| /* |
| * 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 "defines.h" |
| #include "constants.h" |
| #include "comp_corr.h" |
| #include "bw_expand.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; |
| 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 */ |
| 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); |
| |
| /* Shifting down the result one step extra to ensure that no overflow |
| will occur */ |
| energy += (PLCresidual[i] * PLCresidual[i]) >> |
| (iLBCdec_inst->prevScale + 1); |
| } |
| |
| /* less than 30 dB, use only noise */ |
| if (energy < (WEBRTC_SPL_SHIFT_W32(((int32_t)iLBCdec_inst->blockl*900),-(iLBCdec_inst->prevScale+1)))) { |
| energy = 0; |
| 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; |
| } |