2
|
1
|
|
2 /******************************************************************
|
|
3
|
|
4 iLBC Speech Coder ANSI-C Source Code
|
|
5
|
|
6 enhancer.c
|
|
7
|
|
8 Copyright (C) The Internet Society (2004).
|
|
9 All Rights Reserved.
|
|
10
|
|
11 ******************************************************************/
|
|
12
|
|
13 #include <math.h>
|
|
14 #include <string.h>
|
|
15 #include "iLBC_define.h"
|
|
16 #include "constants.h"
|
|
17 #include "filter.h"
|
|
18
|
|
19 /*----------------------------------------------------------------*
|
|
20 * Find index in array such that the array element with said
|
|
21 * index is the element of said array closest to "value"
|
|
22 * according to the squared-error criterion
|
|
23 *---------------------------------------------------------------*/
|
|
24
|
|
25 void NearestNeighbor(int *index, /* (o) index of array element closest
|
|
26 to value */
|
|
27 float *array, /* (i) data array */
|
|
28 float value, /* (i) value */
|
|
29 int arlength /* (i) dimension of data array */
|
|
30 )
|
|
31 {
|
|
32 int i;
|
|
33 float bestcrit, crit;
|
|
34
|
|
35 crit = array[0] - value;
|
|
36 bestcrit = crit * crit;
|
|
37 *index = 0;
|
|
38 for (i = 1; i < arlength; i++) {
|
|
39 crit = array[i] - value;
|
|
40 crit = crit * crit;
|
|
41
|
|
42 if (crit < bestcrit) {
|
|
43 bestcrit = crit;
|
|
44 *index = i;
|
|
45 }
|
|
46 }
|
|
47 }
|
|
48
|
|
49 /*----------------------------------------------------------------*
|
|
50 * compute cross correlation between sequences
|
|
51 *---------------------------------------------------------------*/
|
|
52
|
|
53 void mycorr1(float *corr, /* (o) correlation of seq1 and seq2 */
|
|
54 float *seq1, /* (i) first sequence */
|
|
55 int dim1, /* (i) dimension first seq1 */
|
|
56 const float *seq2, /* (i) second sequence */
|
|
57 int dim2 /* (i) dimension seq2 */
|
|
58 )
|
|
59 {
|
|
60 int i, j;
|
|
61
|
|
62 for (i = 0; i <= dim1 - dim2; i++) {
|
|
63 corr[i] = 0.0;
|
|
64 for (j = 0; j < dim2; j++) {
|
|
65 corr[i] += seq1[i + j] * seq2[j];
|
|
66 }
|
|
67 }
|
|
68 }
|
|
69
|
|
70 /*----------------------------------------------------------------*
|
|
71 * upsample finite array assuming zeros outside bounds
|
|
72 *---------------------------------------------------------------*/
|
|
73
|
|
74
|
|
75
|
|
76
|
|
77
|
|
78
|
|
79 void enh_upsample(float *useq1, /* (o) upsampled output sequence */
|
|
80 float *seq1, /* (i) unupsampled sequence */
|
|
81 int dim1, /* (i) dimension seq1 */
|
|
82 int hfl /* (i) polyphase filter length=2*hfl+1 */
|
|
83 )
|
|
84 {
|
|
85 float *pu, *ps;
|
|
86 int i, j, k, q, filterlength, hfl2;
|
|
87 const float *polyp[ENH_UPS0]; /* pointers to
|
|
88 polyphase columns */
|
|
89 const float *pp;
|
|
90
|
|
91 /* define pointers for filter */
|
|
92
|
|
93 filterlength = 2 * hfl + 1;
|
|
94
|
|
95 if (filterlength > dim1) {
|
|
96 hfl2 = (int) (dim1 / 2);
|
|
97 for (j = 0; j < ENH_UPS0; j++) {
|
|
98 polyp[j] = polyphaserTbl + j * filterlength + hfl - hfl2;
|
|
99 }
|
|
100 hfl = hfl2;
|
|
101 filterlength = 2 * hfl + 1;
|
|
102 } else {
|
|
103 for (j = 0; j < ENH_UPS0; j++) {
|
|
104 polyp[j] = polyphaserTbl + j * filterlength;
|
|
105 }
|
|
106 }
|
|
107
|
|
108 /* filtering: filter overhangs left side of sequence */
|
|
109
|
|
110 pu = useq1;
|
|
111 for (i = hfl; i < filterlength; i++) {
|
|
112 for (j = 0; j < ENH_UPS0; j++) {
|
|
113 *pu = 0.0;
|
|
114 pp = polyp[j];
|
|
115 ps = seq1 + i;
|
|
116 for (k = 0; k <= i; k++) {
|
|
117 *pu += *ps-- * *pp++;
|
|
118 }
|
|
119 pu++;
|
|
120 }
|
|
121 }
|
|
122
|
|
123 /* filtering: simple convolution=inner products */
|
|
124
|
|
125 for (i = filterlength; i < dim1; i++) {
|
|
126
|
|
127
|
|
128
|
|
129
|
|
130
|
|
131 for (j = 0; j < ENH_UPS0; j++) {
|
|
132 *pu = 0.0;
|
|
133 pp = polyp[j];
|
|
134 ps = seq1 + i;
|
|
135 for (k = 0; k < filterlength; k++) {
|
|
136 *pu += *ps-- * *pp++;
|
|
137 }
|
|
138 pu++;
|
|
139 }
|
|
140 }
|
|
141
|
|
142 /* filtering: filter overhangs right side of sequence */
|
|
143
|
|
144 for (q = 1; q <= hfl; q++) {
|
|
145 for (j = 0; j < ENH_UPS0; j++) {
|
|
146 *pu = 0.0;
|
|
147 pp = polyp[j] + q;
|
|
148 ps = seq1 + dim1 - 1;
|
|
149 for (k = 0; k < filterlength - q; k++) {
|
|
150 *pu += *ps-- * *pp++;
|
|
151 }
|
|
152 pu++;
|
|
153 }
|
|
154 }
|
|
155 }
|
|
156
|
|
157
|
|
158 /*----------------------------------------------------------------*
|
|
159 * find segment starting near idata+estSegPos that has highest
|
|
160 * correlation with idata+centerStartPos through
|
|
161 * idata+centerStartPos+ENH_BLOCKL-1 segment is found at a
|
|
162 * resolution of ENH_UPSO times the original of the original
|
|
163 * sampling rate
|
|
164 *---------------------------------------------------------------*/
|
|
165
|
|
166 void refiner(float *seg, /* (o) segment array */
|
|
167 float *updStartPos, /* (o) updated start point */
|
|
168 float *idata, /* (i) original data buffer */
|
|
169 int idatal, /* (i) dimension of idata */
|
|
170 int centerStartPos, /* (i) beginning center segment */
|
|
171 float estSegPos, /* (i) estimated beginning other segment */
|
|
172 float period /* (i) estimated pitch period */
|
|
173 )
|
|
174 {
|
|
175 int estSegPosRounded, searchSegStartPos, searchSegEndPos, corrdim;
|
|
176 int tloc, tloc2, i, st, en, fraction;
|
|
177 float vect[ENH_VECTL], corrVec[ENH_CORRDIM], maxv;
|
|
178 float corrVecUps[ENH_CORRDIM * ENH_UPS0];
|
|
179
|
|
180
|
|
181
|
|
182
|
|
183
|
|
184 /* defining array bounds */
|
|
185
|
|
186 estSegPosRounded = (int) (estSegPos - 0.5);
|
|
187
|
|
188 searchSegStartPos = estSegPosRounded - ENH_SLOP;
|
|
189
|
|
190 if (searchSegStartPos < 0) {
|
|
191 searchSegStartPos = 0;
|
|
192 }
|
|
193 searchSegEndPos = estSegPosRounded + ENH_SLOP;
|
|
194
|
|
195 if (searchSegEndPos + ENH_BLOCKL >= idatal) {
|
|
196 searchSegEndPos = idatal - ENH_BLOCKL - 1;
|
|
197 }
|
|
198 corrdim = searchSegEndPos - searchSegStartPos + 1;
|
|
199
|
|
200 /* compute upsampled correlation (corr33) and find
|
|
201 location of max */
|
|
202
|
|
203 mycorr1(corrVec, idata + searchSegStartPos,
|
|
204 corrdim + ENH_BLOCKL - 1, idata + centerStartPos, ENH_BLOCKL);
|
|
205 enh_upsample(corrVecUps, corrVec, corrdim, ENH_FL0);
|
|
206 tloc = 0;
|
|
207 maxv = corrVecUps[0];
|
|
208 for (i = 1; i < ENH_UPS0 * corrdim; i++) {
|
|
209
|
|
210 if (corrVecUps[i] > maxv) {
|
|
211 tloc = i;
|
|
212 maxv = corrVecUps[i];
|
|
213 }
|
|
214 }
|
|
215
|
|
216 /* make vector can be upsampled without ever running outside
|
|
217 bounds */
|
|
218
|
|
219 *updStartPos = (float) searchSegStartPos +
|
|
220 (float) tloc / (float) ENH_UPS0 + (float) 1.0;
|
|
221 tloc2 = (int) (tloc / ENH_UPS0);
|
|
222
|
|
223 if (tloc > tloc2 * ENH_UPS0) {
|
|
224 tloc2++;
|
|
225 }
|
|
226 st = searchSegStartPos + tloc2 - ENH_FL0;
|
|
227
|
|
228 if (st < 0) {
|
|
229 memset(vect, 0, -st * sizeof(float));
|
|
230 memcpy(&vect[-st], idata, (ENH_VECTL + st) * sizeof(float));
|
|
231 } else {
|
|
232
|
|
233
|
|
234
|
|
235
|
|
236
|
|
237 en = st + ENH_VECTL;
|
|
238
|
|
239 if (en > idatal) {
|
|
240 memcpy(vect, &idata[st],
|
|
241 (ENH_VECTL - (en - idatal)) * sizeof(float));
|
|
242 memset(&vect[ENH_VECTL - (en - idatal)], 0,
|
|
243 (en - idatal) * sizeof(float));
|
|
244 } else {
|
|
245 memcpy(vect, &idata[st], ENH_VECTL * sizeof(float));
|
|
246 }
|
|
247 }
|
|
248 fraction = tloc2 * ENH_UPS0 - tloc;
|
|
249
|
|
250 /* compute the segment (this is actually a convolution) */
|
|
251
|
|
252 mycorr1(seg, vect, ENH_VECTL,
|
|
253 polyphaserTbl + (2 * ENH_FL0 + 1) * fraction, 2 * ENH_FL0 + 1);
|
|
254 }
|
|
255
|
|
256 /*----------------------------------------------------------------*
|
|
257 * find the smoothed output data
|
|
258 *---------------------------------------------------------------*/
|
|
259
|
|
260 void smath(float *odata, /* (o) smoothed output */
|
|
261 float *sseq, /* (i) said second sequence of waveforms */
|
|
262 int hl, /* (i) 2*hl+1 is sseq dimension */
|
|
263 float alpha0 /* (i) max smoothing energy fraction */
|
|
264 )
|
|
265 {
|
|
266 int i, k;
|
|
267 float w00, w10, w11, A, B, C, *psseq, err, errs;
|
|
268 float surround[BLOCKL_MAX]; /* shape contributed by other than
|
|
269 current */
|
|
270 float wt[2 * ENH_HL + 1]; /* waveform weighting to get
|
|
271 surround shape */
|
|
272 float denom;
|
|
273
|
|
274 /* create shape of contribution from all waveforms except the
|
|
275 current one */
|
|
276
|
|
277 for (i = 1; i <= 2 * hl + 1; i++) {
|
|
278 wt[i - 1] =
|
|
279 (float) 0.5 *(1 - (float) cos(2 * PI * i / (2 * hl + 2)));
|
|
280 }
|
|
281 wt[hl] = 0.0; /* for clarity, not used */
|
|
282 for (i = 0; i < ENH_BLOCKL; i++) {
|
|
283 surround[i] = sseq[i] * wt[0];
|
|
284 }
|
|
285
|
|
286
|
|
287
|
|
288
|
|
289
|
|
290 for (k = 1; k < hl; k++) {
|
|
291 psseq = sseq + k * ENH_BLOCKL;
|
|
292 for (i = 0; i < ENH_BLOCKL; i++) {
|
|
293 surround[i] += psseq[i] * wt[k];
|
|
294 }
|
|
295 }
|
|
296 for (k = hl + 1; k <= 2 * hl; k++) {
|
|
297 psseq = sseq + k * ENH_BLOCKL;
|
|
298 for (i = 0; i < ENH_BLOCKL; i++) {
|
|
299 surround[i] += psseq[i] * wt[k];
|
|
300 }
|
|
301 }
|
|
302
|
|
303 /* compute some inner products */
|
|
304
|
|
305 w00 = w10 = w11 = 0.0;
|
|
306 psseq = sseq + hl * ENH_BLOCKL; /* current block */
|
|
307 for (i = 0; i < ENH_BLOCKL; i++) {
|
|
308 w00 += psseq[i] * psseq[i];
|
|
309 w11 += surround[i] * surround[i];
|
|
310 w10 += surround[i] * psseq[i];
|
|
311 }
|
|
312
|
|
313 if (fabs(w11) < 1.0) {
|
|
314 w11 = 1.0;
|
|
315 }
|
|
316 C = (float) sqrt(w00 / w11);
|
|
317
|
|
318 /* first try enhancement without power-constraint */
|
|
319
|
|
320 errs = 0.0;
|
|
321 psseq = sseq + hl * ENH_BLOCKL;
|
|
322 for (i = 0; i < ENH_BLOCKL; i++) {
|
|
323 odata[i] = C * surround[i];
|
|
324 err = psseq[i] - odata[i];
|
|
325 errs += err * err;
|
|
326 }
|
|
327
|
|
328 /* if constraint violated by first try, add constraint */
|
|
329
|
|
330 if (errs > alpha0 * w00) {
|
|
331 if (w00 < 1) {
|
|
332 w00 = 1;
|
|
333 }
|
|
334 denom = (w11 * w00 - w10 * w10) / (w00 * w00);
|
|
335
|
|
336 if (denom > 0.0001) { /* eliminates numerical problems
|
|
337 for if smooth */
|
|
338
|
|
339
|
|
340
|
|
341
|
|
342
|
|
343 A = (float) sqrt((alpha0 - alpha0 * alpha0 / 4) / denom);
|
|
344 B = -alpha0 / 2 - A * w10 / w00;
|
|
345 B = B + 1;
|
|
346 } else { /* essentially no difference between cycles;
|
|
347 smoothing not needed */
|
|
348 A = 0.0;
|
|
349 B = 1.0;
|
|
350 }
|
|
351
|
|
352 /* create smoothed sequence */
|
|
353
|
|
354 psseq = sseq + hl * ENH_BLOCKL;
|
|
355 for (i = 0; i < ENH_BLOCKL; i++) {
|
|
356 odata[i] = A * surround[i] + B * psseq[i];
|
|
357 }
|
|
358 }
|
|
359 }
|
|
360
|
|
361 /*----------------------------------------------------------------*
|
|
362 * get the pitch-synchronous sample sequence
|
|
363 *---------------------------------------------------------------*/
|
|
364
|
|
365 void getsseq(float *sseq, /* (o) the pitch-synchronous sequence */
|
|
366 float *idata, /* (i) original data */
|
|
367 int idatal, /* (i) dimension of data */
|
|
368 int centerStartPos, /* (i) where current block starts */
|
|
369 float *period, /* (i) rough-pitch-period array */
|
|
370 float *plocs, /* (i) where periods of period array
|
|
371 are taken */
|
|
372 int periodl, /* (i) dimension period array */
|
|
373 int hl /* (i) 2*hl+1 is the number of sequences */
|
|
374 )
|
|
375 {
|
|
376 int i, centerEndPos, q;
|
|
377 float blockStartPos[2 * ENH_HL + 1];
|
|
378 int lagBlock[2 * ENH_HL + 1];
|
|
379 float plocs2[ENH_PLOCSL];
|
|
380 float *psseq;
|
|
381
|
|
382 centerEndPos = centerStartPos + ENH_BLOCKL - 1;
|
|
383
|
|
384 /* present */
|
|
385
|
|
386 NearestNeighbor(lagBlock + hl, plocs,
|
|
387 (float) 0.5 * (centerStartPos + centerEndPos), periodl);
|
|
388
|
|
389 blockStartPos[hl] = (float) centerStartPos;
|
|
390
|
|
391
|
|
392
|
|
393
|
|
394
|
|
395 psseq = sseq + ENH_BLOCKL * hl;
|
|
396 memcpy(psseq, idata + centerStartPos, ENH_BLOCKL * sizeof(float));
|
|
397
|
|
398 /* past */
|
|
399
|
|
400 for (q = hl - 1; q >= 0; q--) {
|
|
401 blockStartPos[q] = blockStartPos[q + 1] - period[lagBlock[q + 1]];
|
|
402 NearestNeighbor(lagBlock + q, plocs,
|
|
403 blockStartPos[q] +
|
|
404 ENH_BLOCKL_HALF - period[lagBlock[q + 1]], periodl);
|
|
405
|
|
406
|
|
407 if (blockStartPos[q] - ENH_OVERHANG >= 0) {
|
|
408 refiner(sseq + q * ENH_BLOCKL, blockStartPos + q, idata,
|
|
409 idatal, centerStartPos, blockStartPos[q],
|
|
410 period[lagBlock[q + 1]]);
|
|
411 } else {
|
|
412 psseq = sseq + q * ENH_BLOCKL;
|
|
413 memset(psseq, 0, ENH_BLOCKL * sizeof(float));
|
|
414 }
|
|
415 }
|
|
416
|
|
417 /* future */
|
|
418
|
|
419 for (i = 0; i < periodl; i++) {
|
|
420 plocs2[i] = plocs[i] - period[i];
|
|
421 }
|
|
422 for (q = hl + 1; q <= 2 * hl; q++) {
|
|
423 NearestNeighbor(lagBlock + q, plocs2,
|
|
424 blockStartPos[q - 1] + ENH_BLOCKL_HALF, periodl);
|
|
425
|
|
426 blockStartPos[q] = blockStartPos[q - 1] + period[lagBlock[q]];
|
|
427 if (blockStartPos[q] + ENH_BLOCKL + ENH_OVERHANG < idatal) {
|
|
428 refiner(sseq + ENH_BLOCKL * q, blockStartPos + q, idata,
|
|
429 idatal, centerStartPos, blockStartPos[q], period[lagBlock[q]]);
|
|
430 } else {
|
|
431 psseq = sseq + q * ENH_BLOCKL;
|
|
432 memset(psseq, 0, ENH_BLOCKL * sizeof(float));
|
|
433 }
|
|
434 }
|
|
435 }
|
|
436
|
|
437 /*----------------------------------------------------------------*
|
|
438 * perform enhancement on idata+centerStartPos through
|
|
439 * idata+centerStartPos+ENH_BLOCKL-1
|
|
440 *---------------------------------------------------------------*/
|
|
441
|
|
442
|
|
443
|
|
444
|
|
445
|
|
446 void enhancer(float *odata, /* (o) smoothed block, dimension blockl */
|
|
447 float *idata, /* (i) data buffer used for enhancing */
|
|
448 int idatal, /* (i) dimension idata */
|
|
449 int centerStartPos, /* (i) first sample current block
|
|
450 within idata */
|
|
451 float alpha0, /* (i) max correction-energy-fraction
|
|
452 (in [0,1]) */
|
|
453 float *period, /* (i) pitch period array */
|
|
454 float *plocs, /* (i) locations where period array
|
|
455 values valid */
|
|
456 int periodl /* (i) dimension of period and plocs */
|
|
457 )
|
|
458 {
|
|
459 float sseq[(2 * ENH_HL + 1) * ENH_BLOCKL];
|
|
460
|
|
461 /* get said second sequence of segments */
|
|
462
|
|
463 getsseq(sseq, idata, idatal, centerStartPos, period,
|
|
464 plocs, periodl, ENH_HL);
|
|
465
|
|
466 /* compute the smoothed output from said second sequence */
|
|
467
|
|
468 smath(odata, sseq, ENH_HL, alpha0);
|
|
469
|
|
470 }
|
|
471
|
|
472 /*----------------------------------------------------------------*
|
|
473 * cross correlation
|
|
474 *---------------------------------------------------------------*/
|
|
475
|
|
476 float xCorrCoef(float *target, /* (i) first array */
|
|
477 float *regressor, /* (i) second array */
|
|
478 int subl /* (i) dimension arrays */
|
|
479 )
|
|
480 {
|
|
481 int i;
|
|
482 float ftmp1, ftmp2;
|
|
483
|
|
484 ftmp1 = 0.0;
|
|
485 ftmp2 = 0.0;
|
|
486 for (i = 0; i < subl; i++) {
|
|
487 ftmp1 += target[i] * regressor[i];
|
|
488 ftmp2 += regressor[i] * regressor[i];
|
|
489 }
|
|
490
|
|
491 if (ftmp1 > 0.0) {
|
|
492 return (float) (ftmp1 * ftmp1 / ftmp2);
|
|
493 }
|
|
494
|
|
495
|
|
496
|
|
497
|
|
498
|
|
499 else {
|
|
500 return (float) 0.0;
|
|
501 }
|
|
502 }
|
|
503
|
|
504 /*----------------------------------------------------------------*
|
|
505 * interface for enhancer
|
|
506 *---------------------------------------------------------------*/
|
|
507
|
|
508 int enhancerInterface(float *out, /* (o) enhanced signal */
|
|
509 float *in, /* (i) unenhanced signal */
|
|
510 iLBC_Dec_Inst_t * iLBCdec_inst /* (i) buffers etc */
|
|
511 )
|
|
512 {
|
|
513 float *enh_buf, *enh_period;
|
|
514 int iblock, isample;
|
|
515 int lag = 0, ilag, i, ioffset;
|
|
516 float cc, maxcc;
|
|
517 float ftmp1, ftmp2;
|
|
518 float *inPtr, *enh_bufPtr1, *enh_bufPtr2;
|
|
519 float plc_pred[ENH_BLOCKL];
|
|
520
|
|
521 float lpState[6], downsampled[(ENH_NBLOCKS * ENH_BLOCKL + 120) / 2];
|
|
522 int inLen = ENH_NBLOCKS * ENH_BLOCKL + 120;
|
|
523 int start, plc_blockl, inlag;
|
|
524
|
|
525 enh_buf = iLBCdec_inst->enh_buf;
|
|
526 enh_period = iLBCdec_inst->enh_period;
|
|
527
|
|
528 memmove(enh_buf, &enh_buf[iLBCdec_inst->blockl],
|
|
529 (ENH_BUFL - iLBCdec_inst->blockl) * sizeof(float));
|
|
530
|
|
531 memcpy(&enh_buf[ENH_BUFL - iLBCdec_inst->blockl], in,
|
|
532 iLBCdec_inst->blockl * sizeof(float));
|
|
533
|
|
534 if (iLBCdec_inst->mode == 30)
|
|
535 plc_blockl = ENH_BLOCKL;
|
|
536 else
|
|
537 plc_blockl = 40;
|
|
538
|
|
539 /* when 20 ms frame, move processing one block */
|
|
540 ioffset = 0;
|
|
541 if (iLBCdec_inst->mode == 20)
|
|
542 ioffset = 1;
|
|
543
|
|
544 i = 3 - ioffset;
|
|
545 memmove(enh_period, &enh_period[i],
|
|
546 (ENH_NBLOCKS_TOT - i) * sizeof(float));
|
|
547
|
|
548
|
|
549
|
|
550
|
|
551
|
|
552
|
|
553 /* Set state information to the 6 samples right before
|
|
554 the samples to be downsampled. */
|
|
555
|
|
556 memcpy(lpState,
|
|
557 enh_buf + (ENH_NBLOCKS_EXTRA + ioffset) * ENH_BLOCKL - 126,
|
|
558 6 * sizeof(float));
|
|
559
|
|
560 /* Down sample a factor 2 to save computations */
|
|
561
|
|
562 DownSample(enh_buf + (ENH_NBLOCKS_EXTRA + ioffset) * ENH_BLOCKL - 120,
|
|
563 lpFilt_coefsTbl, inLen - ioffset * ENH_BLOCKL,
|
|
564 lpState, downsampled);
|
|
565
|
|
566 /* Estimate the pitch in the down sampled domain. */
|
|
567 for (iblock = 0; iblock < ENH_NBLOCKS - ioffset; iblock++) {
|
|
568
|
|
569 lag = 10;
|
|
570 maxcc = xCorrCoef(downsampled + 60 + iblock *
|
|
571 ENH_BLOCKL_HALF, downsampled + 60 + iblock *
|
|
572 ENH_BLOCKL_HALF - lag, ENH_BLOCKL_HALF);
|
|
573 for (ilag = 11; ilag < 60; ilag++) {
|
|
574 cc = xCorrCoef(downsampled + 60 + iblock *
|
|
575 ENH_BLOCKL_HALF, downsampled + 60 + iblock *
|
|
576 ENH_BLOCKL_HALF - ilag, ENH_BLOCKL_HALF);
|
|
577
|
|
578 if (cc > maxcc) {
|
|
579 maxcc = cc;
|
|
580 lag = ilag;
|
|
581 }
|
|
582 }
|
|
583
|
|
584 /* Store the estimated lag in the non-downsampled domain */
|
|
585 enh_period[iblock + ENH_NBLOCKS_EXTRA + ioffset] = (float) lag *2;
|
|
586
|
|
587
|
|
588 }
|
|
589
|
|
590
|
|
591 /* PLC was performed on the previous packet */
|
|
592 if (iLBCdec_inst->prev_enh_pl == 1) {
|
|
593
|
|
594 inlag = (int) enh_period[ENH_NBLOCKS_EXTRA + ioffset];
|
|
595
|
|
596 lag = inlag - 1;
|
|
597 maxcc = xCorrCoef(in, in + lag, plc_blockl);
|
|
598 for (ilag = inlag; ilag <= inlag + 1; ilag++) {
|
|
599 cc = xCorrCoef(in, in + ilag, plc_blockl);
|
|
600
|
|
601
|
|
602
|
|
603
|
|
604
|
|
605
|
|
606 if (cc > maxcc) {
|
|
607 maxcc = cc;
|
|
608 lag = ilag;
|
|
609 }
|
|
610 }
|
|
611
|
|
612 enh_period[ENH_NBLOCKS_EXTRA + ioffset - 1] = (float) lag;
|
|
613
|
|
614 /* compute new concealed residual for the old lookahead,
|
|
615 mix the forward PLC with a backward PLC from
|
|
616 the new frame */
|
|
617
|
|
618 inPtr = &in[lag - 1];
|
|
619
|
|
620 enh_bufPtr1 = &plc_pred[plc_blockl - 1];
|
|
621
|
|
622 if (lag > plc_blockl) {
|
|
623 start = plc_blockl;
|
|
624 } else {
|
|
625 start = lag;
|
|
626 }
|
|
627
|
|
628 for (isample = start; isample > 0; isample--) {
|
|
629 *enh_bufPtr1-- = *inPtr--;
|
|
630 }
|
|
631
|
|
632 enh_bufPtr2 = &enh_buf[ENH_BUFL - 1 - iLBCdec_inst->blockl];
|
|
633 for (isample = (plc_blockl - 1 - lag); isample >= 0; isample--) {
|
|
634 *enh_bufPtr1-- = *enh_bufPtr2--;
|
|
635 }
|
|
636
|
|
637 /* limit energy change */
|
|
638 ftmp2 = 0.0;
|
|
639 ftmp1 = 0.0;
|
|
640 for (i = 0; i < plc_blockl; i++) {
|
|
641 ftmp2 += enh_buf[ENH_BUFL - 1 - iLBCdec_inst->blockl - i] *
|
|
642 enh_buf[ENH_BUFL - 1 - iLBCdec_inst->blockl - i];
|
|
643 ftmp1 += plc_pred[i] * plc_pred[i];
|
|
644 }
|
|
645 ftmp1 = (float) sqrt(ftmp1 / (float) plc_blockl);
|
|
646 ftmp2 = (float) sqrt(ftmp2 / (float) plc_blockl);
|
|
647 if (ftmp1 > (float) 2.0 * ftmp2 && ftmp1 > 0.0) {
|
|
648 for (i = 0; i < plc_blockl - 10; i++) {
|
|
649 plc_pred[i] *= (float) 2.0 *ftmp2 / ftmp1;
|
|
650 }
|
|
651 for (i = plc_blockl - 10; i < plc_blockl; i++) {
|
|
652 plc_pred[i] *= (float) (i - plc_blockl + 10) *
|
|
653 ((float) 1.0 - (float) 2.0 * ftmp2 / ftmp1) / (float) (10) +
|
|
654 (float) 2.0 *ftmp2 / ftmp1;
|
|
655 }
|
|
656 }
|
|
657
|
|
658 enh_bufPtr1 = &enh_buf[ENH_BUFL - 1 - iLBCdec_inst->blockl];
|
|
659 for (i = 0; i < plc_blockl; i++) {
|
|
660 ftmp1 = (float) (i + 1) / (float) (plc_blockl + 1);
|
|
661 *enh_bufPtr1 *= ftmp1;
|
|
662 *enh_bufPtr1 += ((float) 1.0 - ftmp1) *
|
|
663 plc_pred[plc_blockl - 1 - i];
|
|
664 enh_bufPtr1--;
|
|
665 }
|
|
666 }
|
|
667
|
|
668 if (iLBCdec_inst->mode == 20) {
|
|
669 /* Enhancer with 40 samples delay */
|
|
670 for (iblock = 0; iblock < 2; iblock++) {
|
|
671 enhancer(out + iblock * ENH_BLOCKL, enh_buf,
|
|
672 ENH_BUFL, (5 + iblock) * ENH_BLOCKL + 40,
|
|
673 ENH_ALPHA0, enh_period, enh_plocsTbl, ENH_NBLOCKS_TOT);
|
|
674 }
|
|
675 } else if (iLBCdec_inst->mode == 30) {
|
|
676 /* Enhancer with 80 samples delay */
|
|
677 for (iblock = 0; iblock < 3; iblock++) {
|
|
678 enhancer(out + iblock * ENH_BLOCKL, enh_buf,
|
|
679 ENH_BUFL, (4 + iblock) * ENH_BLOCKL,
|
|
680 ENH_ALPHA0, enh_period, enh_plocsTbl, ENH_NBLOCKS_TOT);
|
|
681 }
|
|
682 }
|
|
683
|
|
684 return (lag * 2);
|
|
685 }
|