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