xref: /aosp_15_r20/external/webrtc/modules/audio_coding/codecs/ilbc/enhancer_interface.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_EnhancerInterface.c
16 
17 ******************************************************************/
18 
19 #include "modules/audio_coding/codecs/ilbc/enhancer_interface.h"
20 
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "modules/audio_coding/codecs/ilbc/constants.h"
25 #include "modules/audio_coding/codecs/ilbc/defines.h"
26 #include "modules/audio_coding/codecs/ilbc/enhancer.h"
27 #include "modules/audio_coding/codecs/ilbc/hp_output.h"
28 #include "modules/audio_coding/codecs/ilbc/xcorr_coef.h"
29 
30 
31 
32 /*----------------------------------------------------------------*
33  * interface for enhancer
34  *---------------------------------------------------------------*/
35 
36 size_t  // (o) Estimated lag in end of in[]
WebRtcIlbcfix_EnhancerInterface(int16_t * out,const int16_t * in,IlbcDecoder * iLBCdec_inst)37     WebRtcIlbcfix_EnhancerInterface(
38         int16_t* out,                 // (o) enhanced signal
39         const int16_t* in,            // (i) unenhanced signal
40         IlbcDecoder* iLBCdec_inst) {  // (i) buffers etc
41   size_t iblock;
42   size_t lag=20, tlag=20;
43   size_t inLen=iLBCdec_inst->blockl+120;
44   int16_t scale, scale1;
45   size_t plc_blockl;
46   int16_t *enh_buf;
47   size_t *enh_period;
48   int32_t tmp1, tmp2, max;
49   size_t new_blocks;
50   int16_t *enh_bufPtr1;
51   size_t i;
52   size_t k;
53   int16_t EnChange;
54   int16_t SqrtEnChange;
55   int16_t inc;
56   int16_t win;
57   int16_t *tmpW16ptr;
58   size_t startPos;
59   int16_t *plc_pred;
60   const int16_t *target, *regressor;
61   int16_t max16;
62   int shifts;
63   int32_t ener;
64   int16_t enerSh;
65   int16_t corrSh;
66   size_t ind;
67   int16_t sh;
68   size_t start, stop;
69   /* Stack based */
70   int16_t totsh[3];
71   int16_t downsampled[(BLOCKL_MAX+120)>>1]; /* length 180 */
72   int32_t corr32[50];
73   int32_t corrmax[3];
74   int16_t corr16[3];
75   int16_t en16[3];
76   size_t lagmax[3];
77 
78   plc_pred = downsampled; /* Reuse memory since plc_pred[ENH_BLOCKL] and
79                               downsampled are non overlapping */
80   enh_buf=iLBCdec_inst->enh_buf;
81   enh_period=iLBCdec_inst->enh_period;
82 
83   /* Copy in the new data into the enhancer buffer */
84   memmove(enh_buf, &enh_buf[iLBCdec_inst->blockl],
85           (ENH_BUFL - iLBCdec_inst->blockl) * sizeof(*enh_buf));
86 
87   WEBRTC_SPL_MEMCPY_W16(&enh_buf[ENH_BUFL-iLBCdec_inst->blockl], in,
88                         iLBCdec_inst->blockl);
89 
90   /* Set variables that are dependent on frame size */
91   if (iLBCdec_inst->mode==30) {
92     plc_blockl=ENH_BLOCKL;
93     new_blocks=3;
94     startPos=320;  /* Start position for enhancement
95                      (640-new_blocks*ENH_BLOCKL-80) */
96   } else {
97     plc_blockl=40;
98     new_blocks=2;
99     startPos=440;  /* Start position for enhancement
100                     (640-new_blocks*ENH_BLOCKL-40) */
101   }
102 
103   /* Update the pitch prediction for each enhancer block, move the old ones */
104   memmove(enh_period, &enh_period[new_blocks],
105           (ENH_NBLOCKS_TOT - new_blocks) * sizeof(*enh_period));
106 
107   WebRtcSpl_DownsampleFast(
108       enh_buf+ENH_BUFL-inLen,    /* Input samples */
109       inLen + ENH_BUFL_FILTEROVERHEAD,
110       downsampled,
111       inLen / 2,
112       (int16_t*)WebRtcIlbcfix_kLpFiltCoefs,  /* Coefficients in Q12 */
113       FILTERORDER_DS_PLUS1,    /* Length of filter (order-1) */
114       FACTOR_DS,
115       DELAY_DS);
116 
117   /* Estimate the pitch in the down sampled domain. */
118   for(iblock = 0; iblock<new_blocks; iblock++){
119 
120     /* references */
121     target = downsampled + 60 + iblock * ENH_BLOCKL_HALF;
122     regressor = target - 10;
123 
124     /* scaling */
125     max16 = WebRtcSpl_MaxAbsValueW16(&regressor[-50], ENH_BLOCKL_HALF + 50 - 1);
126     shifts = WebRtcSpl_GetSizeInBits((uint32_t)(max16 * max16)) - 25;
127     shifts = WEBRTC_SPL_MAX(0, shifts);
128 
129     /* compute cross correlation */
130     WebRtcSpl_CrossCorrelation(corr32, target, regressor, ENH_BLOCKL_HALF, 50,
131                                shifts, -1);
132 
133     /* Find 3 highest correlations that should be compared for the
134        highest (corr*corr)/ener */
135 
136     for (i=0;i<2;i++) {
137       lagmax[i] = WebRtcSpl_MaxIndexW32(corr32, 50);
138       corrmax[i] = corr32[lagmax[i]];
139       start = WEBRTC_SPL_MAX(2, lagmax[i]) - 2;
140       stop = WEBRTC_SPL_MIN(47, lagmax[i]) + 2;
141       for (k = start; k <= stop; k++) {
142         corr32[k] = 0;
143       }
144     }
145     lagmax[2] = WebRtcSpl_MaxIndexW32(corr32, 50);
146     corrmax[2] = corr32[lagmax[2]];
147 
148     /* Calculate normalized corr^2 and ener */
149     for (i=0;i<3;i++) {
150       corrSh = 15-WebRtcSpl_GetSizeInBits(corrmax[i]);
151       ener = WebRtcSpl_DotProductWithScale(regressor - lagmax[i],
152                                            regressor - lagmax[i],
153                                            ENH_BLOCKL_HALF, shifts);
154       enerSh = 15-WebRtcSpl_GetSizeInBits(ener);
155       corr16[i] = (int16_t)WEBRTC_SPL_SHIFT_W32(corrmax[i], corrSh);
156       corr16[i] = (int16_t)((corr16[i] * corr16[i]) >> 16);
157       en16[i] = (int16_t)WEBRTC_SPL_SHIFT_W32(ener, enerSh);
158       totsh[i] = enerSh - 2 * corrSh;
159     }
160 
161     /* Compare lagmax[0..3] for the (corr^2)/ener criteria */
162     ind = 0;
163     for (i=1; i<3; i++) {
164       if (totsh[ind] > totsh[i]) {
165         sh = WEBRTC_SPL_MIN(31, totsh[ind]-totsh[i]);
166         if (corr16[ind] * en16[i] < (corr16[i] * en16[ind]) >> sh) {
167           ind = i;
168         }
169       } else {
170         sh = WEBRTC_SPL_MIN(31, totsh[i]-totsh[ind]);
171         if ((corr16[ind] * en16[i]) >> sh < corr16[i] * en16[ind]) {
172           ind = i;
173         }
174       }
175     }
176 
177     lag = lagmax[ind] + 10;
178 
179     /* Store the estimated lag in the non-downsampled domain */
180     enh_period[ENH_NBLOCKS_TOT - new_blocks + iblock] = lag * 8;
181 
182     /* Store the estimated lag for backward PLC */
183     if (iLBCdec_inst->prev_enh_pl==1) {
184       if (!iblock) {
185         tlag = lag * 2;
186       }
187     } else {
188       if (iblock==1) {
189         tlag = lag * 2;
190       }
191     }
192 
193     lag *= 2;
194   }
195 
196   if ((iLBCdec_inst->prev_enh_pl==1)||(iLBCdec_inst->prev_enh_pl==2)) {
197 
198     /* Calculate the best lag of the new frame
199        This is used to interpolate backwards and mix with the PLC'd data
200     */
201 
202     /* references */
203     target=in;
204     regressor=in+tlag-1;
205 
206     /* scaling */
207     // Note that this is not abs-max, so we will take the absolute value below.
208     max16 = WebRtcSpl_MaxAbsElementW16(regressor, plc_blockl + 3 - 1);
209     const int16_t max_target =
210         WebRtcSpl_MaxAbsElementW16(target, plc_blockl + 3 - 1);
211     const int64_t max_val = plc_blockl * abs(max16 * max_target);
212     const int32_t factor = max_val >> 31;
213     shifts = factor == 0 ? 0 : 31 - WebRtcSpl_NormW32(factor);
214 
215     /* compute cross correlation */
216     WebRtcSpl_CrossCorrelation(corr32, target, regressor, plc_blockl, 3, shifts,
217                                1);
218 
219     /* find lag */
220     lag=WebRtcSpl_MaxIndexW32(corr32, 3);
221     lag+=tlag-1;
222 
223     /* Copy the backward PLC to plc_pred */
224 
225     if (iLBCdec_inst->prev_enh_pl==1) {
226       if (lag>plc_blockl) {
227         WEBRTC_SPL_MEMCPY_W16(plc_pred, &in[lag-plc_blockl], plc_blockl);
228       } else {
229         WEBRTC_SPL_MEMCPY_W16(&plc_pred[plc_blockl-lag], in, lag);
230         WEBRTC_SPL_MEMCPY_W16(
231             plc_pred, &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl+lag],
232             (plc_blockl-lag));
233       }
234     } else {
235       size_t pos;
236 
237       pos = plc_blockl;
238 
239       while (lag<pos) {
240         WEBRTC_SPL_MEMCPY_W16(&plc_pred[pos-lag], in, lag);
241         pos = pos - lag;
242       }
243       WEBRTC_SPL_MEMCPY_W16(plc_pred, &in[lag-pos], pos);
244 
245     }
246 
247     if (iLBCdec_inst->prev_enh_pl==1) {
248       /* limit energy change
249          if energy in backward PLC is more than 4 times higher than the forward
250          PLC, then reduce the energy in the backward PLC vector:
251          sample 1...len-16 set energy of the to 4 times forward PLC
252          sample len-15..len interpolate between 4 times fw PLC and bw PLC energy
253 
254          Note: Compared to floating point code there is a slight change,
255          the window is 16 samples long instead of 10 samples to simplify the
256          calculations
257       */
258 
259       max=WebRtcSpl_MaxAbsValueW16(
260           &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl], plc_blockl);
261       max16=WebRtcSpl_MaxAbsValueW16(plc_pred, plc_blockl);
262       max = WEBRTC_SPL_MAX(max, max16);
263       scale=22-(int16_t)WebRtcSpl_NormW32(max);
264       scale=WEBRTC_SPL_MAX(scale,0);
265 
266       tmp2 = WebRtcSpl_DotProductWithScale(
267           &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl],
268           &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl],
269           plc_blockl, scale);
270       tmp1 = WebRtcSpl_DotProductWithScale(plc_pred, plc_pred,
271                                            plc_blockl, scale);
272 
273       /* Check the energy difference */
274       if ((tmp1>0)&&((tmp1>>2)>tmp2)) {
275         /* EnChange is now guaranteed to be <0.5
276            Calculate EnChange=tmp2/tmp1 in Q16
277         */
278 
279         scale1=(int16_t)WebRtcSpl_NormW32(tmp1);
280         tmp1=WEBRTC_SPL_SHIFT_W32(tmp1, (scale1-16)); /* using 15 bits */
281 
282         tmp2=WEBRTC_SPL_SHIFT_W32(tmp2, (scale1));
283         EnChange = (int16_t)WebRtcSpl_DivW32W16(tmp2,
284                                                       (int16_t)tmp1);
285 
286         /* Calculate the Sqrt of the energy in Q15 ((14+16)/2) */
287         SqrtEnChange = (int16_t)WebRtcSpl_SqrtFloor(EnChange << 14);
288 
289 
290         /* Multiply first part of vector with 2*SqrtEnChange */
291         WebRtcSpl_ScaleVector(plc_pred, plc_pred, SqrtEnChange, plc_blockl-16,
292                               14);
293 
294         /* Calculate increase parameter for window part (16 last samples) */
295         /* (1-2*SqrtEnChange)/16 in Q15 */
296         inc = 2048 - (SqrtEnChange >> 3);
297 
298         win=0;
299         tmpW16ptr=&plc_pred[plc_blockl-16];
300 
301         for (i=16;i>0;i--) {
302           *tmpW16ptr = (int16_t)(
303               (*tmpW16ptr * (SqrtEnChange + (win >> 1))) >> 14);
304           /* multiply by (2.0*SqrtEnChange+win) */
305 
306           win += inc;
307           tmpW16ptr++;
308         }
309       }
310 
311       /* Make the linear interpolation between the forward PLC'd data
312          and the backward PLC'd data (from the new frame)
313       */
314 
315       if (plc_blockl==40) {
316         inc=400; /* 1/41 in Q14 */
317       } else { /* plc_blockl==80 */
318         inc=202; /* 1/81 in Q14 */
319       }
320       win=0;
321       enh_bufPtr1=&enh_buf[ENH_BUFL-1-iLBCdec_inst->blockl];
322       for (i=0; i<plc_blockl; i++) {
323         win+=inc;
324         *enh_bufPtr1 = (int16_t)((*enh_bufPtr1 * win) >> 14);
325         *enh_bufPtr1 += (int16_t)(
326             ((16384 - win) * plc_pred[plc_blockl - 1 - i]) >> 14);
327         enh_bufPtr1--;
328       }
329     } else {
330       int16_t *synt = &downsampled[LPC_FILTERORDER];
331 
332       enh_bufPtr1=&enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl];
333       WEBRTC_SPL_MEMCPY_W16(enh_bufPtr1, plc_pred, plc_blockl);
334 
335       /* Clear fileter memory */
336       WebRtcSpl_MemSetW16(iLBCdec_inst->syntMem, 0, LPC_FILTERORDER);
337       WebRtcSpl_MemSetW16(iLBCdec_inst->hpimemy, 0, 4);
338       WebRtcSpl_MemSetW16(iLBCdec_inst->hpimemx, 0, 2);
339 
340       /* Initialize filter memory by filtering through 2 lags */
341       WEBRTC_SPL_MEMCPY_W16(&synt[-LPC_FILTERORDER], iLBCdec_inst->syntMem,
342                             LPC_FILTERORDER);
343       WebRtcSpl_FilterARFastQ12(
344           enh_bufPtr1,
345           synt,
346           &iLBCdec_inst->old_syntdenum[
347               (iLBCdec_inst->nsub-1)*(LPC_FILTERORDER+1)],
348           LPC_FILTERORDER+1, lag);
349 
350       WEBRTC_SPL_MEMCPY_W16(&synt[-LPC_FILTERORDER], &synt[lag-LPC_FILTERORDER],
351                             LPC_FILTERORDER);
352       WebRtcIlbcfix_HpOutput(synt, (int16_t*)WebRtcIlbcfix_kHpOutCoefs,
353                              iLBCdec_inst->hpimemy, iLBCdec_inst->hpimemx,
354                              lag);
355       WebRtcSpl_FilterARFastQ12(
356           enh_bufPtr1, synt,
357           &iLBCdec_inst->old_syntdenum[
358               (iLBCdec_inst->nsub-1)*(LPC_FILTERORDER+1)],
359           LPC_FILTERORDER+1, lag);
360 
361       WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->syntMem, &synt[lag-LPC_FILTERORDER],
362                             LPC_FILTERORDER);
363       WebRtcIlbcfix_HpOutput(synt, (int16_t*)WebRtcIlbcfix_kHpOutCoefs,
364                              iLBCdec_inst->hpimemy, iLBCdec_inst->hpimemx,
365                              lag);
366     }
367   }
368 
369 
370   /* Perform enhancement block by block */
371 
372   for (iblock = 0; iblock<new_blocks; iblock++) {
373     WebRtcIlbcfix_Enhancer(out + iblock * ENH_BLOCKL,
374                            enh_buf,
375                            ENH_BUFL,
376                            iblock * ENH_BLOCKL + startPos,
377                            enh_period,
378                            WebRtcIlbcfix_kEnhPlocs, ENH_NBLOCKS_TOT);
379   }
380 
381   return (lag);
382 }
383