git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@7221 65c4cc65-6c06-0410-ace0-fbb531ad65f3
260 lines
7.2 KiB
C
260 lines
7.2 KiB
C
|
|
/******************************************************************
|
|
|
|
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"
|
|
#include "doCPLC.h"
|
|
|
|
/*----------------------------------------------------------------*
|
|
* Compute cross correlation and pitch gain for pitch prediction
|
|
* of last subframe at given lag.
|
|
*---------------------------------------------------------------*/
|
|
|
|
static 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;
|
|
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));
|
|
}
|
|
|
|
|
|
|
|
|