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 }

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.