niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
| 11 | /****************************************************************** |
| 12 | |
| 13 | iLBC Speech Coder ANSI-C Source Code |
| 14 | |
| 15 | WebRtcIlbcfix_DoThePlc.c |
| 16 | |
| 17 | ******************************************************************/ |
| 18 | |
Mirko Bonadei | 06c2aa9 | 2018-02-01 15:11:41 +0100 | [diff] [blame^] | 19 | #include "modules/audio_coding/codecs/ilbc/defines.h" |
| 20 | #include "modules/audio_coding/codecs/ilbc/constants.h" |
| 21 | #include "modules/audio_coding/codecs/ilbc/comp_corr.h" |
| 22 | #include "modules/audio_coding/codecs/ilbc/bw_expand.h" |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 23 | |
| 24 | /*----------------------------------------------------------------* |
| 25 | * Packet loss concealment routine. Conceals a residual signal |
| 26 | * and LP parameters. If no packet loss, update state. |
| 27 | *---------------------------------------------------------------*/ |
| 28 | |
| 29 | void WebRtcIlbcfix_DoThePlc( |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 30 | int16_t *PLCresidual, /* (o) concealed residual */ |
| 31 | int16_t *PLClpc, /* (o) concealed LP parameters */ |
| 32 | int16_t PLI, /* (i) packet loss indicator |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 33 | 0 - no PL, 1 = PL */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 34 | int16_t *decresidual, /* (i) decoded residual */ |
| 35 | int16_t *lpc, /* (i) decoded LPC (only used for no PL) */ |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 36 | size_t inlag, /* (i) pitch lag */ |
pbos@webrtc.org | eb54446 | 2014-12-17 15:23:29 +0000 | [diff] [blame] | 37 | IlbcDecoder *iLBCdec_inst |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 38 | /* (i/o) decoder instance */ |
| 39 | ){ |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 40 | size_t i; |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 41 | int32_t cross, ener, cross_comp, ener_comp = 0; |
| 42 | int32_t measure, maxMeasure, energy; |
| 43 | int16_t max, crossSquareMax, crossSquare; |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 44 | size_t j, lag, randlag; |
| 45 | int16_t tmp1, tmp2; |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 46 | int16_t shift1, shift2, shift3, shiftMax; |
| 47 | int16_t scale3; |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 48 | size_t corrLen; |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 49 | int32_t tmpW32, tmp2W32; |
| 50 | int16_t use_gain; |
| 51 | int16_t tot_gain; |
| 52 | int16_t max_perSquare; |
| 53 | int16_t scale1, scale2; |
| 54 | int16_t totscale; |
| 55 | int32_t nom; |
| 56 | int16_t denom; |
| 57 | int16_t pitchfact; |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 58 | size_t use_lag; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 59 | int ind; |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 60 | int16_t randvec[BLOCKL_MAX]; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 61 | |
| 62 | /* Packet Loss */ |
| 63 | if (PLI == 1) { |
| 64 | |
| 65 | (*iLBCdec_inst).consPLICount += 1; |
| 66 | |
| 67 | /* if previous frame not lost, |
| 68 | determine pitch pred. gain */ |
| 69 | |
| 70 | if (iLBCdec_inst->prevPLI != 1) { |
| 71 | |
| 72 | /* Maximum 60 samples are correlated, preserve as high accuracy |
| 73 | as possible without getting overflow */ |
pkasting | b297c5a | 2015-07-22 15:17:22 -0700 | [diff] [blame] | 74 | max = WebRtcSpl_MaxAbsValueW16((*iLBCdec_inst).prevResidual, |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 75 | iLBCdec_inst->blockl); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 76 | scale3 = (WebRtcSpl_GetSizeInBits(max)<<1) - 25; |
| 77 | if (scale3 < 0) { |
| 78 | scale3 = 0; |
| 79 | } |
| 80 | |
| 81 | /* Store scale for use when interpolating between the |
| 82 | * concealment and the received packet */ |
| 83 | iLBCdec_inst->prevScale = scale3; |
| 84 | |
| 85 | /* Search around the previous lag +/-3 to find the |
| 86 | best pitch period */ |
| 87 | lag = inlag - 3; |
| 88 | |
| 89 | /* Guard against getting outside the frame */ |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 90 | corrLen = (size_t)WEBRTC_SPL_MIN(60, iLBCdec_inst->blockl-(inlag+3)); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 91 | |
| 92 | WebRtcIlbcfix_CompCorr( &cross, &ener, |
| 93 | iLBCdec_inst->prevResidual, lag, iLBCdec_inst->blockl, corrLen, scale3); |
| 94 | |
| 95 | /* Normalize and store cross^2 and the number of shifts */ |
| 96 | shiftMax = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_ABS_W32(cross))-15; |
bjornv@webrtc.org | 2f6ae0d | 2015-03-01 19:50:41 +0000 | [diff] [blame] | 97 | crossSquareMax = (int16_t)(( |
| 98 | (int16_t)WEBRTC_SPL_SHIFT_W32(cross, -shiftMax) * |
| 99 | (int16_t)WEBRTC_SPL_SHIFT_W32(cross, -shiftMax)) >> 15); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 100 | |
| 101 | for (j=inlag-2;j<=inlag+3;j++) { |
| 102 | WebRtcIlbcfix_CompCorr( &cross_comp, &ener_comp, |
| 103 | iLBCdec_inst->prevResidual, j, iLBCdec_inst->blockl, corrLen, scale3); |
| 104 | |
| 105 | /* Use the criteria (corr*corr)/energy to compare if |
| 106 | this lag is better or not. To avoid the division, |
| 107 | do a cross multiplication */ |
| 108 | shift1 = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_ABS_W32(cross_comp))-15; |
bjornv@webrtc.org | 2f6ae0d | 2015-03-01 19:50:41 +0000 | [diff] [blame] | 109 | crossSquare = (int16_t)(( |
| 110 | (int16_t)WEBRTC_SPL_SHIFT_W32(cross_comp, -shift1) * |
| 111 | (int16_t)WEBRTC_SPL_SHIFT_W32(cross_comp, -shift1)) >> 15); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 112 | |
| 113 | shift2 = WebRtcSpl_GetSizeInBits(ener)-15; |
bjornv@webrtc.org | ba97ea6 | 2015-02-13 09:51:40 +0000 | [diff] [blame] | 114 | measure = (int16_t)WEBRTC_SPL_SHIFT_W32(ener, -shift2) * crossSquare; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 115 | |
| 116 | shift3 = WebRtcSpl_GetSizeInBits(ener_comp)-15; |
bjornv@webrtc.org | ba97ea6 | 2015-02-13 09:51:40 +0000 | [diff] [blame] | 117 | maxMeasure = (int16_t)WEBRTC_SPL_SHIFT_W32(ener_comp, -shift3) * |
| 118 | crossSquareMax; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 119 | |
| 120 | /* Calculate shift value, so that the two measures can |
| 121 | be put in the same Q domain */ |
kwiberg | 3fc8e8d | 2016-05-20 04:40:29 -0700 | [diff] [blame] | 122 | if(2 * shiftMax + shift3 > 2 * shift1 + shift2) { |
| 123 | tmp1 = |
| 124 | WEBRTC_SPL_MIN(31, 2 * shiftMax + shift3 - 2 * shift1 - shift2); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 125 | tmp2 = 0; |
| 126 | } else { |
| 127 | tmp1 = 0; |
kwiberg | 3fc8e8d | 2016-05-20 04:40:29 -0700 | [diff] [blame] | 128 | tmp2 = |
| 129 | WEBRTC_SPL_MIN(31, 2 * shift1 + shift2 - 2 * shiftMax - shift3); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 130 | } |
| 131 | |
| 132 | if ((measure>>tmp1) > (maxMeasure>>tmp2)) { |
| 133 | /* New lag is better => record lag, measure and domain */ |
| 134 | lag = j; |
| 135 | crossSquareMax = crossSquare; |
| 136 | cross = cross_comp; |
| 137 | shiftMax = shift1; |
| 138 | ener = ener_comp; |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | /* Calculate the periodicity for the lag with the maximum correlation. |
| 143 | |
| 144 | Definition of the periodicity: |
| 145 | abs(corr(vec1, vec2))/(sqrt(energy(vec1))*sqrt(energy(vec2))) |
| 146 | |
| 147 | Work in the Square domain to simplify the calculations |
| 148 | max_perSquare is less than 1 (in Q15) |
| 149 | */ |
| 150 | tmp2W32=WebRtcSpl_DotProductWithScale(&iLBCdec_inst->prevResidual[iLBCdec_inst->blockl-corrLen], |
| 151 | &iLBCdec_inst->prevResidual[iLBCdec_inst->blockl-corrLen], |
| 152 | corrLen, scale3); |
| 153 | |
| 154 | if ((tmp2W32>0)&&(ener_comp>0)) { |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 155 | /* norm energies to int16_t, compute the product of the energies and |
| 156 | use the upper int16_t as the denominator */ |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 157 | |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 158 | scale1=(int16_t)WebRtcSpl_NormW32(tmp2W32)-16; |
| 159 | tmp1=(int16_t)WEBRTC_SPL_SHIFT_W32(tmp2W32, scale1); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 160 | |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 161 | scale2=(int16_t)WebRtcSpl_NormW32(ener)-16; |
| 162 | tmp2=(int16_t)WEBRTC_SPL_SHIFT_W32(ener, scale2); |
bjornv@webrtc.org | 2f6ae0d | 2015-03-01 19:50:41 +0000 | [diff] [blame] | 163 | denom = (int16_t)((tmp1 * tmp2) >> 16); /* in Q(scale1+scale2-16) */ |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 164 | |
| 165 | /* Square the cross correlation and norm it such that max_perSquare |
| 166 | will be in Q15 after the division */ |
| 167 | |
| 168 | totscale = scale1+scale2-1; |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 169 | tmp1 = (int16_t)WEBRTC_SPL_SHIFT_W32(cross, (totscale>>1)); |
| 170 | tmp2 = (int16_t)WEBRTC_SPL_SHIFT_W32(cross, totscale-(totscale>>1)); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 171 | |
bjornv@webrtc.org | ba97ea6 | 2015-02-13 09:51:40 +0000 | [diff] [blame] | 172 | nom = tmp1 * tmp2; |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 173 | max_perSquare = (int16_t)WebRtcSpl_DivW32W16(nom, denom); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 174 | |
| 175 | } else { |
| 176 | max_perSquare = 0; |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | /* previous frame lost, use recorded lag and gain */ |
| 181 | |
| 182 | else { |
| 183 | lag = iLBCdec_inst->prevLag; |
| 184 | max_perSquare = iLBCdec_inst->perSquare; |
| 185 | } |
| 186 | |
| 187 | /* Attenuate signal and scale down pitch pred gain if |
| 188 | several frames lost consecutively */ |
| 189 | |
| 190 | use_gain = 32767; /* 1.0 in Q15 */ |
| 191 | |
| 192 | if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>320) { |
| 193 | use_gain = 29491; /* 0.9 in Q15 */ |
| 194 | } else if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>640) { |
| 195 | use_gain = 22938; /* 0.7 in Q15 */ |
| 196 | } else if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>960) { |
| 197 | use_gain = 16384; /* 0.5 in Q15 */ |
| 198 | } else if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>1280) { |
| 199 | use_gain = 0; /* 0.0 in Q15 */ |
| 200 | } |
| 201 | |
| 202 | /* Compute mixing factor of picth repeatition and noise: |
| 203 | for max_per>0.7 set periodicity to 1.0 |
| 204 | 0.4<max_per<0.7 set periodicity to (maxper-0.4)/0.7-0.4) |
| 205 | max_per<0.4 set periodicity to 0.0 |
| 206 | */ |
| 207 | |
| 208 | if (max_perSquare>7868) { /* periodicity > 0.7 (0.7^4=0.2401 in Q15) */ |
| 209 | pitchfact = 32767; |
| 210 | } else if (max_perSquare>839) { /* 0.4 < periodicity < 0.7 (0.4^4=0.0256 in Q15) */ |
| 211 | /* find best index and interpolate from that */ |
| 212 | ind = 5; |
| 213 | while ((max_perSquare<WebRtcIlbcfix_kPlcPerSqr[ind])&&(ind>0)) { |
| 214 | ind--; |
| 215 | } |
| 216 | /* pitch fact is approximated by first order */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 217 | tmpW32 = (int32_t)WebRtcIlbcfix_kPlcPitchFact[ind] + |
bjornv@webrtc.org | 2f6ae0d | 2015-03-01 19:50:41 +0000 | [diff] [blame] | 218 | ((WebRtcIlbcfix_kPlcPfSlope[ind] * |
| 219 | (max_perSquare - WebRtcIlbcfix_kPlcPerSqr[ind])) >> 11); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 220 | |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 221 | pitchfact = (int16_t)WEBRTC_SPL_MIN(tmpW32, 32767); /* guard against overflow */ |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 222 | |
| 223 | } else { /* periodicity < 0.4 */ |
| 224 | pitchfact = 0; |
| 225 | } |
| 226 | |
| 227 | /* avoid repetition of same pitch cycle (buzzyness) */ |
| 228 | use_lag = lag; |
| 229 | if (lag<80) { |
| 230 | use_lag = 2*lag; |
| 231 | } |
| 232 | |
| 233 | /* compute concealed residual */ |
| 234 | energy = 0; |
| 235 | |
| 236 | for (i=0; i<iLBCdec_inst->blockl; i++) { |
| 237 | |
| 238 | /* noise component - 52 < randlagFIX < 117 */ |
bjornv@webrtc.org | ba97ea6 | 2015-02-13 09:51:40 +0000 | [diff] [blame] | 239 | iLBCdec_inst->seed = (int16_t)(iLBCdec_inst->seed * 31821 + 13849); |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 240 | randlag = 53 + (iLBCdec_inst->seed & 63); |
Peter Kasting | f045e4d | 2015-06-10 21:15:38 -0700 | [diff] [blame] | 241 | if (randlag > i) { |
| 242 | randvec[i] = |
| 243 | iLBCdec_inst->prevResidual[iLBCdec_inst->blockl + i - randlag]; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 244 | } else { |
Peter Kasting | f045e4d | 2015-06-10 21:15:38 -0700 | [diff] [blame] | 245 | randvec[i] = iLBCdec_inst->prevResidual[i - randlag]; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 246 | } |
| 247 | |
| 248 | /* pitch repeatition component */ |
Peter Kasting | f045e4d | 2015-06-10 21:15:38 -0700 | [diff] [blame] | 249 | if (use_lag > i) { |
| 250 | PLCresidual[i] = |
| 251 | iLBCdec_inst->prevResidual[iLBCdec_inst->blockl + i - use_lag]; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 252 | } else { |
Peter Kasting | f045e4d | 2015-06-10 21:15:38 -0700 | [diff] [blame] | 253 | PLCresidual[i] = PLCresidual[i - use_lag]; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 254 | } |
| 255 | |
| 256 | /* Attinuate total gain for each 10 ms */ |
| 257 | if (i<80) { |
| 258 | tot_gain=use_gain; |
| 259 | } else if (i<160) { |
bjornv@webrtc.org | 2f6ae0d | 2015-03-01 19:50:41 +0000 | [diff] [blame] | 260 | tot_gain = (int16_t)((31130 * use_gain) >> 15); /* 0.95*use_gain */ |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 261 | } else { |
bjornv@webrtc.org | 2f6ae0d | 2015-03-01 19:50:41 +0000 | [diff] [blame] | 262 | tot_gain = (int16_t)((29491 * use_gain) >> 15); /* 0.9*use_gain */ |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 263 | } |
| 264 | |
| 265 | |
| 266 | /* mix noise and pitch repeatition */ |
bjornv@webrtc.org | 2f6ae0d | 2015-03-01 19:50:41 +0000 | [diff] [blame] | 267 | PLCresidual[i] = (int16_t)((tot_gain * |
| 268 | ((pitchfact * PLCresidual[i] + (32767 - pitchfact) * randvec[i] + |
| 269 | 16384) >> 15)) >> 15); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 270 | |
| 271 | /* Shifting down the result one step extra to ensure that no overflow |
| 272 | will occur */ |
bjornv@webrtc.org | 2f6ae0d | 2015-03-01 19:50:41 +0000 | [diff] [blame] | 273 | energy += (PLCresidual[i] * PLCresidual[i]) >> |
| 274 | (iLBCdec_inst->prevScale + 1); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 275 | } |
| 276 | |
| 277 | /* less than 30 dB, use only noise */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 278 | if (energy < (WEBRTC_SPL_SHIFT_W32(((int32_t)iLBCdec_inst->blockl*900),-(iLBCdec_inst->prevScale+1)))) { |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 279 | energy = 0; |
| 280 | for (i=0; i<iLBCdec_inst->blockl; i++) { |
| 281 | PLCresidual[i] = randvec[i]; |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | /* use the old LPC */ |
| 286 | WEBRTC_SPL_MEMCPY_W16(PLClpc, (*iLBCdec_inst).prevLpc, LPC_FILTERORDER+1); |
| 287 | |
| 288 | /* Update state in case there are multiple frame losses */ |
| 289 | iLBCdec_inst->prevLag = lag; |
| 290 | iLBCdec_inst->perSquare = max_perSquare; |
| 291 | } |
| 292 | |
| 293 | /* no packet loss, copy input */ |
| 294 | |
| 295 | else { |
| 296 | WEBRTC_SPL_MEMCPY_W16(PLCresidual, decresidual, iLBCdec_inst->blockl); |
| 297 | WEBRTC_SPL_MEMCPY_W16(PLClpc, lpc, (LPC_FILTERORDER+1)); |
| 298 | iLBCdec_inst->consPLICount = 0; |
| 299 | } |
| 300 | |
| 301 | /* update state */ |
| 302 | iLBCdec_inst->prevPLI = PLI; |
| 303 | WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->prevLpc, PLClpc, (LPC_FILTERORDER+1)); |
| 304 | WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->prevResidual, PLCresidual, iLBCdec_inst->blockl); |
| 305 | |
| 306 | return; |
| 307 | } |