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