summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/modules/audio_coding/codecs/ilbc/do_plc.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/libwebrtc/modules/audio_coding/codecs/ilbc/do_plc.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/audio_coding/codecs/ilbc/do_plc.c b/third_party/libwebrtc/modules/audio_coding/codecs/ilbc/do_plc.c
new file mode 100644
index 0000000000..9ca6ca48e9
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/codecs/ilbc/do_plc.c
@@ -0,0 +1,309 @@
+/*
+ * 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;
+}