/****************************************************************** | |
iLBC Speech Coder ANSI-C Source Code | |
doCPLC.c | |
Copyright (C) The Internet Society (2004). | |
All Rights Reserved. | |
******************************************************************/ | |
#include <math.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include "iLBC_define.h" | |
/*----------------------------------------------------------------* | |
* Compute cross correlation and pitch gain for pitch prediction | |
* of last subframe at given lag. | |
*---------------------------------------------------------------*/ | |
void compCorr( | |
float *cc, /* (o) cross correlation coefficient */ | |
float *gc, /* (o) gain */ | |
float *pm, | |
float *buffer, /* (i) signal buffer */ | |
int lag, /* (i) pitch lag */ | |
int bLen, /* (i) length of buffer */ | |
int sRange /* (i) correlation search length */ | |
){ | |
int i; | |
float ftmp1, ftmp2, ftmp3; | |
/* Guard against getting outside buffer */ | |
if ((bLen-sRange-lag)<0) { | |
sRange=bLen-lag; | |
} | |
ftmp1 = 0.0; | |
ftmp2 = 0.0; | |
ftmp3 = 0.0; | |
for (i=0; i<sRange; i++) { | |
ftmp1 += buffer[bLen-sRange+i] * | |
buffer[bLen-sRange+i-lag]; | |
ftmp2 += buffer[bLen-sRange+i-lag] * | |
buffer[bLen-sRange+i-lag]; | |
ftmp3 += buffer[bLen-sRange+i] * | |
buffer[bLen-sRange+i]; | |
} | |
if (ftmp2 > 0.0) { | |
*cc = ftmp1*ftmp1/ftmp2; | |
*gc = (float)fabs(ftmp1/ftmp2); | |
*pm=(float)fabs(ftmp1)/ | |
((float)sqrt(ftmp2)*(float)sqrt(ftmp3)); | |
} | |
else { | |
*cc = 0.0; | |
*gc = 0.0; | |
*pm=0.0; | |
} | |
} | |
/*----------------------------------------------------------------* | |
* Packet loss concealment routine. Conceals a residual signal | |
* and LP parameters. If no packet loss, update state. | |
*---------------------------------------------------------------*/ | |
void doThePLC( | |
float *PLCresidual, /* (o) concealed residual */ | |
float *PLClpc, /* (o) concealed LP parameters */ | |
int PLI, /* (i) packet loss indicator | |
0 - no PL, 1 = PL */ | |
float *decresidual, /* (i) decoded residual */ | |
float *lpc, /* (i) decoded LPC (only used for no PL) */ | |
int inlag, /* (i) pitch lag */ | |
iLBC_Dec_Inst_t *iLBCdec_inst | |
/* (i/o) decoder instance */ | |
){ | |
int lag=20, randlag; | |
float gain, maxcc; | |
float use_gain; | |
float gain_comp, maxcc_comp, per, max_per=0; | |
int i, pick, use_lag; | |
float ftmp, randvec[BLOCKL_MAX], pitchfact, energy; | |
/* Packet Loss */ | |
if (PLI == 1) { | |
iLBCdec_inst->consPLICount += 1; | |
/* if previous frame not lost, | |
determine pitch pred. gain */ | |
if (iLBCdec_inst->prevPLI != 1) { | |
/* Search around the previous lag to find the | |
best pitch period */ | |
lag=inlag-3; | |
compCorr(&maxcc, &gain, &max_per, | |
iLBCdec_inst->prevResidual, | |
lag, iLBCdec_inst->blockl, 60); | |
for (i=inlag-2;i<=inlag+3;i++) { | |
compCorr(&maxcc_comp, &gain_comp, &per, | |
iLBCdec_inst->prevResidual, | |
i, iLBCdec_inst->blockl, 60); | |
if (maxcc_comp>maxcc) { | |
maxcc=maxcc_comp; | |
gain=gain_comp; | |
lag=i; | |
max_per=per; | |
} | |
} | |
} | |
/* previous frame lost, use recorded lag and periodicity */ | |
else { | |
lag=iLBCdec_inst->prevLag; | |
max_per=iLBCdec_inst->per; | |
} | |
/* downscaling */ | |
use_gain=1.0; | |
if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>320) | |
use_gain=(float)0.9; | |
else if (iLBCdec_inst->consPLICount* | |
iLBCdec_inst->blockl>2*320) | |
use_gain=(float)0.7; | |
else if (iLBCdec_inst->consPLICount* | |
iLBCdec_inst->blockl>3*320) | |
use_gain=(float)0.5; | |
else if (iLBCdec_inst->consPLICount* | |
iLBCdec_inst->blockl>4*320) | |
use_gain=(float)0.0; | |
/* mix noise and pitch repeatition */ | |
ftmp=(float)sqrt(max_per); | |
if (ftmp>(float)0.7) | |
pitchfact=(float)1.0; | |
else if (ftmp>(float)0.4) | |
pitchfact=(ftmp-(float)0.4)/((float)0.7-(float)0.4); | |
else | |
pitchfact=0.0; | |
/* avoid repetition of same pitch cycle */ | |
use_lag=lag; | |
if (lag<80) { | |
use_lag=2*lag; | |
} | |
/* compute concealed residual */ | |
energy = 0.0; | |
for (i=0; i<iLBCdec_inst->blockl; i++) { | |
/* noise component */ | |
iLBCdec_inst->seed=(iLBCdec_inst->seed*69069L+1) & | |
(0x80000000L-1); | |
randlag = 50 + ((signed long) iLBCdec_inst->seed)%70; | |
pick = i - randlag; | |
if (pick < 0) { | |
randvec[i] = | |
iLBCdec_inst->prevResidual[ | |
iLBCdec_inst->blockl+pick]; | |
} else { | |
randvec[i] = randvec[pick]; | |
} | |
/* pitch repeatition component */ | |
pick = i - use_lag; | |
if (pick < 0) { | |
PLCresidual[i] = | |
iLBCdec_inst->prevResidual[ | |
iLBCdec_inst->blockl+pick]; | |
} else { | |
PLCresidual[i] = PLCresidual[pick]; | |
} | |
/* mix random and periodicity component */ | |
if (i<80) | |
PLCresidual[i] = use_gain*(pitchfact * | |
PLCresidual[i] + | |
((float)1.0 - pitchfact) * randvec[i]); | |
else if (i<160) | |
PLCresidual[i] = (float)0.95*use_gain*(pitchfact * | |
PLCresidual[i] + | |
((float)1.0 - pitchfact) * randvec[i]); | |
else | |
PLCresidual[i] = (float)0.9*use_gain*(pitchfact * | |
PLCresidual[i] + | |
((float)1.0 - pitchfact) * randvec[i]); | |
energy += PLCresidual[i] * PLCresidual[i]; | |
} | |
/* less than 30 dB, use only noise */ | |
if (sqrt(energy/(float)iLBCdec_inst->blockl) < 30.0) { | |
gain=0.0; | |
for (i=0; i<iLBCdec_inst->blockl; i++) { | |
PLCresidual[i] = randvec[i]; | |
} | |
} | |
/* use old LPC */ | |
memcpy(PLClpc,iLBCdec_inst->prevLpc, | |
(LPC_FILTERORDER+1)*sizeof(float)); | |
} | |
/* no packet loss, copy input */ | |
else { | |
memcpy(PLCresidual, decresidual, | |
iLBCdec_inst->blockl*sizeof(float)); | |
memcpy(PLClpc, lpc, (LPC_FILTERORDER+1)*sizeof(float)); | |
iLBCdec_inst->consPLICount = 0; | |
} | |
/* update state */ | |
if (PLI) { | |
iLBCdec_inst->prevLag = lag; | |
iLBCdec_inst->per=max_per; | |
} | |
iLBCdec_inst->prevPLI = PLI; | |
memcpy(iLBCdec_inst->prevLpc, PLClpc, | |
(LPC_FILTERORDER+1)*sizeof(float)); | |
memcpy(iLBCdec_inst->prevResidual, PLCresidual, | |
iLBCdec_inst->blockl*sizeof(float)); | |
} | |