xref: /aosp_15_r20/external/webrtc/modules/audio_coding/codecs/ilbc/cb_search.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_CbSearch.c
16 
17 ******************************************************************/
18 
19 #include "modules/audio_coding/codecs/ilbc/cb_search.h"
20 
21 #include "modules/audio_coding/codecs/ilbc/augmented_cb_corr.h"
22 #include "modules/audio_coding/codecs/ilbc/cb_mem_energy.h"
23 #include "modules/audio_coding/codecs/ilbc/cb_mem_energy_augmentation.h"
24 #include "modules/audio_coding/codecs/ilbc/cb_search_core.h"
25 #include "modules/audio_coding/codecs/ilbc/cb_update_best_index.h"
26 #include "modules/audio_coding/codecs/ilbc/constants.h"
27 #include "modules/audio_coding/codecs/ilbc/create_augmented_vec.h"
28 #include "modules/audio_coding/codecs/ilbc/defines.h"
29 #include "modules/audio_coding/codecs/ilbc/energy_inverse.h"
30 #include "modules/audio_coding/codecs/ilbc/filtered_cb_vecs.h"
31 #include "modules/audio_coding/codecs/ilbc/gain_quant.h"
32 #include "modules/audio_coding/codecs/ilbc/interpolate_samples.h"
33 
34 /*----------------------------------------------------------------*
35  *  Search routine for codebook encoding and gain quantization.
36  *----------------------------------------------------------------*/
37 
WebRtcIlbcfix_CbSearch(IlbcEncoder * iLBCenc_inst,int16_t * index,int16_t * gain_index,int16_t * intarget,int16_t * decResidual,size_t lMem,size_t lTarget,int16_t * weightDenum,size_t block)38 void WebRtcIlbcfix_CbSearch(
39     IlbcEncoder *iLBCenc_inst,
40     /* (i) the encoder state structure */
41     int16_t *index,  /* (o) Codebook indices */
42     int16_t *gain_index, /* (o) Gain quantization indices */
43     int16_t *intarget, /* (i) Target vector for encoding */
44     int16_t *decResidual,/* (i) Decoded residual for codebook construction */
45     size_t lMem,  /* (i) Length of buffer */
46     size_t lTarget,  /* (i) Length of vector */
47     int16_t *weightDenum,/* (i) weighting filter coefficients in Q12 */
48     size_t block  /* (i) the subblock number */
49                             ) {
50   size_t i, range;
51   int16_t ii, j, stage;
52   int16_t *pp;
53   int16_t tmp;
54   int scale;
55   int16_t bits, temp1, temp2;
56   size_t base_size;
57   int32_t codedEner, targetEner;
58   int16_t gains[CB_NSTAGES+1];
59   int16_t *cb_vecPtr;
60   size_t indexOffset, sInd, eInd;
61   int32_t CritMax=0;
62   int16_t shTotMax=WEBRTC_SPL_WORD16_MIN;
63   size_t bestIndex=0;
64   int16_t bestGain=0;
65   size_t indexNew;
66   int16_t CritNewSh;
67   int32_t CritNew;
68   int32_t *cDotPtr;
69   size_t noOfZeros;
70   int16_t *gainPtr;
71   int32_t t32, tmpW32;
72   int16_t *WebRtcIlbcfix_kGainSq5_ptr;
73   /* Stack based */
74   int16_t CBbuf[CB_MEML+LPC_FILTERORDER+CB_HALFFILTERLEN];
75   int32_t cDot[128];
76   int32_t Crit[128];
77   int16_t targetVec[SUBL+LPC_FILTERORDER];
78   int16_t cbvectors[CB_MEML + 1];  /* Adding one extra position for
79                                             Coverity warnings. */
80   int16_t codedVec[SUBL];
81   int16_t interpSamples[20*4];
82   int16_t interpSamplesFilt[20*4];
83   int16_t energyW16[CB_EXPAND*128];
84   int16_t energyShifts[CB_EXPAND*128];
85   int16_t *inverseEnergy=energyW16;   /* Reuse memory */
86   int16_t *inverseEnergyShifts=energyShifts; /* Reuse memory */
87   int16_t *buf = &CBbuf[LPC_FILTERORDER];
88   int16_t *target = &targetVec[LPC_FILTERORDER];
89   int16_t *aug_vec = (int16_t*)cDot;   /* length [SUBL], reuse memory */
90 
91   /* Determine size of codebook sections */
92 
93   base_size=lMem-lTarget+1;
94   if (lTarget==SUBL) {
95     base_size=lMem-19;
96   }
97 
98   /* weighting of the CB memory */
99   noOfZeros=lMem-WebRtcIlbcfix_kFilterRange[block];
100   WebRtcSpl_MemSetW16(&buf[-LPC_FILTERORDER], 0, noOfZeros+LPC_FILTERORDER);
101   WebRtcSpl_FilterARFastQ12(
102       decResidual+noOfZeros, buf+noOfZeros,
103       weightDenum, LPC_FILTERORDER+1, WebRtcIlbcfix_kFilterRange[block]);
104 
105   /* weighting of the target vector */
106   WEBRTC_SPL_MEMCPY_W16(&target[-LPC_FILTERORDER], buf+noOfZeros+WebRtcIlbcfix_kFilterRange[block]-LPC_FILTERORDER, LPC_FILTERORDER);
107   WebRtcSpl_FilterARFastQ12(
108       intarget, target,
109       weightDenum, LPC_FILTERORDER+1, lTarget);
110 
111   /* Store target, towards the end codedVec is calculated as
112      the initial target minus the remaining target */
113   WEBRTC_SPL_MEMCPY_W16(codedVec, target, lTarget);
114 
115   /* Find the highest absolute value to calculate proper
116      vector scale factor (so that it uses 12 bits) */
117   temp1 = WebRtcSpl_MaxAbsValueW16(buf, lMem);
118   temp2 = WebRtcSpl_MaxAbsValueW16(target, lTarget);
119 
120   if ((temp1>0)&&(temp2>0)) {
121     temp1 = WEBRTC_SPL_MAX(temp1, temp2);
122     scale = WebRtcSpl_GetSizeInBits((uint32_t)(temp1 * temp1));
123   } else {
124     /* temp1 or temp2 is negative (maximum was -32768) */
125     scale = 30;
126   }
127 
128   /* Scale to so that a mul-add 40 times does not overflow */
129   scale = scale - 25;
130   scale = WEBRTC_SPL_MAX(0, scale);
131 
132   /* Compute energy of the original target */
133   targetEner = WebRtcSpl_DotProductWithScale(target, target, lTarget, scale);
134 
135   /* Prepare search over one more codebook section. This section
136      is created by filtering the original buffer with a filter. */
137   WebRtcIlbcfix_FilteredCbVecs(cbvectors, buf, lMem, WebRtcIlbcfix_kFilterRange[block]);
138 
139   range = WebRtcIlbcfix_kSearchRange[block][0];
140 
141   if(lTarget == SUBL) {
142     /* Create the interpolated samples and store them for use in all stages */
143 
144     /* First section, non-filtered half of the cb */
145     WebRtcIlbcfix_InterpolateSamples(interpSamples, buf, lMem);
146 
147     /* Second section, filtered half of the cb */
148     WebRtcIlbcfix_InterpolateSamples(interpSamplesFilt, cbvectors, lMem);
149 
150     /* Compute the CB vectors' energies for the first cb section (non-filtered) */
151     WebRtcIlbcfix_CbMemEnergyAugmentation(interpSamples, buf,
152                                           scale, 20, energyW16, energyShifts);
153 
154     /* Compute the CB vectors' energies for the second cb section (filtered cb) */
155     WebRtcIlbcfix_CbMemEnergyAugmentation(interpSamplesFilt, cbvectors, scale,
156                                           base_size + 20, energyW16,
157                                           energyShifts);
158 
159     /* Compute the CB vectors' energies and store them in the vector
160      * energyW16. Also the corresponding shift values are stored. The
161      * energy values are used in all three stages. */
162     WebRtcIlbcfix_CbMemEnergy(range, buf, cbvectors, lMem,
163                               lTarget, energyW16+20, energyShifts+20, scale, base_size);
164 
165   } else {
166     /* Compute the CB vectors' energies and store them in the vector
167      * energyW16. Also the corresponding shift values are stored. The
168      * energy values are used in all three stages. */
169     WebRtcIlbcfix_CbMemEnergy(range, buf, cbvectors, lMem,
170                               lTarget, energyW16, energyShifts, scale, base_size);
171 
172     /* Set the energy positions 58-63 and 122-127 to zero
173        (otherwise they are uninitialized) */
174     WebRtcSpl_MemSetW16(energyW16+range, 0, (base_size-range));
175     WebRtcSpl_MemSetW16(energyW16+range+base_size, 0, (base_size-range));
176   }
177 
178   /* Calculate Inverse Energy (energyW16 is already normalized
179      and will contain the inverse energy in Q29 after this call */
180   WebRtcIlbcfix_EnergyInverse(energyW16, base_size*CB_EXPAND);
181 
182   /* The gain value computed in the previous stage is used
183    * as an upper limit to what the next stage gain value
184    * is allowed to be. In stage 0, 16384 (1.0 in Q14) is used as
185    * the upper limit. */
186   gains[0] = 16384;
187 
188   for (stage=0; stage<CB_NSTAGES; stage++) {
189 
190     /* Set up memories */
191     range = WebRtcIlbcfix_kSearchRange[block][stage];
192 
193     /* initialize search measures */
194     CritMax=0;
195     shTotMax=-100;
196     bestIndex=0;
197     bestGain=0;
198 
199     /* loop over lags 40+ in the first codebook section, full search */
200     cb_vecPtr = buf+lMem-lTarget;
201 
202     /* Calculate all the cross correlations (augmented part of CB) */
203     if (lTarget==SUBL) {
204       WebRtcIlbcfix_AugmentedCbCorr(target, buf+lMem,
205                                     interpSamples, cDot,
206                                     20, 39, scale);
207       cDotPtr=&cDot[20];
208     } else {
209       cDotPtr=cDot;
210     }
211     /* Calculate all the cross correlations (main part of CB) */
212     WebRtcSpl_CrossCorrelation(cDotPtr, target, cb_vecPtr, lTarget, range, scale, -1);
213 
214     /* Adjust the search range for the augmented vectors */
215     if (lTarget==SUBL) {
216       range=WebRtcIlbcfix_kSearchRange[block][stage]+20;
217     } else {
218       range=WebRtcIlbcfix_kSearchRange[block][stage];
219     }
220 
221     indexOffset=0;
222 
223     /* Search for best index in this part of the vector */
224     WebRtcIlbcfix_CbSearchCore(
225         cDot, range, stage, inverseEnergy,
226         inverseEnergyShifts, Crit,
227         &indexNew, &CritNew, &CritNewSh);
228 
229     /* Update the global best index and the corresponding gain */
230     WebRtcIlbcfix_CbUpdateBestIndex(
231         CritNew, CritNewSh, indexNew+indexOffset, cDot[indexNew+indexOffset],
232         inverseEnergy[indexNew+indexOffset], inverseEnergyShifts[indexNew+indexOffset],
233         &CritMax, &shTotMax, &bestIndex, &bestGain);
234 
235     sInd = ((CB_RESRANGE >> 1) > bestIndex) ?
236         0 : (bestIndex - (CB_RESRANGE >> 1));
237     eInd=sInd+CB_RESRANGE;
238     if (eInd>=range) {
239       eInd=range-1;
240       sInd=eInd-CB_RESRANGE;
241     }
242 
243     range = WebRtcIlbcfix_kSearchRange[block][stage];
244 
245     if (lTarget==SUBL) {
246       i=sInd;
247       if (sInd<20) {
248         WebRtcIlbcfix_AugmentedCbCorr(target, cbvectors + lMem,
249                                       interpSamplesFilt, cDot, sInd + 20,
250                                       WEBRTC_SPL_MIN(39, (eInd + 20)), scale);
251         i=20;
252         cDotPtr = &cDot[20 - sInd];
253       } else {
254         cDotPtr = cDot;
255       }
256 
257       cb_vecPtr = cbvectors+lMem-20-i;
258 
259       /* Calculate the cross correlations (main part of the filtered CB) */
260       WebRtcSpl_CrossCorrelation(cDotPtr, target, cb_vecPtr, lTarget,
261                                  eInd - i + 1, scale, -1);
262 
263     } else {
264       cDotPtr = cDot;
265       cb_vecPtr = cbvectors+lMem-lTarget-sInd;
266 
267       /* Calculate the cross correlations (main part of the filtered CB) */
268       WebRtcSpl_CrossCorrelation(cDotPtr, target, cb_vecPtr, lTarget,
269                                  eInd - sInd + 1, scale, -1);
270 
271     }
272 
273     /* Adjust the search range for the augmented vectors */
274     indexOffset=base_size+sInd;
275 
276     /* Search for best index in this part of the vector */
277     WebRtcIlbcfix_CbSearchCore(
278         cDot, eInd-sInd+1, stage, inverseEnergy+indexOffset,
279         inverseEnergyShifts+indexOffset, Crit,
280         &indexNew, &CritNew, &CritNewSh);
281 
282     /* Update the global best index and the corresponding gain */
283     WebRtcIlbcfix_CbUpdateBestIndex(
284         CritNew, CritNewSh, indexNew+indexOffset, cDot[indexNew],
285         inverseEnergy[indexNew+indexOffset], inverseEnergyShifts[indexNew+indexOffset],
286         &CritMax, &shTotMax, &bestIndex, &bestGain);
287 
288     index[stage] = (int16_t)bestIndex;
289 
290 
291     bestGain = WebRtcIlbcfix_GainQuant(bestGain,
292                                        (int16_t)WEBRTC_SPL_ABS_W16(gains[stage]), stage, &gain_index[stage]);
293 
294     /* Extract the best (according to measure) codebook vector
295        Also adjust the index, so that the augmented vectors are last.
296        Above these vectors were first...
297     */
298 
299     if(lTarget==(STATE_LEN-iLBCenc_inst->state_short_len)) {
300 
301       if((size_t)index[stage]<base_size) {
302         pp=buf+lMem-lTarget-index[stage];
303       } else {
304         pp=cbvectors+lMem-lTarget-
305             index[stage]+base_size;
306       }
307 
308     } else {
309 
310       if ((size_t)index[stage]<base_size) {
311         if (index[stage]>=20) {
312           /* Adjust index and extract vector */
313           index[stage]-=20;
314           pp=buf+lMem-lTarget-index[stage];
315         } else {
316           /* Adjust index and extract vector */
317           index[stage]+=(int16_t)(base_size-20);
318 
319           WebRtcIlbcfix_CreateAugmentedVec(index[stage]-base_size+40,
320                                            buf+lMem, aug_vec);
321           pp = aug_vec;
322 
323         }
324       } else {
325 
326         if ((index[stage] - base_size) >= 20) {
327           /* Adjust index and extract vector */
328           index[stage]-=20;
329           pp=cbvectors+lMem-lTarget-
330               index[stage]+base_size;
331         } else {
332           /* Adjust index and extract vector */
333           index[stage]+=(int16_t)(base_size-20);
334           WebRtcIlbcfix_CreateAugmentedVec(index[stage]-2*base_size+40,
335                                            cbvectors+lMem, aug_vec);
336           pp = aug_vec;
337         }
338       }
339     }
340 
341     /* Subtract the best codebook vector, according
342        to measure, from the target vector */
343 
344     WebRtcSpl_AddAffineVectorToVector(target, pp, (int16_t)(-bestGain),
345                                       (int32_t)8192, (int16_t)14, lTarget);
346 
347     /* record quantized gain */
348     gains[stage+1] = bestGain;
349 
350   } /* end of Main Loop. for (stage=0;... */
351 
352   /* Calculte the coded vector (original target - what's left) */
353   for (i=0;i<lTarget;i++) {
354     codedVec[i]-=target[i];
355   }
356 
357   /* Gain adjustment for energy matching */
358   codedEner = WebRtcSpl_DotProductWithScale(codedVec, codedVec, lTarget, scale);
359 
360   j=gain_index[0];
361 
362   temp1 = (int16_t)WebRtcSpl_NormW32(codedEner);
363   temp2 = (int16_t)WebRtcSpl_NormW32(targetEner);
364 
365   if(temp1 < temp2) {
366     bits = 16 - temp1;
367   } else {
368     bits = 16 - temp2;
369   }
370 
371   tmp = (int16_t)((gains[1] * gains[1]) >> 14);
372 
373   targetEner = (int16_t)WEBRTC_SPL_SHIFT_W32(targetEner, -bits) * tmp;
374 
375   tmpW32 = ((int32_t)(gains[1]-1))<<1;
376 
377   /* Pointer to the table that contains
378      gain_sq5TblFIX * gain_sq5TblFIX in Q14 */
379   gainPtr=(int16_t*)WebRtcIlbcfix_kGainSq5Sq+gain_index[0];
380   temp1 = (int16_t)WEBRTC_SPL_SHIFT_W32(codedEner, -bits);
381 
382   WebRtcIlbcfix_kGainSq5_ptr = (int16_t*)&WebRtcIlbcfix_kGainSq5[j];
383 
384   /* targetEner and codedEner are in Q(-2*scale) */
385   for (ii=gain_index[0];ii<32;ii++) {
386 
387     /* Change the index if
388        (codedEnergy*gainTbl[i]*gainTbl[i])<(targetEn*gain[0]*gain[0]) AND
389        gainTbl[i] < 2*gain[0]
390     */
391 
392     t32 = temp1 * *gainPtr;
393     t32 = t32 - targetEner;
394     if (t32 < 0) {
395       if ((*WebRtcIlbcfix_kGainSq5_ptr) < tmpW32) {
396         j=ii;
397         WebRtcIlbcfix_kGainSq5_ptr = (int16_t*)&WebRtcIlbcfix_kGainSq5[ii];
398       }
399     }
400     gainPtr++;
401   }
402   gain_index[0]=j;
403 
404   return;
405 }
406