/****************************************************************** | |
iLBC Speech Coder ANSI-C Source Code | |
iCBSearch.c | |
Copyright (C) The Internet Society (2004). | |
All Rights Reserved. | |
******************************************************************/ | |
#include <math.h> | |
#include <string.h> | |
#include "iLBC_define.h" | |
#include "gainquant.h" | |
#include "createCB.h" | |
#include "filter.h" | |
#include "constants.h" | |
/*----------------------------------------------------------------* | |
* Search routine for codebook encoding and gain quantization. | |
*---------------------------------------------------------------*/ | |
void iCBSearch( | |
iLBC_Enc_Inst_t *iLBCenc_inst, | |
/* (i) the encoder state structure */ | |
int *index, /* (o) Codebook indices */ | |
int *gain_index,/* (o) Gain quantization indices */ | |
float *intarget,/* (i) Target vector for encoding */ | |
float *mem, /* (i) Buffer for codebook construction */ | |
int lMem, /* (i) Length of buffer */ | |
int lTarget, /* (i) Length of vector */ | |
int nStages, /* (i) Number of codebook stages */ | |
float *weightDenum, /* (i) weighting filter coefficients */ | |
float *weightState, /* (i) weighting filter state */ | |
int block /* (i) the sub-block number */ | |
){ | |
int i, j, icount, stage, best_index, range, counter; | |
float max_measure, gain, measure, crossDot, ftmp; | |
float gains[CB_NSTAGES]; | |
float target[SUBL]; | |
int base_index, sInd, eInd, base_size; | |
int sIndAug=0, eIndAug=0; | |
float buf[CB_MEML+SUBL+2*LPC_FILTERORDER]; | |
float invenergy[CB_EXPAND*128], energy[CB_EXPAND*128]; | |
float *pp, *ppi=0, *ppo=0, *ppe=0; | |
float cbvectors[CB_MEML]; | |
float tene, cene, cvec[SUBL]; | |
float aug_vec[SUBL]; | |
memset(cvec,0,SUBL*sizeof(float)); | |
/* Determine size of codebook sections */ | |
base_size=lMem-lTarget+1; | |
if (lTarget==SUBL) { | |
base_size=lMem-lTarget+1+lTarget/2; | |
} | |
/* setup buffer for weighting */ | |
memcpy(buf,weightState,sizeof(float)*LPC_FILTERORDER); | |
memcpy(buf+LPC_FILTERORDER,mem,lMem*sizeof(float)); | |
memcpy(buf+LPC_FILTERORDER+lMem,intarget,lTarget*sizeof(float)); | |
/* weighting */ | |
AllPoleFilter(buf+LPC_FILTERORDER, weightDenum, | |
lMem+lTarget, LPC_FILTERORDER); | |
/* Construct the codebook and target needed */ | |
memcpy(target, buf+LPC_FILTERORDER+lMem, lTarget*sizeof(float)); | |
tene=0.0; | |
for (i=0; i<lTarget; i++) { | |
tene+=target[i]*target[i]; | |
} | |
/* Prepare search over one more codebook section. This section | |
is created by filtering the original buffer with a filter. */ | |
filteredCBvecs(cbvectors, buf+LPC_FILTERORDER, lMem); | |
/* The Main Loop over stages */ | |
for (stage=0; stage<nStages; stage++) { | |
range = search_rangeTbl[block][stage]; | |
/* initialize search measure */ | |
max_measure = (float)-10000000.0; | |
gain = (float)0.0; | |
best_index = 0; | |
/* Compute cross dot product between the target | |
and the CB memory */ | |
crossDot=0.0; | |
pp=buf+LPC_FILTERORDER+lMem-lTarget; | |
for (j=0; j<lTarget; j++) { | |
crossDot += target[j]*(*pp++); | |
} | |
if (stage==0) { | |
/* Calculate energy in the first block of | |
'lTarget' samples. */ | |
ppe = energy; | |
ppi = buf+LPC_FILTERORDER+lMem-lTarget-1; | |
ppo = buf+LPC_FILTERORDER+lMem-1; | |
*ppe=0.0; | |
pp=buf+LPC_FILTERORDER+lMem-lTarget; | |
for (j=0; j<lTarget; j++) { | |
*ppe+=(*pp)*(*pp); | |
++pp; | |
} | |
if (*ppe>0.0) { | |
invenergy[0] = (float) 1.0 / (*ppe + EPS); | |
} else { | |
invenergy[0] = (float) 0.0; | |
} | |
ppe++; | |
measure=(float)-10000000.0; | |
if (crossDot > 0.0) { | |
measure = crossDot*crossDot*invenergy[0]; | |
} | |
} | |
else { | |
measure = crossDot*crossDot*invenergy[0]; | |
} | |
/* check if measure is better */ | |
ftmp = crossDot*invenergy[0]; | |
if ((measure>max_measure) && (fabs(ftmp)<CB_MAXGAIN)) { | |
best_index = 0; | |
max_measure = measure; | |
gain = ftmp; | |
} | |
/* loop over the main first codebook section, | |
full search */ | |
for (icount=1; icount<range; icount++) { | |
/* calculate measure */ | |
crossDot=0.0; | |
pp = buf+LPC_FILTERORDER+lMem-lTarget-icount; | |
for (j=0; j<lTarget; j++) { | |
crossDot += target[j]*(*pp++); | |
} | |
if (stage==0) { | |
*ppe++ = energy[icount-1] + (*ppi)*(*ppi) - | |
(*ppo)*(*ppo); | |
ppo--; | |
ppi--; | |
if (energy[icount]>0.0) { | |
invenergy[icount] = | |
(float)1.0/(energy[icount]+EPS); | |
} else { | |
invenergy[icount] = (float) 0.0; | |
} | |
measure=(float)-10000000.0; | |
if (crossDot > 0.0) { | |
measure = crossDot*crossDot*invenergy[icount]; | |
} | |
} | |
else { | |
measure = crossDot*crossDot*invenergy[icount]; | |
} | |
/* check if measure is better */ | |
ftmp = crossDot*invenergy[icount]; | |
if ((measure>max_measure) && (fabs(ftmp)<CB_MAXGAIN)) { | |
best_index = icount; | |
max_measure = measure; | |
gain = ftmp; | |
} | |
} | |
/* Loop over augmented part in the first codebook | |
* section, full search. | |
* The vectors are interpolated. | |
*/ | |
if (lTarget==SUBL) { | |
/* Search for best possible cb vector and | |
compute the CB-vectors' energy. */ | |
searchAugmentedCB(20, 39, stage, base_size-lTarget/2, | |
target, buf+LPC_FILTERORDER+lMem, | |
&max_measure, &best_index, &gain, energy, | |
invenergy); | |
} | |
/* set search range for following codebook sections */ | |
base_index=best_index; | |
/* unrestricted search */ | |
if (CB_RESRANGE == -1) { | |
sInd=0; | |
eInd=range-1; | |
sIndAug=20; | |
eIndAug=39; | |
} | |
/* restricted search around best index from first | |
codebook section */ | |
else { | |
/* Initialize search indices */ | |
sIndAug=0; | |
eIndAug=0; | |
sInd=base_index-CB_RESRANGE/2; | |
eInd=sInd+CB_RESRANGE; | |
if (lTarget==SUBL) { | |
if (sInd<0) { | |
sIndAug = 40 + sInd; | |
eIndAug = 39; | |
sInd=0; | |
} else if ( base_index < (base_size-20) ) { | |
if (eInd > range) { | |
sInd -= (eInd-range); | |
eInd = range; | |
} | |
} else { /* base_index >= (base_size-20) */ | |
if (sInd < (base_size-20)) { | |
sIndAug = 20; | |
sInd = 0; | |
eInd = 0; | |
eIndAug = 19 + CB_RESRANGE; | |
if(eIndAug > 39) { | |
eInd = eIndAug-39; | |
eIndAug = 39; | |
} | |
} else { | |
sIndAug = 20 + sInd - (base_size-20); | |
eIndAug = 39; | |
sInd = 0; | |
eInd = CB_RESRANGE - (eIndAug-sIndAug+1); | |
} | |
} | |
} else { /* lTarget = 22 or 23 */ | |
if (sInd < 0) { | |
eInd -= sInd; | |
sInd = 0; | |
} | |
if(eInd > range) { | |
sInd -= (eInd - range); | |
eInd = range; | |
} | |
} | |
} | |
/* search of higher codebook section */ | |
/* index search range */ | |
counter = sInd; | |
sInd += base_size; | |
eInd += base_size; | |
if (stage==0) { | |
ppe = energy+base_size; | |
*ppe=0.0; | |
pp=cbvectors+lMem-lTarget; | |
for (j=0; j<lTarget; j++) { | |
*ppe+=(*pp)*(*pp); | |
++pp; | |
} | |
ppi = cbvectors + lMem - 1 - lTarget; | |
ppo = cbvectors + lMem - 1; | |
for (j=0; j<(range-1); j++) { | |
*(ppe+1) = *ppe + (*ppi)*(*ppi) - (*ppo)*(*ppo); | |
ppo--; | |
ppi--; | |
ppe++; | |
} | |
} | |
/* loop over search range */ | |
for (icount=sInd; icount<eInd; icount++) { | |
/* calculate measure */ | |
crossDot=0.0; | |
pp=cbvectors + lMem - (counter++) - lTarget; | |
for (j=0;j<lTarget;j++) { | |
crossDot += target[j]*(*pp++); | |
} | |
if (energy[icount]>0.0) { | |
invenergy[icount] =(float)1.0/(energy[icount]+EPS); | |
} else { | |
invenergy[icount] =(float)0.0; | |
} | |
if (stage==0) { | |
measure=(float)-10000000.0; | |
if (crossDot > 0.0) { | |
measure = crossDot*crossDot* | |
invenergy[icount]; | |
} | |
} | |
else { | |
measure = crossDot*crossDot*invenergy[icount]; | |
} | |
/* check if measure is better */ | |
ftmp = crossDot*invenergy[icount]; | |
if ((measure>max_measure) && (fabs(ftmp)<CB_MAXGAIN)) { | |
best_index = icount; | |
max_measure = measure; | |
gain = ftmp; | |
} | |
} | |
/* Search the augmented CB inside the limited range. */ | |
if ((lTarget==SUBL)&&(sIndAug!=0)) { | |
searchAugmentedCB(sIndAug, eIndAug, stage, | |
2*base_size-20, target, cbvectors+lMem, | |
&max_measure, &best_index, &gain, energy, | |
invenergy); | |
} | |
/* record best index */ | |
index[stage] = best_index; | |
/* gain quantization */ | |
if (stage==0){ | |
if (gain<0.0){ | |
gain = 0.0; | |
} | |
if (gain>CB_MAXGAIN) { | |
gain = (float)CB_MAXGAIN; | |
} | |
gain = gainquant(gain, 1.0, 32, &gain_index[stage]); | |
} | |
else { | |
if (stage==1) { | |
gain = gainquant(gain, (float)fabs(gains[stage-1]), | |
16, &gain_index[stage]); | |
} else { | |
gain = gainquant(gain, (float)fabs(gains[stage-1]), | |
8, &gain_index[stage]); | |
} | |
} | |
/* Extract the best (according to measure) | |
codebook vector */ | |
if (lTarget==(STATE_LEN-iLBCenc_inst->state_short_len)) { | |
if (index[stage]<base_size) { | |
pp=buf+LPC_FILTERORDER+lMem-lTarget-index[stage]; | |
} else { | |
pp=cbvectors+lMem-lTarget- | |
index[stage]+base_size; | |
} | |
} else { | |
if (index[stage]<base_size) { | |
if (index[stage]<(base_size-20)) { | |
pp=buf+LPC_FILTERORDER+lMem- | |
lTarget-index[stage]; | |
} else { | |
createAugmentedVec(index[stage]-base_size+40, | |
buf+LPC_FILTERORDER+lMem,aug_vec); | |
pp=aug_vec; | |
} | |
} else { | |
int filterno, position; | |
filterno=index[stage]/base_size; | |
position=index[stage]-filterno*base_size; | |
if (position<(base_size-20)) { | |
pp=cbvectors+filterno*lMem-lTarget- | |
index[stage]+filterno*base_size; | |
} else { | |
createAugmentedVec( | |
index[stage]-(filterno+1)*base_size+40, | |
cbvectors+filterno*lMem,aug_vec); | |
pp=aug_vec; | |
} | |
} | |
} | |
/* Subtract the best codebook vector, according | |
to measure, from the target vector */ | |
for (j=0;j<lTarget;j++) { | |
cvec[j] += gain*(*pp); | |
target[j] -= gain*(*pp++); | |
} | |
/* record quantized gain */ | |
gains[stage]=gain; | |
}/* end of Main Loop. for (stage=0;... */ | |
/* Gain adjustment for energy matching */ | |
cene=0.0; | |
for (i=0; i<lTarget; i++) { | |
cene+=cvec[i]*cvec[i]; | |
} | |
j=gain_index[0]; | |
for (i=gain_index[0]; i<32; i++) { | |
ftmp=cene*gain_sq5Tbl[i]*gain_sq5Tbl[i]; | |
if ((ftmp<(tene*gains[0]*gains[0])) && | |
(gain_sq5Tbl[j]<(2.0*gains[0]))) { | |
j=i; | |
} | |
} | |
gain_index[0]=j; | |
} | |