2 /******************************************************************
4 iLBC Speech Coder ANSI-C Source Code
8 Copyright (C) The Internet Society (2004).
11 ******************************************************************/
15 #include "iLBC_define.h"
17 #include "constants.h"
20 /*----------------------------------------------------------------*
23 * Find index in array such that the array element with said
24 * index is the element of said array closest to "value"
25 * according to the squared-error criterion
26 *---------------------------------------------------------------*/
28 static void NearestNeighbor(
29 int *index
, /* (o) index of array element closest
31 float *array
, /* (i) data array */
32 float value
,/* (i) value */
33 int arlength
/* (i) dimension of data array */
41 for (i
=1; i
<arlength
; i
++) {
52 /*----------------------------------------------------------------*
53 * compute cross correlation between sequences
54 *---------------------------------------------------------------*/
57 float* corr
, /* (o) correlation of seq1 and seq2 */
58 float* seq1
, /* (i) first sequence */
59 int dim1
, /* (i) dimension first seq1 */
60 const float *seq2
, /* (i) second sequence */
61 int dim2
/* (i) dimension seq2 */
65 for (i
=0; i
<=dim1
-dim2
; i
++) {
67 for (j
=0; j
<dim2
; j
++) {
68 corr
[i
] += seq1
[i
+j
] * seq2
[j
];
73 /*----------------------------------------------------------------*
74 * upsample finite array assuming zeros outside bounds
75 *---------------------------------------------------------------*/
79 static void enh_upsample(
80 float* useq1
, /* (o) upsampled output sequence */
81 float* seq1
,/* (i) unupsampled sequence */
82 int dim1
, /* (i) dimension seq1 */
83 int hfl
/* (i) polyphase filter length=2*hfl+1 */
86 int i
,j
,k
,q
,filterlength
,hfl2
;
87 const float *polyp
[ENH_UPS0
]; /* pointers to
91 /* define pointers for filter */
95 if ( filterlength
> dim1
) {
97 for (j
=0; j
<ENH_UPS0
; j
++) {
98 polyp
[j
]=polyphaserTbl
+j
*filterlength
+hfl
-hfl2
;
101 filterlength
=2*hfl
+1;
104 for (j
=0; j
<ENH_UPS0
; j
++) {
105 polyp
[j
]=polyphaserTbl
+j
*filterlength
;
109 /* filtering: filter overhangs left side of sequence */
112 for (i
=hfl
; i
<filterlength
; i
++) {
113 for (j
=0; j
<ENH_UPS0
; j
++) {
117 for (k
=0; k
<=i
; k
++) {
118 *pu
+= *ps
-- * *pp
++;
124 /* filtering: simple convolution=inner products */
126 for (i
=filterlength
; i
<dim1
; i
++) {
127 for (j
=0;j
<ENH_UPS0
; j
++){
131 for (k
=0; k
<filterlength
; k
++) {
132 *pu
+= *ps
-- * *pp
++;
140 /* filtering: filter overhangs right side of sequence */
142 for (q
=1; q
<=hfl
; q
++) {
143 for (j
=0; j
<ENH_UPS0
; j
++) {
147 for (k
=0; k
<filterlength
-q
; k
++) {
148 *pu
+= *ps
-- * *pp
++;
156 /*----------------------------------------------------------------*
157 * find segment starting near idata+estSegPos that has highest
158 * correlation with idata+centerStartPos through
159 * idata+centerStartPos+ENH_BLOCKL-1 segment is found at a
160 * resolution of ENH_UPSO times the original of the original
162 *---------------------------------------------------------------*/
165 float *seg
, /* (o) segment array */
166 float *updStartPos
, /* (o) updated start point */
167 float* idata
, /* (i) original data buffer */
168 int idatal
, /* (i) dimension of idata */
169 int centerStartPos
, /* (i) beginning center segment */
170 float estSegPos
,/* (i) estimated beginning other segment */
171 float period
/* (i) estimated pitch period */
173 int estSegPosRounded
,searchSegStartPos
,searchSegEndPos
,corrdim
;
174 int tloc
,tloc2
,i
,st
,en
,fraction
;
175 float vect
[ENH_VECTL
],corrVec
[ENH_CORRDIM
],maxv
;
176 float corrVecUps
[ENH_CORRDIM
*ENH_UPS0
];
178 /* defining array bounds */
180 estSegPosRounded
=(int)(estSegPos
- 0.5);
182 searchSegStartPos
=estSegPosRounded
-ENH_SLOP
;
184 if (searchSegStartPos
<0) {
187 searchSegEndPos
=estSegPosRounded
+ENH_SLOP
;
191 if (searchSegEndPos
+ENH_BLOCKL
>= idatal
) {
192 searchSegEndPos
=idatal
-ENH_BLOCKL
-1;
194 corrdim
=searchSegEndPos
-searchSegStartPos
+1;
196 /* compute upsampled correlation (corr33) and find
199 mycorr1(corrVec
,idata
+searchSegStartPos
,
200 corrdim
+ENH_BLOCKL
-1,idata
+centerStartPos
,ENH_BLOCKL
);
201 enh_upsample(corrVecUps
,corrVec
,corrdim
,ENH_FL0
);
202 tloc
=0; maxv
=corrVecUps
[0];
203 for (i
=1; i
<ENH_UPS0
*corrdim
; i
++) {
205 if (corrVecUps
[i
]>maxv
) {
211 /* make vector can be upsampled without ever running outside
214 *updStartPos
= (float)searchSegStartPos
+
215 (float)tloc
/(float)ENH_UPS0
+(float)1.0;
216 tloc2
=(int)(tloc
/ENH_UPS0
);
218 if (tloc
>tloc2
*ENH_UPS0
) {
221 st
=searchSegStartPos
+tloc2
-ENH_FL0
;
224 memset(vect
,0,-st
*sizeof(float));
225 memcpy(&vect
[-st
],idata
, (ENH_VECTL
+st
)*sizeof(float));
231 memcpy(vect
, &idata
[st
],
232 (ENH_VECTL
-(en
-idatal
))*sizeof(float));
233 memset(&vect
[ENH_VECTL
-(en
-idatal
)], 0,
234 (en
-idatal
)*sizeof(float));
237 memcpy(vect
, &idata
[st
], ENH_VECTL
*sizeof(float));
240 fraction
=tloc2
*ENH_UPS0
-tloc
;
242 /* compute the segment (this is actually a convolution) */
244 mycorr1(seg
,vect
,ENH_VECTL
,polyphaserTbl
+(2*ENH_FL0
+1)*fraction
,
250 /*----------------------------------------------------------------*
251 * find the smoothed output data
252 *---------------------------------------------------------------*/
255 float *odata
, /* (o) smoothed output */
256 float *sseq
,/* (i) said second sequence of waveforms */
257 int hl
, /* (i) 2*hl+1 is sseq dimension */
258 float alpha0
/* (i) max smoothing energy fraction */
261 float w00
,w10
,w11
,A
,B
,C
,*psseq
,err
,errs
;
262 float surround
[BLOCKL_MAX
]; /* shape contributed by other than
264 float wt
[2*ENH_HL
+1]; /* waveform weighting to get
268 /* create shape of contribution from all waveforms except the
271 for (i
=1; i
<=2*hl
+1; i
++) {
272 wt
[i
-1] = (float)0.5*(1 - (float)cos(2*PI
*i
/(2*hl
+2)));
274 wt
[hl
]=0.0; /* for clarity, not used */
275 for (i
=0; i
<ENH_BLOCKL
; i
++) {
276 surround
[i
]=sseq
[i
]*wt
[0];
278 for (k
=1; k
<hl
; k
++) {
279 psseq
=sseq
+k
*ENH_BLOCKL
;
280 for(i
=0;i
<ENH_BLOCKL
; i
++) {
281 surround
[i
]+=psseq
[i
]*wt
[k
];
284 for (k
=hl
+1; k
<=2*hl
; k
++) {
285 psseq
=sseq
+k
*ENH_BLOCKL
;
286 for(i
=0;i
<ENH_BLOCKL
; i
++) {
287 surround
[i
]+=psseq
[i
]*wt
[k
];
291 /* compute some inner products */
293 w00
= w10
= w11
= 0.0;
294 psseq
=sseq
+hl
*ENH_BLOCKL
; /* current block */
295 for (i
=0; i
<ENH_BLOCKL
;i
++) {
296 w00
+=psseq
[i
]*psseq
[i
];
297 w11
+=surround
[i
]*surround
[i
];
298 w10
+=surround
[i
]*psseq
[i
];
303 if (fabs(w11
) < 1.0) {
306 C
= (float)sqrt( w00
/w11
);
308 /* first try enhancement without power-constraint */
311 psseq
=sseq
+hl
*ENH_BLOCKL
;
312 for (i
=0; i
<ENH_BLOCKL
; i
++) {
313 odata
[i
]=C
*surround
[i
];
314 err
=psseq
[i
]-odata
[i
];
318 /* if constraint violated by first try, add constraint */
320 if (errs
> alpha0
* w00
) {
324 denom
= (w11
*w00
-w10
*w10
)/(w00
*w00
);
326 if (denom
> 0.0001) { /* eliminates numerical problems
328 A
= (float)sqrt( (alpha0
- alpha0
*alpha0
/4)/denom
);
329 B
= -alpha0
/2 - A
* w10
/w00
;
332 else { /* essentially no difference between cycles;
333 smoothing not needed */
338 /* create smoothed sequence */
340 psseq
=sseq
+hl
*ENH_BLOCKL
;
341 for (i
=0; i
<ENH_BLOCKL
; i
++) {
342 odata
[i
]=A
*surround
[i
]+B
*psseq
[i
];
347 /*----------------------------------------------------------------*
348 * get the pitch-synchronous sample sequence
349 *---------------------------------------------------------------*/
352 float *sseq
, /* (o) the pitch-synchronous sequence */
353 float *idata
, /* (i) original data */
354 int idatal
, /* (i) dimension of data */
355 int centerStartPos
, /* (i) where current block starts */
356 float *period
, /* (i) rough-pitch-period array */
359 float *plocs
, /* (i) where periods of period array
361 int periodl
, /* (i) dimension period array */
362 int hl
/* (i) 2*hl+1 is the number of sequences */
364 int i
,centerEndPos
,q
;
365 float blockStartPos
[2*ENH_HL
+1];
366 int lagBlock
[2*ENH_HL
+1];
367 float plocs2
[ENH_PLOCSL
];
370 centerEndPos
=centerStartPos
+ENH_BLOCKL
-1;
374 NearestNeighbor(lagBlock
+hl
,plocs
,
375 (float)0.5*(centerStartPos
+centerEndPos
),periodl
);
377 blockStartPos
[hl
]=(float)centerStartPos
;
378 psseq
=sseq
+ENH_BLOCKL
*hl
;
379 memcpy(psseq
, idata
+centerStartPos
, ENH_BLOCKL
*sizeof(float));
383 for (q
=hl
-1; q
>=0; q
--) {
384 blockStartPos
[q
]=blockStartPos
[q
+1]-period
[lagBlock
[q
+1]];
385 NearestNeighbor(lagBlock
+q
,plocs
,
387 ENH_BLOCKL_HALF
-period
[lagBlock
[q
+1]], periodl
);
390 if (blockStartPos
[q
]-ENH_OVERHANG
>=0) {
391 refiner(sseq
+q
*ENH_BLOCKL
, blockStartPos
+q
, idata
,
392 idatal
, centerStartPos
, blockStartPos
[q
],
393 period
[lagBlock
[q
+1]]);
395 psseq
=sseq
+q
*ENH_BLOCKL
;
396 memset(psseq
, 0, ENH_BLOCKL
*sizeof(float));
402 for (i
=0; i
<periodl
; i
++) {
403 plocs2
[i
]=plocs
[i
]-period
[i
];
405 for (q
=hl
+1; q
<=2*hl
; q
++) {
406 NearestNeighbor(lagBlock
+q
,plocs2
,
407 blockStartPos
[q
-1]+ENH_BLOCKL_HALF
,periodl
);
409 blockStartPos
[q
]=blockStartPos
[q
-1]+period
[lagBlock
[q
]];
410 if (blockStartPos
[q
]+ENH_BLOCKL
+ENH_OVERHANG
<idatal
) {
411 refiner(sseq
+ENH_BLOCKL
*q
, blockStartPos
+q
, idata
,
412 idatal
, centerStartPos
, blockStartPos
[q
],
415 period
[lagBlock
[q
]]);
418 psseq
=sseq
+q
*ENH_BLOCKL
;
419 memset(psseq
, 0, ENH_BLOCKL
*sizeof(float));
424 /*----------------------------------------------------------------*
425 * perform enhancement on idata+centerStartPos through
426 * idata+centerStartPos+ENH_BLOCKL-1
427 *---------------------------------------------------------------*/
429 static void enhancer(
430 float *odata
, /* (o) smoothed block, dimension blockl */
431 float *idata
, /* (i) data buffer used for enhancing */
432 int idatal
, /* (i) dimension idata */
433 int centerStartPos
, /* (i) first sample current block
435 float alpha0
, /* (i) max correction-energy-fraction
437 float *period
, /* (i) pitch period array */
438 float *plocs
, /* (i) locations where period array
440 int periodl
/* (i) dimension of period and plocs */
442 float sseq
[(2*ENH_HL
+1)*ENH_BLOCKL
];
444 /* get said second sequence of segments */
446 getsseq(sseq
,idata
,idatal
,centerStartPos
,period
,
447 plocs
,periodl
,ENH_HL
);
449 /* compute the smoothed output from said second sequence */
451 smath(odata
,sseq
,ENH_HL
,alpha0
);
455 /*----------------------------------------------------------------*
457 *---------------------------------------------------------------*/
460 float *target
, /* (i) first array */
461 float *regressor
, /* (i) second array */
462 int subl
/* (i) dimension arrays */
471 for (i
=0; i
<subl
; i
++) {
472 ftmp1
+= target
[i
]*regressor
[i
];
473 ftmp2
+= regressor
[i
]*regressor
[i
];
477 return (float)(ftmp1
*ftmp1
/ftmp2
);
484 /*----------------------------------------------------------------*
485 * interface for enhancer
486 *---------------------------------------------------------------*/
488 int enhancerInterface(
489 float *out
, /* (o) enhanced signal */
490 float *in
, /* (i) unenhanced signal */
491 iLBC_Dec_Inst_t
*iLBCdec_inst
/* (i) buffers etc */
493 float *enh_buf
, *enh_period
;
495 int lag
=0, ilag
, i
, ioffset
;
498 float *inPtr
, *enh_bufPtr1
, *enh_bufPtr2
;
499 float plc_pred
[ENH_BLOCKL
];
501 float lpState
[6], downsampled
[(ENH_NBLOCKS
*ENH_BLOCKL
+120)/2];
502 int inLen
=ENH_NBLOCKS
*ENH_BLOCKL
+120;
503 int start
, plc_blockl
, inlag
;
505 enh_buf
=iLBCdec_inst
->enh_buf
;
506 enh_period
=iLBCdec_inst
->enh_period
;
508 memmove(enh_buf
, &enh_buf
[iLBCdec_inst
->blockl
],
509 (ENH_BUFL
-iLBCdec_inst
->blockl
)*sizeof(float));
511 memcpy(&enh_buf
[ENH_BUFL
-iLBCdec_inst
->blockl
], in
,
512 iLBCdec_inst
->blockl
*sizeof(float));
514 if (iLBCdec_inst
->mode
==30)
515 plc_blockl
=ENH_BLOCKL
;
519 /* when 20 ms frame, move processing one block */
521 if (iLBCdec_inst
->mode
==20) ioffset
=1;
524 memmove(enh_period
, &enh_period
[i
],
527 (ENH_NBLOCKS_TOT
-i
)*sizeof(float));
529 /* Set state information to the 6 samples right before
530 the samples to be downsampled. */
533 enh_buf
+(ENH_NBLOCKS_EXTRA
+ioffset
)*ENH_BLOCKL
-126,
536 /* Down sample a factor 2 to save computations */
538 DownSample(enh_buf
+(ENH_NBLOCKS_EXTRA
+ioffset
)*ENH_BLOCKL
-120,
539 lpFilt_coefsTbl
, inLen
-ioffset
*ENH_BLOCKL
,
540 lpState
, downsampled
);
542 /* Estimate the pitch in the down sampled domain. */
543 for (iblock
= 0; iblock
<ENH_NBLOCKS
-ioffset
; iblock
++) {
546 maxcc
= xCorrCoef(downsampled
+60+iblock
*
547 ENH_BLOCKL_HALF
, downsampled
+60+iblock
*
548 ENH_BLOCKL_HALF
-lag
, ENH_BLOCKL_HALF
);
549 for (ilag
=11; ilag
<60; ilag
++) {
550 cc
= xCorrCoef(downsampled
+60+iblock
*
551 ENH_BLOCKL_HALF
, downsampled
+60+iblock
*
552 ENH_BLOCKL_HALF
-ilag
, ENH_BLOCKL_HALF
);
560 /* Store the estimated lag in the non-downsampled domain */
561 enh_period
[iblock
+ENH_NBLOCKS_EXTRA
+ioffset
] = (float)lag
*2;
567 /* PLC was performed on the previous packet */
568 if (iLBCdec_inst
->prev_enh_pl
==1) {
570 inlag
=(int)enh_period
[ENH_NBLOCKS_EXTRA
+ioffset
];
573 maxcc
= xCorrCoef(in
, in
+lag
, plc_blockl
);
574 for (ilag
=inlag
; ilag
<=inlag
+1; ilag
++) {
575 cc
= xCorrCoef(in
, in
+ilag
, plc_blockl
);
585 enh_period
[ENH_NBLOCKS_EXTRA
+ioffset
-1]=(float)lag
;
587 /* compute new concealed residual for the old lookahead,
588 mix the forward PLC with a backward PLC from
593 enh_bufPtr1
=&plc_pred
[plc_blockl
-1];
595 if (lag
>plc_blockl
) {
601 for (isample
= start
; isample
>0; isample
--) {
602 *enh_bufPtr1
-- = *inPtr
--;
605 enh_bufPtr2
=&enh_buf
[ENH_BUFL
-1-iLBCdec_inst
->blockl
];
606 for (isample
= (plc_blockl
-1-lag
); isample
>=0; isample
--)
608 *enh_bufPtr1
-- = *enh_bufPtr2
--;
611 /* limit energy change */
614 for (i
=0;i
<plc_blockl
;i
++) {
615 ftmp2
+=enh_buf
[ENH_BUFL
-1-iLBCdec_inst
->blockl
-i
]*
616 enh_buf
[ENH_BUFL
-1-iLBCdec_inst
->blockl
-i
];
617 ftmp1
+=plc_pred
[i
]*plc_pred
[i
];
619 ftmp1
=(float)sqrt(ftmp1
/(float)plc_blockl
);
620 ftmp2
=(float)sqrt(ftmp2
/(float)plc_blockl
);
621 if (ftmp1
>(float)2.0*ftmp2
&& ftmp1
>0.0) {
622 for (i
=0;i
<plc_blockl
-10;i
++) {
623 plc_pred
[i
]*=(float)2.0*ftmp2
/ftmp1
;
625 for (i
=plc_blockl
-10;i
<plc_blockl
;i
++) {
626 plc_pred
[i
]*=(float)(i
-plc_blockl
+10)*
627 ((float)1.0-(float)2.0*ftmp2
/ftmp1
)/(float)(10)+
628 (float)2.0*ftmp2
/ftmp1
;
632 enh_bufPtr1
=&enh_buf
[ENH_BUFL
-1-iLBCdec_inst
->blockl
];
633 for (i
=0; i
<plc_blockl
; i
++) {
634 ftmp1
= (float) (i
+1) / (float) (plc_blockl
+1);
635 *enh_bufPtr1
*= ftmp1
;
636 *enh_bufPtr1
+= ((float)1.0-ftmp1
)*
637 plc_pred
[plc_blockl
-1-i
];
644 if (iLBCdec_inst
->mode
==20) {
645 /* Enhancer with 40 samples delay */
646 for (iblock
= 0; iblock
<2; iblock
++) {
647 enhancer(out
+iblock
*ENH_BLOCKL
, enh_buf
,
648 ENH_BUFL
, (5+iblock
)*ENH_BLOCKL
+40,
649 ENH_ALPHA0
, enh_period
, enh_plocsTbl
,
652 } else if (iLBCdec_inst
->mode
==30) {
653 /* Enhancer with 80 samples delay */
654 for (iblock
= 0; iblock
<3; iblock
++) {
655 enhancer(out
+iblock
*ENH_BLOCKL
, enh_buf
,
656 ENH_BUFL
, (4+iblock
)*ENH_BLOCKL
,
657 ENH_ALPHA0
, enh_period
, enh_plocsTbl
,