Mercurial > hg > audiostuff
comparison intercom/ilbc/enhancer.c @ 2:13be24d74cd2
import intercom-0.4.1
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 09:57:52 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1:9cadc470e3da | 2:13be24d74cd2 |
---|---|
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 } |