diff options
Diffstat (limited to 'codecs/ilbc/doCPLC.c')
-rwxr-xr-x | codecs/ilbc/doCPLC.c | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/codecs/ilbc/doCPLC.c b/codecs/ilbc/doCPLC.c new file mode 100755 index 000000000..0b0083b09 --- /dev/null +++ b/codecs/ilbc/doCPLC.c @@ -0,0 +1,303 @@ + +/****************************************************************** + + iLBC Speech Coder ANSI-C Source Code + + doCPLC.c + + Copyright (c) 2001, + Global IP Sound AB. + All rights reserved. + +******************************************************************/ + +#include <math.h> +#include <string.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 *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; + + ftmp1 = 0.0; + ftmp2 = 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]; + } + + if (ftmp2 > 0.0) { + *cc = ftmp1*ftmp1/ftmp2; + *gc = (float)fabs(ftmp1/ftmp2); + } + else { + *cc = 0.0; + *gc = 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 gain_comp, maxcc_comp; + int i, pick, offset; + float ftmp, ftmp1, randvec[BLOCKL], pitchfact; + + /* 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, (*iLBCdec_inst).prevResidual, + lag, BLOCKL, 60); + for (i=inlag-2;i<=inlag+3;i++) { + compCorr(&maxcc_comp, &gain_comp, + (*iLBCdec_inst).prevResidual, + i, BLOCKL, 60); + + if (maxcc_comp>maxcc) { + maxcc=maxcc_comp; + gain=gain_comp; + lag=i; + } + } + + if (gain > 1.0) { + gain = 1.0; + } + } + + /* previous frame lost, use recorded lag and gain */ + + else { + lag=(*iLBCdec_inst).prevLag; + gain=(*iLBCdec_inst).prevGain; + } + + /* Attenuate signal and scale down pitch pred gain if + several frames lost consecutively */ + + + if ((*iLBCdec_inst).consPLICount > 1) { + gain *= (float)0.9; + } + + /* Compute mixing factor of picth repeatition and noise */ + + + if (gain > PLC_XT_MIX) { + pitchfact = PLC_YT_MIX; + } else if (gain < PLC_XB_MIX) { + pitchfact = PLC_YB_MIX; + } else { + pitchfact = PLC_YB_MIX + (gain - PLC_XB_MIX) * + (PLC_YT_MIX-PLC_YB_MIX)/(PLC_XT_MIX-PLC_XB_MIX); + } + + /* compute concealed residual */ + + (*iLBCdec_inst).energy = 0.0; + for (i=0; i<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] = gain * + (*iLBCdec_inst).prevResidual[BLOCKL+pick]; + } else { + randvec[i] = gain * randvec[pick]; + } + + /* pitch repeatition component */ + + pick = i - lag; + + if (pick < 0) { + PLCresidual[i] = gain * + (*iLBCdec_inst).prevResidual[BLOCKL+pick]; + } else { + PLCresidual[i] = gain * PLCresidual[pick]; + } + + /* mix noise and pitch repeatition */ + + PLCresidual[i] = (pitchfact * PLCresidual[i] + + ((float)1.0 - pitchfact) * randvec[i]); + + (*iLBCdec_inst).energy += PLCresidual[i] * + PLCresidual[i]; + } + + /* less than 30 dB, use only noise */ + + if (sqrt((*iLBCdec_inst).energy/(float)BLOCKL) < 30.0) { + (*iLBCdec_inst).energy = 0.0; + gain=0.0; + for (i=0; i<BLOCKL; i++) { + PLCresidual[i] = randvec[i]; + (*iLBCdec_inst).energy += PLCresidual[i] * + PLCresidual[i]; + } + } + + /* conceal LPC by bandwidth expansion of old LPC */ + + ftmp=PLC_BWEXPAND; + PLClpc[0]=(float)1.0; + for (i=1; i<LPC_FILTERORDER+1; i++) { + PLClpc[i] = ftmp * (*iLBCdec_inst).prevLpc[i]; + ftmp *= PLC_BWEXPAND; + } + + } + + /* previous frame lost and this frame OK, mixing in + with new frame */ + + else if ((*iLBCdec_inst).prevPLI == 1) { + + lag = (*iLBCdec_inst).prevLag; + gain = (*iLBCdec_inst).prevGain; + + /* if pitch pred gain high, do overlap-add */ + + if (gain >= PLC_GAINTHRESHOLD) { + + /* Compute mixing factor of pitch repeatition + and noise */ + + if (gain > PLC_XT_MIX) { + pitchfact = PLC_YT_MIX; + } else if (gain < PLC_XB_MIX) { + pitchfact = PLC_YB_MIX; + } else { + pitchfact = PLC_YB_MIX + (gain - PLC_XB_MIX) * + (PLC_YT_MIX-PLC_YB_MIX)/(PLC_XT_MIX-PLC_XB_MIX); + } + + /* compute concealed residual for 3 subframes */ + + for (i=0; i<3*SUBL; i++) { + + (*iLBCdec_inst).seed=((*iLBCdec_inst).seed* + 69069L+1) & (0x80000000L-1); + randlag = 50 + ((signed long) + (*iLBCdec_inst).seed)%70; + + /* noise component */ + + pick = i - randlag; + + if (pick < 0) { + randvec[i] = gain * + (*iLBCdec_inst).prevResidual[BLOCKL+pick]; + } else { + randvec[i] = gain * randvec[pick]; + } + + /* pitch repeatition component */ + + pick = i - lag; + + if (pick < 0) { + PLCresidual[i] = gain * + (*iLBCdec_inst).prevResidual[BLOCKL+pick]; + } else { + PLCresidual[i] = gain * PLCresidual[pick]; + } + + /* mix noise and pitch repeatition */ + + PLCresidual[i] = (pitchfact * PLCresidual[i] + + ((float)1.0 - pitchfact) * randvec[i]); + } + + /* interpolate concealed residual with actual + residual */ + + offset = 3*SUBL; + for (i=0; i<offset; i++) { + ftmp1 = (float) (i+1) / (float) (offset+1); + ftmp = (float)1.0 - ftmp1; + PLCresidual[i]=PLCresidual[i]*ftmp+ + decresidual[i]*ftmp1; + } + + memcpy(PLCresidual+offset, decresidual+offset, + (BLOCKL-offset)*sizeof(float)); + + } else { + memcpy(PLCresidual, decresidual, BLOCKL*sizeof(float)); + } + + /* copy LPC */ + + memcpy(PLClpc, lpc, (LPC_FILTERORDER+1)*sizeof(float)); + + (*iLBCdec_inst).consPLICount = 0; + } + + /* no packet loss, copy input */ + + else { + memcpy(PLCresidual, decresidual, BLOCKL*sizeof(float)); + memcpy(PLClpc, lpc, (LPC_FILTERORDER+1)*sizeof(float)); + } + + /* update state */ + + (*iLBCdec_inst).prevLag = lag; + (*iLBCdec_inst).prevGain = gain; + (*iLBCdec_inst).prevPLI = PLI; + memcpy((*iLBCdec_inst).prevLpc, PLClpc, + (LPC_FILTERORDER+1)*sizeof(float)); + memcpy((*iLBCdec_inst).prevResidual, PLCresidual, + BLOCKL*sizeof(float)); +} + + |