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
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"
23
24 /*----------------------------------------------------------------*
25 * Packet loss concealment routine. Conceals a residual signal
26 * and LP parameters. If no packet loss, update state.
27 *---------------------------------------------------------------*/
28
WebRtcIlbcfix_DoThePlc(int16_t * PLCresidual,int16_t * PLClpc,int16_t PLI,int16_t * decresidual,int16_t * lpc,size_t inlag,IlbcDecoder * iLBCdec_inst)29 void WebRtcIlbcfix_DoThePlc(
30 int16_t *PLCresidual, /* (o) concealed residual */
31 int16_t *PLClpc, /* (o) concealed LP parameters */
32 int16_t PLI, /* (i) packet loss indicator
33 0 - no PL, 1 = PL */
34 int16_t *decresidual, /* (i) decoded residual */
35 int16_t *lpc, /* (i) decoded LPC (only used for no PL) */
36 size_t inlag, /* (i) pitch lag */
37 IlbcDecoder *iLBCdec_inst
38 /* (i/o) decoder instance */
39 ){
40 size_t i;
41 int32_t cross, ener, cross_comp, ener_comp = 0;
42 int32_t measure, maxMeasure, energy;
43 int32_t noise_energy_threshold_30dB;
44 int16_t max, crossSquareMax, crossSquare;
45 size_t j, lag, randlag;
46 int16_t tmp1, tmp2;
47 int16_t shift1, shift2, shift3, shiftMax;
48 int16_t scale3;
49 size_t corrLen;
50 int32_t tmpW32, tmp2W32;
51 int16_t use_gain;
52 int16_t tot_gain;
53 int16_t max_perSquare;
54 int16_t scale1, scale2;
55 int16_t totscale;
56 int32_t nom;
57 int16_t denom;
58 int16_t pitchfact;
59 size_t use_lag;
60 int ind;
61 int16_t randvec[BLOCKL_MAX];
62
63 /* Packet Loss */
64 if (PLI == 1) {
65
66 (*iLBCdec_inst).consPLICount += 1;
67
68 /* if previous frame not lost,
69 determine pitch pred. gain */
70
71 if (iLBCdec_inst->prevPLI != 1) {
72
73 /* Maximum 60 samples are correlated, preserve as high accuracy
74 as possible without getting overflow */
75 max = WebRtcSpl_MaxAbsValueW16((*iLBCdec_inst).prevResidual,
76 iLBCdec_inst->blockl);
77 scale3 = (WebRtcSpl_GetSizeInBits(max)<<1) - 25;
78 if (scale3 < 0) {
79 scale3 = 0;
80 }
81
82 /* Store scale for use when interpolating between the
83 * concealment and the received packet */
84 iLBCdec_inst->prevScale = scale3;
85
86 /* Search around the previous lag +/-3 to find the
87 best pitch period */
88 lag = inlag - 3;
89
90 /* Guard against getting outside the frame */
91 corrLen = (size_t)WEBRTC_SPL_MIN(60, iLBCdec_inst->blockl-(inlag+3));
92
93 WebRtcIlbcfix_CompCorr( &cross, &ener,
94 iLBCdec_inst->prevResidual, lag, iLBCdec_inst->blockl, corrLen, scale3);
95
96 /* Normalize and store cross^2 and the number of shifts */
97 shiftMax = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_ABS_W32(cross))-15;
98 crossSquareMax = (int16_t)((
99 (int16_t)WEBRTC_SPL_SHIFT_W32(cross, -shiftMax) *
100 (int16_t)WEBRTC_SPL_SHIFT_W32(cross, -shiftMax)) >> 15);
101
102 for (j=inlag-2;j<=inlag+3;j++) {
103 WebRtcIlbcfix_CompCorr( &cross_comp, &ener_comp,
104 iLBCdec_inst->prevResidual, j, iLBCdec_inst->blockl, corrLen, scale3);
105
106 /* Use the criteria (corr*corr)/energy to compare if
107 this lag is better or not. To avoid the division,
108 do a cross multiplication */
109 shift1 = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_ABS_W32(cross_comp))-15;
110 crossSquare = (int16_t)((
111 (int16_t)WEBRTC_SPL_SHIFT_W32(cross_comp, -shift1) *
112 (int16_t)WEBRTC_SPL_SHIFT_W32(cross_comp, -shift1)) >> 15);
113
114 shift2 = WebRtcSpl_GetSizeInBits(ener)-15;
115 measure = (int16_t)WEBRTC_SPL_SHIFT_W32(ener, -shift2) * crossSquare;
116
117 shift3 = WebRtcSpl_GetSizeInBits(ener_comp)-15;
118 maxMeasure = (int16_t)WEBRTC_SPL_SHIFT_W32(ener_comp, -shift3) *
119 crossSquareMax;
120
121 /* Calculate shift value, so that the two measures can
122 be put in the same Q domain */
123 if(2 * shiftMax + shift3 > 2 * shift1 + shift2) {
124 tmp1 =
125 WEBRTC_SPL_MIN(31, 2 * shiftMax + shift3 - 2 * shift1 - shift2);
126 tmp2 = 0;
127 } else {
128 tmp1 = 0;
129 tmp2 =
130 WEBRTC_SPL_MIN(31, 2 * shift1 + shift2 - 2 * shiftMax - shift3);
131 }
132
133 if ((measure>>tmp1) > (maxMeasure>>tmp2)) {
134 /* New lag is better => record lag, measure and domain */
135 lag = j;
136 crossSquareMax = crossSquare;
137 cross = cross_comp;
138 shiftMax = shift1;
139 ener = ener_comp;
140 }
141 }
142
143 /* Calculate the periodicity for the lag with the maximum correlation.
144
145 Definition of the periodicity:
146 abs(corr(vec1, vec2))/(sqrt(energy(vec1))*sqrt(energy(vec2)))
147
148 Work in the Square domain to simplify the calculations
149 max_perSquare is less than 1 (in Q15)
150 */
151 tmp2W32=WebRtcSpl_DotProductWithScale(&iLBCdec_inst->prevResidual[iLBCdec_inst->blockl-corrLen],
152 &iLBCdec_inst->prevResidual[iLBCdec_inst->blockl-corrLen],
153 corrLen, scale3);
154
155 if ((tmp2W32>0)&&(ener_comp>0)) {
156 /* norm energies to int16_t, compute the product of the energies and
157 use the upper int16_t as the denominator */
158
159 scale1=(int16_t)WebRtcSpl_NormW32(tmp2W32)-16;
160 tmp1=(int16_t)WEBRTC_SPL_SHIFT_W32(tmp2W32, scale1);
161
162 scale2=(int16_t)WebRtcSpl_NormW32(ener)-16;
163 tmp2=(int16_t)WEBRTC_SPL_SHIFT_W32(ener, scale2);
164 denom = (int16_t)((tmp1 * tmp2) >> 16); /* in Q(scale1+scale2-16) */
165
166 /* Square the cross correlation and norm it such that max_perSquare
167 will be in Q15 after the division */
168
169 totscale = scale1+scale2-1;
170 tmp1 = (int16_t)WEBRTC_SPL_SHIFT_W32(cross, (totscale>>1));
171 tmp2 = (int16_t)WEBRTC_SPL_SHIFT_W32(cross, totscale-(totscale>>1));
172
173 nom = tmp1 * tmp2;
174 max_perSquare = (int16_t)WebRtcSpl_DivW32W16(nom, denom);
175
176 } else {
177 max_perSquare = 0;
178 }
179 }
180
181 /* previous frame lost, use recorded lag and gain */
182
183 else {
184 lag = iLBCdec_inst->prevLag;
185 max_perSquare = iLBCdec_inst->perSquare;
186 }
187
188 /* Attenuate signal and scale down pitch pred gain if
189 several frames lost consecutively */
190
191 use_gain = 32767; /* 1.0 in Q15 */
192
193 if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>320) {
194 use_gain = 29491; /* 0.9 in Q15 */
195 } else if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>640) {
196 use_gain = 22938; /* 0.7 in Q15 */
197 } else if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>960) {
198 use_gain = 16384; /* 0.5 in Q15 */
199 } else if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>1280) {
200 use_gain = 0; /* 0.0 in Q15 */
201 }
202
203 /* Compute mixing factor of picth repeatition and noise:
204 for max_per>0.7 set periodicity to 1.0
205 0.4<max_per<0.7 set periodicity to (maxper-0.4)/0.7-0.4)
206 max_per<0.4 set periodicity to 0.0
207 */
208
209 if (max_perSquare>7868) { /* periodicity > 0.7 (0.7^4=0.2401 in Q15) */
210 pitchfact = 32767;
211 } else if (max_perSquare>839) { /* 0.4 < periodicity < 0.7 (0.4^4=0.0256 in Q15) */
212 /* find best index and interpolate from that */
213 ind = 5;
214 while ((max_perSquare<WebRtcIlbcfix_kPlcPerSqr[ind])&&(ind>0)) {
215 ind--;
216 }
217 /* pitch fact is approximated by first order */
218 tmpW32 = (int32_t)WebRtcIlbcfix_kPlcPitchFact[ind] +
219 ((WebRtcIlbcfix_kPlcPfSlope[ind] *
220 (max_perSquare - WebRtcIlbcfix_kPlcPerSqr[ind])) >> 11);
221
222 pitchfact = (int16_t)WEBRTC_SPL_MIN(tmpW32, 32767); /* guard against overflow */
223
224 } else { /* periodicity < 0.4 */
225 pitchfact = 0;
226 }
227
228 /* avoid repetition of same pitch cycle (buzzyness) */
229 use_lag = lag;
230 if (lag<80) {
231 use_lag = 2*lag;
232 }
233
234 /* compute concealed residual */
235 noise_energy_threshold_30dB = (int32_t)iLBCdec_inst->blockl * 900;
236 energy = 0;
237 for (i=0; i<iLBCdec_inst->blockl; i++) {
238
239 /* noise component - 52 < randlagFIX < 117 */
240 iLBCdec_inst->seed = (int16_t)(iLBCdec_inst->seed * 31821 + 13849);
241 randlag = 53 + (iLBCdec_inst->seed & 63);
242 if (randlag > i) {
243 randvec[i] =
244 iLBCdec_inst->prevResidual[iLBCdec_inst->blockl + i - randlag];
245 } else {
246 randvec[i] = iLBCdec_inst->prevResidual[i - randlag];
247 }
248
249 /* pitch repeatition component */
250 if (use_lag > i) {
251 PLCresidual[i] =
252 iLBCdec_inst->prevResidual[iLBCdec_inst->blockl + i - use_lag];
253 } else {
254 PLCresidual[i] = PLCresidual[i - use_lag];
255 }
256
257 /* Attinuate total gain for each 10 ms */
258 if (i<80) {
259 tot_gain=use_gain;
260 } else if (i<160) {
261 tot_gain = (int16_t)((31130 * use_gain) >> 15); /* 0.95*use_gain */
262 } else {
263 tot_gain = (int16_t)((29491 * use_gain) >> 15); /* 0.9*use_gain */
264 }
265
266
267 /* mix noise and pitch repeatition */
268 PLCresidual[i] = (int16_t)((tot_gain *
269 ((pitchfact * PLCresidual[i] + (32767 - pitchfact) * randvec[i] +
270 16384) >> 15)) >> 15);
271
272 /* Compute energy until threshold for noise energy is reached */
273 if (energy < noise_energy_threshold_30dB) {
274 energy += PLCresidual[i] * PLCresidual[i];
275 }
276 }
277
278 /* less than 30 dB, use only noise */
279 if (energy < noise_energy_threshold_30dB) {
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 }
308