/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
//package net.java.sip.communicator.impl.media.codec.audio.ilbc;
package org.red5.app.sip.codecs.ilbc;
/**
* @author Jean Lorchat
*/
public class ilbc_decoder {
int consPLICount;
int prevPLI;
int prevLag;
int last_lag;
int prev_enh_pl;
float per;
float prevResidual[];
long seed;
float prevLpc[];
ilbc_ulp ULP_inst = null;
float syntMem[];
float lsfdeqold[];
float old_syntdenum[];
float hpomem[];
int use_enhancer;
float enh_buf[];
float enh_period[];
// La plupart des variables globales sont dans ilbc_constants.etc...
void syntFilter(
float Out[], /* (i/o) Signal to be filtered */
int Out_idx,
float a[], /* (i) LP parameters */
int a_idx,
int len, /* (i) Length of signal */
float mem[]) /* (i/o) Filter state */
{
int i, j;
// float *po, *pi, *pa, *pm;
int po, pi, pa, pm;
// System.out.println("out size : " + Out.length);
// System.out.println("out idx : " + Out_idx);
// System.out.println("a size : " + a.length);
// System.out.println("a idx : " + a_idx);
// System.out.println("len : " + len);
// System.out.println("mem size : " + mem.length);
po = Out_idx;
/* Filter first part using memory from past */
for (i=0; i<ilbc_constants.LPC_FILTERORDER; i++) {
// pi=&Out[i-1];
// pa=&a[1];
// pm=&mem[LPC_FILTERORDER-1];
pi = Out_idx + i - 1;
pa = a_idx + 1;
pm = ilbc_constants.LPC_FILTERORDER - 1;
for (j=1; j<=i; j++) {
// *po-=(*pa++)*(*pi--);
// System.out.println("1 Soustraction (" + i + "," + j + ") a " + Out[po] + " de " + a[pa] + " * " + Out[pi]);
// System.out.println("index " + (po - Out_idx) + " <> " + (pi - Out_idx));
Out[po] -= a[pa] * Out[pi];
// System.out.println("Pour un resultat de " + Out[po]);
pa++;
pi--;
}
for (j=i+1; j < ilbc_constants.LPC_FILTERORDER+1; j++) {
// *po-=(*pa++)*(*pm--);
// System.out.println("2 Soustraction a " + Out[po] + " de " + a[pa] + " * " + mem[pm]);
Out[po] -= a[pa] * mem[pm];
// System.out.println("Pour un resultat de " + Out[po]);
pa++;
pm--;
}
po++;
}
/* Filter last part where the state is entirely in
the output vector */
for (i = ilbc_constants.LPC_FILTERORDER; i < len; i++) {
// pi=&Out[i-1];
pi = Out_idx + i - 1;
// pa=&a[1];
pa = a_idx + 1;
for (j=1; j < ilbc_constants.LPC_FILTERORDER+1; j++) {
// *po-=(*pa++)*(*pi--);
// System.out.println("3 Soustraction a " + Out[po] + " de " + a[pa] + " * " + Out[pi]);
Out[po] -= a[pa] * Out[pi];
// System.out.println("Pour un resultat de " + Out[po]);
pa++;
pi--;
}
po++;
}
/* Update state vector */
System.arraycopy(Out, Out_idx + len - ilbc_constants.LPC_FILTERORDER,
mem, 0, ilbc_constants.LPC_FILTERORDER);
// memcpy(mem, &Out[len-LPC_FILTERORDER],
// LPC_FILTERORDER*sizeof(float));
}
/*---------------------------------------------------------------*
* interpolation of lsf coefficients for the decoder
*--------------------------------------------------------------*/
public void LSFinterpolate2a_dec(
float a[], /* (o) lpc coefficients for a sub-frame */
float lsf1[], /* (i) first lsf coefficient vector */
float lsf2[], /* (i) second lsf coefficient vector */
int lsf2_idx,
float coef, /* (i) interpolation weight */
int length /* (i) length of lsf vectors */
){
float [] lsftmp = new float[ilbc_constants.LPC_FILTERORDER];
ilbc_common.interpolate(lsftmp, lsf1, lsf2, lsf2_idx, coef, length);
ilbc_common.lsf2a(a, lsftmp);
}
/*---------------------------------------------------------------*
* obtain dequantized lsf coefficients from quantization index
*--------------------------------------------------------------*/
void SimplelsfDEQ(
float lsfdeq[], /* (o) dequantized lsf coefficients */
int index[], /* (i) quantization index */
int lpc_n /* (i) number of LPCs */
){
int i, j, pos, cb_pos;
/* decode first LSF */
pos = 0;
cb_pos = 0;
for (i = 0; i < ilbc_constants.LSF_NSPLIT; i++) {
for (j = 0; j < ilbc_constants.dim_lsfCbTbl[i]; j++) {
lsfdeq[pos + j] = ilbc_constants.lsfCbTbl[cb_pos + (int)
((long)(index[i])*ilbc_constants.dim_lsfCbTbl[i] + j)];
}
pos += ilbc_constants.dim_lsfCbTbl[i];
cb_pos += ilbc_constants.size_lsfCbTbl[i]*ilbc_constants.dim_lsfCbTbl[i];
}
if (lpc_n>1) {
/* decode last LSF */
pos = 0;
cb_pos = 0;
for (i = 0; i < ilbc_constants.LSF_NSPLIT; i++) {
for (j = 0; j < ilbc_constants.dim_lsfCbTbl[i]; j++) {
lsfdeq[ilbc_constants.LPC_FILTERORDER + pos + j] =
ilbc_constants.lsfCbTbl[cb_pos + (int)
((long)(index[ilbc_constants.LSF_NSPLIT + i])*
ilbc_constants.dim_lsfCbTbl[i]) + j];
}
pos += ilbc_constants.dim_lsfCbTbl[i];
cb_pos += ilbc_constants.size_lsfCbTbl[i]*ilbc_constants.dim_lsfCbTbl[i];
}
}
}
/*----------------------------------------------------------------*
* obtain synthesis and weighting filters form lsf coefficients
*---------------------------------------------------------------*/
void DecoderInterpolateLSF(
float syntdenum[], /* (o) synthesis filter coefficients */
float weightdenum[], /* (o) weighting denumerator
coefficients */
float lsfdeq[], /* (i) dequantized lsf coefficients */
int length) /* (i) length of lsf coefficient vector */
{
int i, pos, lp_length;
float [] lp = new float[ilbc_constants.LPC_FILTERORDER + 1];
int lsfdeq2;
lsfdeq2 = length;
// lsfdeq2 = lsfdeq + length;
lp_length = length + 1;
if (this.ULP_inst.mode==30) {
/* sub-frame 1: Interpolation between old and first */
LSFinterpolate2a_dec(lp, this.lsfdeqold, lsfdeq, 0,
ilbc_constants.lsf_weightTbl_30ms[0], length);
System.arraycopy(lp, 0, syntdenum, 0, lp_length);
// memcpy(syntdenum,lp,lp_length*sizeof(float));
ilbc_common.bwexpand(weightdenum, 0, lp, ilbc_constants.LPC_CHIRP_WEIGHTDENUM, lp_length);
/* sub-frames 2 to 6: interpolation between first
and last LSF */
pos = lp_length;
for (i = 1; i < 6; i++) {
LSFinterpolate2a_dec(lp, lsfdeq, lsfdeq, lsfdeq2,
ilbc_constants.lsf_weightTbl_30ms[i], length);
System.arraycopy(lp, 0, syntdenum, pos, lp_length);
// memcpy(syntdenum + pos,lp,lp_length*sizeof(float));
ilbc_common.bwexpand(weightdenum, pos, lp,
ilbc_constants.LPC_CHIRP_WEIGHTDENUM, lp_length);
pos += lp_length;
}
}
else {
pos = 0;
for (i = 0; i < this.ULP_inst.nsub; i++) {
LSFinterpolate2a_dec(lp, this.lsfdeqold,
lsfdeq, 0, ilbc_constants.lsf_weightTbl_20ms[i], length);
System.arraycopy(lp, 0, syntdenum, pos, lp_length);
// memcpy(syntdenum+pos,lp,lp_length*sizeof(float));
ilbc_common.bwexpand(weightdenum, pos, lp, ilbc_constants.LPC_CHIRP_WEIGHTDENUM,
lp_length);
pos += lp_length;
}
}
/* update memory */
if (this.ULP_inst.mode==30) {
System.arraycopy(lsfdeq, lsfdeq2, this.lsfdeqold, 0, length);
// memcpy(iLBCdec_inst->lsfdeqold, lsfdeq2, length*sizeof(float));
} else {
System.arraycopy(lsfdeq, 0, this.lsfdeqold, 0, length);
// memcpy(iLBCdec_inst->lsfdeqold, lsfdeq, length*sizeof(float));
}
}
public void index_conv_dec(int index[]) /* (i/o) Codebook indexes */
{
int k;
for (k=1; k<ilbc_constants.CB_NSTAGES; k++) {
if ((index[k]>=44)&&(index[k]<108)) {
index[k]+=64;
} else if ((index[k]>=108)&&(index[k]<128)) {
index[k]+=128;
} else {
/* ERROR */
}
}
}
public void hpOutput(
float In[], /* (i) vector to filter */
int len,/* (i) length of vector to filter */
float Out[], /* (o) the resulting filtered vector */
float mem[]) /* (i/o) the filter state */
{
int i;
// float *pi, *po;
int pi, po;
/* all-zero section*/
// pi = &In[0];
// po = &Out[0];
pi = 0;
po = 0;
for (i=0; i<len; i++) {
Out[po] = ilbc_constants.hpo_zero_coefsTbl[0] * (In[pi]);
Out[po] += ilbc_constants.hpo_zero_coefsTbl[1] * mem[0];
Out[po] += ilbc_constants.hpo_zero_coefsTbl[2] * mem[1];
mem[1] = mem[0];
mem[0] = In[pi];
po++;
pi++;
}
/* all-pole section*/
// po = &Out[0];
po = 0;
for (i=0; i<len; i++) {
Out[po] -= ilbc_constants.hpo_pole_coefsTbl[1] * mem[2];
Out[po] -= ilbc_constants.hpo_pole_coefsTbl[2] * mem[3];
mem[3] = mem[2];
mem[2] = Out[po];
po++;
}
}
/*----------------------------------------------------------------*
* downsample (LP filter and decimation)
*---------------------------------------------------------------*/
void DownSample (
float In[], /* (i) input samples */
int in_idx,
float Coef[], /* (i) filter coefficients */
int lengthIn, /* (i) number of input samples */
float state[], /* (i) filter state */
float Out[]) /* (o) downsampled output */
{
float o;
// float *Out_ptr = Out;
int out_ptr = 0;
//float *Coef_ptr, *In_ptr;
int coef_ptr = 0;
int in_ptr = in_idx;
//float *state_ptr;
int state_ptr = 0;
int i, j, stop;
/* LP filter and decimate at the same time */
for (i = ilbc_constants.DELAY_DS; i < lengthIn; i += ilbc_constants.FACTOR_DS)
{
coef_ptr = 0;
in_ptr = in_idx + i;
state_ptr = ilbc_constants.FILTERORDER_DS - 2;
o = (float)0.0f;
// stop = (i < ilbc_constants.FILTERORDER_DS) ? i + 1 : ilbc_constants.FILTERORDER_DS;
if (i < ilbc_constants.FILTERORDER_DS) {
stop = i + 1;
}
else {
stop = ilbc_constants.FILTERORDER_DS;
}
for (j = 0; j < stop; j++)
{
o += Coef[coef_ptr] * In[in_ptr];
coef_ptr++;
in_ptr--;
}
for (j = i + 1; j < ilbc_constants.FILTERORDER_DS; j++)
{
o += Coef[coef_ptr] * state[state_ptr];
coef_ptr++;
state_ptr--;
}
Out[out_ptr] = o;
out_ptr++;
// *Out_ptr++ = o;
}
/* Get the last part (use zeros as input for the future) */
for (i=(lengthIn+ilbc_constants.FACTOR_DS); i<(lengthIn+ilbc_constants.DELAY_DS);
i+=ilbc_constants.FACTOR_DS) {
o=(float)0.0f;
if (i<lengthIn) {
coef_ptr = 0;
in_ptr = in_idx + i;
for (j=0; j<ilbc_constants.FILTERORDER_DS; j++) {
o += Coef[coef_ptr] * Out[out_ptr];
coef_ptr++;
out_ptr--;
// o += *Coef_ptr++ * (*Out_ptr--);
}
} else {
coef_ptr = i-lengthIn;
in_ptr = in_idx + lengthIn - 1;
for (j=0; j<ilbc_constants.FILTERORDER_DS-(i-lengthIn); j++) {
o += Coef[coef_ptr] * In[in_ptr];
coef_ptr++;
in_ptr--;
}
}
Out[out_ptr] = o;
out_ptr++;
}
}
/*----------------------------------------------------------------*
* Find index in array such that the array element with said
* index is the element of said array closest to "value"
* according to the squared-error criterion
*---------------------------------------------------------------*/
public int NearestNeighbor(
// int index[], /* (o) index of array element closest
// to value */
float array[], /* (i) data array */
float value,/* (i) value */
int arlength)/* (i) dimension of data array */
{
int i;
float bestcrit,crit;
int index;
crit = array[0] - value;
bestcrit = crit * crit;
index = 0;
for (i = 1; i < arlength; i++) {
crit = array[i] - value;
crit = crit * crit;
if (crit < bestcrit) {
bestcrit = crit;
index = i;
}
}
return index;
}
/*----------------------------------------------------------------*
* compute cross correlation between sequences
*---------------------------------------------------------------*/
public void mycorr1(
float corr[], /* (o) correlation of seq1 and seq2 */
int corr_idx,
float seq1[], /* (i) first sequence */
int seq1_idx,
int dim1, /* (i) dimension first seq1 */
float seq2[], /* (i) second sequence */
int seq2_idx,
int dim2) /* (i) dimension seq2 */
{
int i,j;
// System.out.println("longueur 1 : " + seq1.length);
// System.out.println("distance 1 : " + seq1_idx);
// System.out.println("longueur 2 : " + seq2.length);
// System.out.println("distance 2 : " + seq2_idx);
// System.out.println("dimensions : " + dim1 + " et " + dim2);
// BUG in ILBC ???
for (i=0; i<=dim1-dim2; i++) {
if ((corr_idx+i) < corr.length)
corr[corr_idx+i]=0.0f;
for (j=0; j<dim2; j++) {
corr[corr_idx+i] += seq1[seq1_idx+i+j] * seq2[seq2_idx+j];
}
}
}
/*----------------------------------------------------------------*
* upsample finite array assuming zeros outside bounds
*---------------------------------------------------------------*/
public void enh_upsample(
float useq1[], /* (o) upsampled output sequence */
float seq1[],/* (i) unupsampled sequence */
int dim1, /* (i) dimension seq1 */
int hfl) /* (i) polyphase filter length=2*hfl+1 */
{
// float *pu,*ps;
int pu, ps;
int i,j,k,q,filterlength,hfl2;
int [] polyp = new int[ilbc_constants.ENH_UPS0]; /* pointers to
polyphase columns */
// const float *pp;
int pp;
/* define pointers for filter */
filterlength=2*hfl+1;
if ( filterlength > dim1 ) {
hfl2=(int) (dim1/2);
for (j=0; j<ilbc_constants.ENH_UPS0; j++) {
polyp[j]=j*filterlength+hfl-hfl2;
}
hfl=hfl2;
filterlength=2*hfl+1;
}
else {
for (j=0; j<ilbc_constants.ENH_UPS0; j++) {
polyp[j]=j*filterlength;
}
}
/* filtering: filter overhangs left side of sequence */
// pu=useq1;
pu = 0;
for (i=hfl; i<filterlength; i++) {
for (j=0; j<ilbc_constants.ENH_UPS0; j++) {
// *pu=0.0f;
useq1[pu] = 0.0f;
// pp = polyp[j];
pp = polyp[j];
// ps = seq1+i;
ps = i;
for (k=0; k<=i; k++) {
useq1[pu] += seq1[ps] * ilbc_constants.polyphaserTbl[pp];
ps--;
pp++;
}
pu++;
}
}
/* filtering: simple convolution=inner products */
for (i=filterlength; i<dim1; i++) {
for (j=0;j < ilbc_constants.ENH_UPS0; j++){
// *pu=0.0f;
useq1[pu] = 0.0f;
// pp = polyp[j];
pp = polyp[j];
// ps = seq1+i;
ps = i;
for (k=0; k<filterlength; k++) {
// *pu += *ps-- * *pp++;
useq1[pu] += seq1[ps] * ilbc_constants.polyphaserTbl[pp];
ps--;
pp++;
}
pu++;
}
}
/* filtering: filter overhangs right side of sequence */
for (q=1; q<=hfl; q++) {
for (j=0; j<ilbc_constants.ENH_UPS0; j++) {
// *pu=0.0f;
useq1[pu] = 0.0f;
// pp = polyp[j]+q;
pp = polyp[j]+q;
// ps = seq1+dim1-1;
ps = dim1 - 1;
for (k=0; k<filterlength-q; k++) {
useq1[pu] += seq1[ps] * ilbc_constants.polyphaserTbl[pp];
ps--;
pp++;
// *pu += *ps-- * *pp++;
}
pu++;
}
}
}
/*----------------------------------------------------------------*
* find segment starting near idata+estSegPos that has highest
* correlation with idata+centerStartPos through
* idata+centerStartPos+ENH_BLOCKL-1 segment is found at a
* resolution of ENH_UPSO times the original of the original
* sampling rate
*---------------------------------------------------------------*/
public float refiner(
float seg[], /* (o) segment array */
int seg_idx,
float idata[], /* (i) original data buffer */
int idatal, /* (i) dimension of idata */
int centerStartPos, /* (i) beginning center segment */
float estSegPos,/* (i) estimated beginning other segment */
float period) /* (i) estimated pitch period */
{
int estSegPosRounded,searchSegStartPos,searchSegEndPos,corrdim;
int tloc,tloc2,i,st,en,fraction;
float [] vect = new float[ilbc_constants.ENH_VECTL];
float [] corrVec = new float[ilbc_constants.ENH_CORRDIM];
float maxv;
float [] corrVecUps = new float[ilbc_constants.ENH_CORRDIM*ilbc_constants.ENH_UPS0];
float updStartPos = 0.0f;
/* defining array bounds */
estSegPosRounded=(int)(estSegPos - 0.5);
searchSegStartPos=estSegPosRounded-ilbc_constants.ENH_SLOP;
if (searchSegStartPos<0) {
searchSegStartPos=0;
}
searchSegEndPos=estSegPosRounded+ilbc_constants.ENH_SLOP;
if (searchSegEndPos+ilbc_constants.ENH_BLOCKL >= idatal) {
searchSegEndPos=idatal-ilbc_constants.ENH_BLOCKL-1;
}
corrdim=searchSegEndPos-searchSegStartPos+1;
/* compute upsampled correlation (corr33) and find
location of max */
// System.out.println("appel 1");
mycorr1(corrVec, 0, idata, searchSegStartPos,
corrdim+ilbc_constants.ENH_BLOCKL-1,
idata,centerStartPos,ilbc_constants.ENH_BLOCKL);
enh_upsample(corrVecUps,corrVec,corrdim,ilbc_constants.ENH_FL0);
tloc=0; maxv=corrVecUps[0];
for (i=1; i<ilbc_constants.ENH_UPS0*corrdim; i++) {
if (corrVecUps[i]>maxv) {
tloc=i;
maxv=corrVecUps[i];
}
}
/* make vector can be upsampled without ever running outside
bounds */
updStartPos= (float)searchSegStartPos +
(float)tloc/(float)ilbc_constants.ENH_UPS0+(float)1.0f;
tloc2=(int)(tloc/ilbc_constants.ENH_UPS0);
if (tloc>tloc2*ilbc_constants.ENH_UPS0) {
tloc2++;
}
st=searchSegStartPos+tloc2-ilbc_constants.ENH_FL0;
if (st<0) {
for (int li = 0; li < -st; li++)
vect[li] = 0.0f;
// memset(vect,0,-st*sizeof(float));
System.arraycopy(idata, 0, vect, -st, (ilbc_constants.ENH_VECTL+st));
// memcpy(&vect[-st],idata, (ilbc_constants.ENH_VECTL+st)*sizeof(float));
}
else {
en=st+ilbc_constants.ENH_VECTL;
if (en>idatal) {
System.arraycopy(idata, st, vect, 0, (ilbc_constants.ENH_VECTL-(en-idatal)));
// memcpy(vect, &idata[st],
// (ilbc_constants.ENH_VECTL-(en-idatal))*sizeof(float));
for (int li = 0; li < en-idatal; li++)
vect[ilbc_constants.ENH_VECTL-(en-idatal)+li] = 0.0f;
// memset(&vect[ilbc_constants.ENH_VECTL-(en-idatal)], 0,
// (en-idatal)*sizeof(float));
}
else {
System.arraycopy(idata, st, vect, 0, ilbc_constants.ENH_VECTL);
// memcpy(vect, &idata[st], ilbc_constants.ENH_VECTL*sizeof(float));
}
}
fraction=tloc2*ilbc_constants.ENH_UPS0-tloc;
/* compute the segment (this is actually a convolution) */
// System.out.println("appel 2");
// System.out.println("longueur 1 : " + vect.length);
// System.out.println("distance 1 : " + 0);
// System.out.println("longueur 2 : " + ilbc_constants.polyphaserTbl.length);
// System.out.println("distance 2 : " + (2*ilbc_constants.ENH_FL0+1)*fraction);
// System.out.println("dimension 1 : " + ilbc_constants.ENH_VECTL);
// System.out.println("dimension 2 : " + (2 * ilbc_constants.ENH_FL0+1));
// System.out.println("correlations de dimension " + seg.length);
mycorr1(seg, seg_idx, vect, 0, ilbc_constants.ENH_VECTL,
ilbc_constants.polyphaserTbl,
(2*ilbc_constants.ENH_FL0+1)*fraction,
2*ilbc_constants.ENH_FL0+1);
return updStartPos;
}
/*----------------------------------------------------------------*
* find the smoothed output data
*---------------------------------------------------------------*/
public void smath(
float odata[], /* (o) smoothed output */
int odata_idx,
float sseq[],/* (i) said second sequence of waveforms */
int hl, /* (i) 2*hl+1 is sseq dimension */
float alpha0)/* (i) max smoothing energy fraction */
{
int i,k;
float w00,w10,w11,A,B,C,err,errs;
float [] surround = new float[ilbc_constants.BLOCKL_MAX]; /* shape contributed by other than
current */
float [] wt = new float[2*ilbc_constants.ENH_HL+1]; /* waveform weighting to get
surround shape */
float denom;
int psseq;
/* create shape of contribution from all waveforms except the
current one */
for (i=1; i<=2*hl+1; i++) {
wt[i-1] = (float)0.5*(1 - (float)(float)Math.cos(2*ilbc_constants.PI*i/(2*hl+2)));
}
wt[hl]=0.0f; /* for clarity, not used */
for (i=0; i<ilbc_constants.ENH_BLOCKL; i++) {
surround[i]=sseq[i]*wt[0];
}
for (k=1; k<hl; k++) {
psseq=k*ilbc_constants.ENH_BLOCKL;
for(i=0;i<ilbc_constants.ENH_BLOCKL; i++) {
surround[i]+=sseq[psseq+i]*wt[k];
}
}
for (k=hl+1; k<=2*hl; k++) {
psseq=k*ilbc_constants.ENH_BLOCKL;
for(i=0;i<ilbc_constants.ENH_BLOCKL; i++) {
surround[i]+=sseq[psseq+i]*wt[k];
}
}
/* compute some inner products */
w00 = w10 = w11 = 0.0f;
psseq=hl*ilbc_constants.ENH_BLOCKL; /* current block */
for (i=0; i<ilbc_constants.ENH_BLOCKL;i++) {
w00+=sseq[psseq+i]*sseq[psseq+i];
w11+=surround[i]*surround[i];
w10+=surround[i]*sseq[psseq+i];
}
if ((float)Math.abs(w11) < 1.0f) {
w11=1.0f;
}
C = (float)(float)Math.sqrt( w00/w11);
/* first try enhancement without power-constraint */
errs=0.0f;
psseq=hl*ilbc_constants.ENH_BLOCKL;
for (i=0; i<ilbc_constants.ENH_BLOCKL; i++) {
odata[odata_idx+i]=C*surround[i];
err=sseq[psseq+i]-odata[odata_idx+i];
errs+=err*err;
}
/* if constraint violated by first try, add constraint */
if (errs > alpha0 * w00) {
if ( w00 < 1) {
w00=1;
}
denom = (w11*w00-w10*w10)/(w00*w00);
if (denom > 0.0001f) { /* eliminates numerical problems
for if smooth */
A = (float)(float)Math.sqrt( (alpha0- alpha0*alpha0/4)/denom);
B = -alpha0/2 - A * w10/w00;
B = B+1;
}
else { /* essentially no difference between cycles;
smoothing not needed */
A= 0.0f;
B= 1.0f;
}
/* create smoothed sequence */
psseq=hl*ilbc_constants.ENH_BLOCKL;
for (i=0; i<ilbc_constants.ENH_BLOCKL; i++) {
odata[odata_idx + i]=A*surround[i]+B*sseq[psseq+i];
}
}
}
/*----------------------------------------------------------------*
* get the pitch-synchronous sample sequence
*---------------------------------------------------------------*/
public void getsseq(
float sseq[], /* (o) the pitch-synchronous sequence */
float idata[], /* (i) original data */
int idatal, /* (i) dimension of data */
int centerStartPos, /* (i) where current block starts */
float period[], /* (i) rough-pitch-period array */
float plocs[], /* (i) where periods of period array
are taken */
int periodl, /* (i) dimension period array */
int hl) /* (i) 2*hl+1 is the number of sequences */
{
int i,centerEndPos,q;
float [] blockStartPos = new float[2*ilbc_constants.ENH_HL+1];
int [] lagBlock = new int[2*ilbc_constants.ENH_HL+1];
float [] plocs2 = new float[ilbc_constants.ENH_PLOCSL];
// float *psseq;
int psseq;
centerEndPos=centerStartPos+ilbc_constants.ENH_BLOCKL-1;
/* present */
lagBlock[hl] = NearestNeighbor(plocs,
(float)0.5*(centerStartPos+centerEndPos),periodl);
blockStartPos[hl]=(float)centerStartPos;
psseq=ilbc_constants.ENH_BLOCKL*hl;
// psseq=sseq+ENH_BLOCKL*hl;
System.arraycopy(idata, centerStartPos, sseq, psseq, ilbc_constants.ENH_BLOCKL);
// memcpy(psseq, idata+centerStartPos, ENH_BLOCKL*sizeof(float));
/* past */
for (q=hl-1; q>=0; q--) {
blockStartPos[q]=blockStartPos[q+1]-period[lagBlock[q+1]];
lagBlock[q] = NearestNeighbor(plocs,
blockStartPos[q]+
ilbc_constants.ENH_BLOCKL_HALF-period[lagBlock[q+1]],
periodl);
if (blockStartPos[q]-ilbc_constants.ENH_OVERHANG>=0) {
blockStartPos[q] = refiner(sseq,q*ilbc_constants.ENH_BLOCKL, idata,
idatal, centerStartPos,
blockStartPos[q],
period[lagBlock[q+1]]);
} else {
psseq=q*ilbc_constants.ENH_BLOCKL;
// psseq=sseq+q*ENH_BLOCKL;
for (int li = 0; li < ilbc_constants.ENH_BLOCKL; li++)
sseq[psseq+li] = 0.0f;
// memset(psseq, 0, ENH_BLOCKL*sizeof(float));
}
}
/* future */
for (i=0; i<periodl; i++) {
plocs2[i]=plocs[i]-period[i];
}
for (q=hl+1; q<=2*hl; q++) {
lagBlock[q] = NearestNeighbor(plocs2,
blockStartPos[q-1]+ilbc_constants.ENH_BLOCKL_HALF,
periodl);
blockStartPos[q]=blockStartPos[q-1]+period[lagBlock[q]];
if (blockStartPos[q]+ilbc_constants.ENH_BLOCKL+ilbc_constants.ENH_OVERHANG<idatal) {
blockStartPos[q] = refiner(sseq,q*ilbc_constants.ENH_BLOCKL, idata,
idatal, centerStartPos,
blockStartPos[q],
period[lagBlock[q]]);
}
else {
psseq=q*ilbc_constants.ENH_BLOCKL;
// psseq=sseq+q*ENH_BLOCKL;
for (int li = 0; li < ilbc_constants.ENH_BLOCKL; li++)
sseq[psseq+li] = 0.0f;
// memset(psseq, 0, ENH_BLOCKL*sizeof(float));
}
}
}
/*----------------------------------------------------------------*
* perform enhancement on idata+centerStartPos through
* idata+centerStartPos+ENH_BLOCKL-1
*---------------------------------------------------------------*/
public void enhancer(
float odata[], /* (o) smoothed block, dimension blockl */
int odata_idx,
float idata[], /* (i) data buffer used for enhancing */
int idatal, /* (i) dimension idata */
int centerStartPos, /* (i) first sample current block
within idata */
float alpha0, /* (i) max correction-energy-fraction
(in [0,1]) */
float period[], /* (i) pitch period array */
float plocs[], /* (i) locations where period array
values valid */
int periodl /* (i) dimension of period and plocs */
){
float [] sseq = new float[(2*ilbc_constants.ENH_HL+1)*ilbc_constants.ENH_BLOCKL];
/* get said second sequence of segments */
getsseq(sseq,idata,idatal,centerStartPos,period,
plocs,periodl,ilbc_constants.ENH_HL);
/* compute the smoothed output from said second sequence */
smath(odata, odata_idx, sseq,ilbc_constants.ENH_HL,alpha0);
}
/*----------------------------------------------------------------*
* cross correlation
*---------------------------------------------------------------*/
public float xCorrCoef(
float target[], /* (i) first array */
int t_idx,
float regressor[], /* (i) second array */
int r_idx,
int subl) /* (i) dimension arrays */
{
int i;
float ftmp1, ftmp2;
ftmp1 = 0.0f;
ftmp2 = 0.0f;
for (i=0; i<subl; i++) {
ftmp1 += target[t_idx + i] * regressor[r_idx + i];
ftmp2 += regressor[r_idx + i] * regressor[r_idx + i];
}
if (ftmp1 > 0.0f) {
return (float)(ftmp1*ftmp1/ftmp2);
}
else {
return (float)0.0f;
}
}
/*----------------------------------------------------------------*
* interface for enhancer
*---------------------------------------------------------------*/
int enhancerInterface(
float out[], /* (o) enhanced signal */
float in[]) /* (i) unenhanced signal */
{
// float *enh_buf, *enh_period; (definis en global pour la classe)
int iblock, isample;
int lag=0, ilag, i, ioffset;
float cc, maxcc;
float ftmp1, ftmp2;
// float *inPtr, *enh_bufPtr1, *enh_bufPtr2;
int inPtr, enh_bufPtr1, enh_bufPtr2;
float [] plc_pred = new float[ilbc_constants.ENH_BLOCKL];
float [] lpState = new float[6];
float [] downsampled = new float[(ilbc_constants.ENH_NBLOCKS*ilbc_constants.ENH_BLOCKL+120)/2];
int inLen=ilbc_constants.ENH_NBLOCKS*ilbc_constants.ENH_BLOCKL+120;
int start, plc_blockl, inlag;
// enh_buf=iLBCdec_inst->enh_buf;
// enh_period=iLBCdec_inst->enh_period;
System.arraycopy(enh_buf, this.ULP_inst.blockl,
enh_buf, 0,
ilbc_constants.ENH_BUFL-this.ULP_inst.blockl);
// memmove(enh_buf, &enh_buf[iLBCdec_inst->blockl],
// (ENH_BUFL-iLBCdec_inst->blockl)*sizeof(float));
System.arraycopy(in, 0, enh_buf, ilbc_constants.ENH_BUFL-this.ULP_inst.blockl,
this.ULP_inst.blockl);
// memcpy(&enh_buf[ENH_BUFL-this.ULP_inst.blockl], in,
// this.ULP_inst.blockl*sizeof(float));
if (this.ULP_inst.mode==30)
plc_blockl=ilbc_constants.ENH_BLOCKL;
else
plc_blockl=40;
/* when 20 ms frame, move processing one block */
ioffset=0;
if (this.ULP_inst.mode==20) ioffset=1;
i=3-ioffset;
System.arraycopy(enh_period, i, enh_period, 0, ilbc_constants.ENH_NBLOCKS_TOT-i);
// memmove(enh_period, &enh_period[i],
// (ENH_NBLOCKS_TOT-i)*sizeof(float));
/* Set state information to the 6 samples right before
the samples to be downsampled. */
System.arraycopy(enh_buf, (ilbc_constants.ENH_NBLOCKS_EXTRA+ioffset)*ilbc_constants.ENH_BLOCKL-126,
lpState, 0, 6);
// memcpy(lpState,
// enh_buf+(ENH_NBLOCKS_EXTRA+ioffset)*ENH_BLOCKL-126,
// 6*sizeof(float));
/* Down sample a factor 2 to save computations */
DownSample(enh_buf,
(ilbc_constants.ENH_NBLOCKS_EXTRA+ioffset)*ilbc_constants.ENH_BLOCKL-120,
ilbc_constants.lpFilt_coefsTbl, inLen-ioffset*ilbc_constants.ENH_BLOCKL,
lpState, downsampled);
/* Estimate the pitch in the down sampled domain. */
for (iblock = 0; iblock<ilbc_constants.ENH_NBLOCKS-ioffset; iblock++) {
lag = 10;
maxcc = xCorrCoef(downsampled, 60+iblock * ilbc_constants.ENH_BLOCKL_HALF,
downsampled, 60+iblock * ilbc_constants.ENH_BLOCKL_HALF - lag,
ilbc_constants.ENH_BLOCKL_HALF);
for (ilag=11; ilag<60; ilag++) {
cc = xCorrCoef(downsampled, 60+iblock* ilbc_constants.ENH_BLOCKL_HALF,
downsampled, 60+iblock* ilbc_constants.ENH_BLOCKL_HALF - ilag,
ilbc_constants.ENH_BLOCKL_HALF);
if (cc > maxcc) {
maxcc = cc;
lag = ilag;
}
}
/* Store the estimated lag in the non-downsampled domain */
enh_period[iblock+ilbc_constants.ENH_NBLOCKS_EXTRA+ioffset] = (float)lag*2;
}
/* PLC was performed on the previous packet */
if (this.prev_enh_pl==1) {
inlag=(int)enh_period[ilbc_constants.ENH_NBLOCKS_EXTRA+ioffset];
lag = inlag-1;
maxcc = xCorrCoef(in, 0, in, lag, plc_blockl);
for (ilag=inlag; ilag<=inlag+1; ilag++) {
cc = xCorrCoef(in, 0, in, ilag, plc_blockl);
if (cc > maxcc) {
maxcc = cc;
lag = ilag;
}
}
enh_period[ilbc_constants.ENH_NBLOCKS_EXTRA+ioffset-1]=(float)lag;
/* compute new concealed residual for the old lookahead,
mix the forward PLC with a backward PLC from
the new frame */
// inPtr=&in[lag-1];
inPtr = lag - 1;
// enh_bufPtr1=&plc_pred[plc_blockl-1];
enh_bufPtr1 = plc_blockl - 1;
if (lag>plc_blockl) {
start=plc_blockl;
} else {
start=lag;
}
for (isample = start; isample>0; isample--) {
// *enh_bufPtr1-- = *inPtr--;
plc_pred[enh_bufPtr1] = in[inPtr];
enh_bufPtr1--;
inPtr--;
}
// enh_bufPtr2=&enh_buf[ENH_BUFL-1-this.ULP_inst.blockl];
enh_bufPtr2 = ilbc_constants.ENH_BUFL - 1 - this.ULP_inst.blockl;
for (isample = (plc_blockl-1-lag); isample>=0; isample--) {
// *enh_bufPtr1-- = *enh_bufPtr2--;
plc_pred[enh_bufPtr1] = enh_buf[enh_bufPtr2];
enh_bufPtr1--;
enh_bufPtr2--;
}
/* limit energy change */
ftmp2=0.0f;
ftmp1=0.0f;
for (i=0;i<plc_blockl;i++) {
ftmp2+=enh_buf[ilbc_constants.ENH_BUFL-1-this.ULP_inst.blockl-i]*
enh_buf[ilbc_constants.ENH_BUFL-1-this.ULP_inst.blockl-i];
ftmp1+=plc_pred[i]*plc_pred[i];
}
ftmp1=(float)(float)Math.sqrt(ftmp1/(float)plc_blockl);
ftmp2=(float)(float)Math.sqrt(ftmp2/(float)plc_blockl);
if (ftmp1>(float)2.0f*ftmp2 && ftmp1>0.0) {
for (i=0;i<plc_blockl-10;i++) {
plc_pred[i]*=(float)2.0f*ftmp2/ftmp1;
}
for (i=plc_blockl-10;i<plc_blockl;i++) {
plc_pred[i]*=(float)(i-plc_blockl+10)*
((float)1.0f-(float)2.0*ftmp2/ftmp1)/(float)(10)+
(float)2.0f*ftmp2/ftmp1;
}
}
enh_bufPtr1=ilbc_constants.ENH_BUFL-1-this.ULP_inst.blockl;
// enh_bufPtr1=&enh_buf[ilbc_constants.ENH_BUFL-1-this.ULP_inst.blockl];
for (i=0; i<plc_blockl; i++) {
ftmp1 = (float) (i+1) / (float) (plc_blockl+1);
enh_buf[enh_bufPtr1] *= ftmp1;
// *enh_bufPtr1 *= ftmp1;
enh_buf[enh_bufPtr1] += ((float)1.0f-ftmp1)*
plc_pred[plc_blockl-1-i];
// *enh_bufPtr1 += ((float)1.0f-ftmp1)*
// plc_pred[plc_blockl-1-i];
enh_bufPtr1--;
}
}
if (this.ULP_inst.mode==20) {
/* Enhancer with 40 samples delay */
for (iblock = 0; iblock<2; iblock++) {
enhancer(out, iblock*ilbc_constants.ENH_BLOCKL, enh_buf,
ilbc_constants.ENH_BUFL, (5+iblock)*ilbc_constants.ENH_BLOCKL+40,
ilbc_constants.ENH_ALPHA0, enh_period, ilbc_constants.enh_plocsTbl,
ilbc_constants.ENH_NBLOCKS_TOT);
}
} else if (this.ULP_inst.mode==30) {
/* Enhancer with 80 samples delay */
for (iblock = 0; iblock<3; iblock++) {
enhancer(out, iblock*ilbc_constants.ENH_BLOCKL, enh_buf,
ilbc_constants.ENH_BUFL, (4+iblock)*ilbc_constants.ENH_BLOCKL,
ilbc_constants.ENH_ALPHA0, enh_period, ilbc_constants.enh_plocsTbl,
ilbc_constants.ENH_NBLOCKS_TOT);
}
}
return (lag*2);
}
/*----------------------------------------------------------------*
* Packet loss concealment routine. Conceals a residual signal
* and LP parameters. If no packet loss, update state.
*---------------------------------------------------------------*/
/*----------------------------------------------------------------*
* Compute cross correlation and pitch gain for pitch prediction
* of last subframe at given lag.
*---------------------------------------------------------------*/
public 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.0f;
ftmp2 = 0.0f;
ftmp3 = 0.0f;
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.0f) {
cc[0] = ftmp1*ftmp1/ftmp2;
gc[0] = (float)(float)Math.abs(ftmp1 / ftmp2);
pm[0] = (float)(float)Math.abs(ftmp1) /
((float)(float)Math.sqrt(ftmp2)*(float)Math.sqrt(ftmp3));
}
else {
cc[0] = 0.0f;
gc[0] = 0.0f;
pm[0] = 0.0f;
}
}
public 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 lpc_idx,
int inlag) /* (i) pitch lag */
{
int lag = 20, randlag = 0;
float gain = 0.0f, maxcc = 0.0f;
float use_gain = 0.0f;
float gain_comp = 0.0f, maxcc_comp = 0.0f, per = 0.0f, max_per = 0.0f;
int i, pick, use_lag;
float ftmp, randvec[], pitchfact, energy;
float [] a_gain, a_comp, a_per;
randvec = new float [ilbc_constants.BLOCKL_MAX];
a_gain = new float[1];
a_comp = new float[1];
a_per = new float[1];
/* Packet Loss */
if (PLI == 1) {
this.consPLICount += 1;
/* if previous frame not lost,
determine pitch pred. gain */
if (this.prevPLI != 1) {
/* Search around the previous lag to find the
best pitch period */
lag=inlag-3;
a_comp[0] = maxcc;
a_gain[0] = gain;
a_per[0] = max_per;
compCorr(a_comp, a_gain, a_per,
this.prevResidual,
lag, this.ULP_inst.blockl, 60);
maxcc = a_comp[0];
gain = a_gain[0];
max_per = a_per[0];
for (i=inlag-2;i<=inlag+3;i++) {
a_comp[0] = maxcc_comp;
a_gain[0] = gain_comp;
a_per[0] = per;
compCorr(a_comp, a_gain, a_per,
this.prevResidual,
i, this.ULP_inst.blockl, 60);
maxcc_comp = a_comp[0];
gain_comp = a_gain[0];
per = a_per[0];
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=this.prevLag;
max_per=this.per;
}
/* downscaling */
use_gain=1.0f;
if (this.consPLICount*this.ULP_inst.blockl>320)
use_gain=(float)0.9;
else if (this.consPLICount*this.ULP_inst.blockl>2*320)
use_gain=(float)0.7;
else if (this.consPLICount*this.ULP_inst.blockl>3*320)
use_gain=(float)0.5;
else if (this.consPLICount*this.ULP_inst.blockl>4*320)
use_gain=(float)0.0f;
/* mix noise and pitch repeatition */
ftmp=(float)(float)Math.sqrt(max_per);
if (ftmp>(float)0.7)
pitchfact=(float)1.0f;
else if (ftmp>(float)0.4)
pitchfact=(ftmp-(float)0.4)/((float)0.7-(float)0.4);
else
pitchfact=0.0f;
/* avoid repetition of same pitch cycle */
use_lag=lag;
if (lag<80) {
use_lag=2*lag;
}
/* compute concealed residual */
energy = 0.0f;
for (i=0; i<this.ULP_inst.blockl; i++) {
/* noise component */
this.seed = (this.seed * 69069 + 1) & (0x80000000 - 1);
randlag = 50 + (int) (this.seed % 70);
pick = i - randlag;
if (pick < 0) {
randvec[i] = this.prevResidual[this.ULP_inst.blockl+pick];
} else {
randvec[i] = randvec[pick];
}
/* pitch repeatition component */
pick = i - use_lag;
if (pick < 0) {
PLCresidual[i] = this.prevResidual[this.ULP_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.0f - pitchfact) * randvec[i]);
else if (i<160)
PLCresidual[i] = (float)0.95*use_gain*(pitchfact *
PLCresidual[i] +
((float)1.0f - pitchfact) * randvec[i]);
else
PLCresidual[i] = (float)0.9*use_gain*(pitchfact *
PLCresidual[i] +
((float)1.0f - pitchfact) * randvec[i]);
energy += PLCresidual[i] * PLCresidual[i];
}
/* less than 30 dB, use only noise */
if ((float)Math.sqrt(energy/(float)this.ULP_inst.blockl) < 30.0f) {
gain=0.0f;
for (i=0; i<this.ULP_inst.blockl; i++) {
PLCresidual[i] = randvec[i];
}
}
/* use old LPC */
// memcpy(PLClpc,this.prevLpc, (LPC_FILTERORDER+1)*sizeof(float));
System.arraycopy(this.prevLpc, 0, PLClpc, 0, ilbc_constants.LPC_FILTERORDER + 1);
}
/* no packet loss, copy input */
else {
// memcpy(PLCresidual, decresidual,this.ULP_inst.blockl*sizeof(float));
System.arraycopy(decresidual, 0, PLCresidual, 0, this.ULP_inst.blockl);
// memcpy(PLClpc, lpc, (LPC_FILTERORDER+1)*sizeof(float));
System.arraycopy(lpc, lpc_idx, PLClpc, 0, ilbc_constants.LPC_FILTERORDER + 1);
this.consPLICount = 0;
}
/* update state */
if (PLI != 0) {
this.prevLag = lag;
this.per=max_per;
}
this.prevPLI = PLI;
// memcpy(this.prevLpc, PLClpc, (LPC_FILTERORDER+1)*sizeof(float));
System.arraycopy(PLClpc, 0, this.prevLpc, 0, ilbc_constants.LPC_FILTERORDER + 1);
// memcpy(this.prevResidual, PLCresidual, this.ULP_inst.blockl*sizeof(float));
System.arraycopy(PLCresidual, 0, this.prevResidual, 0, this.ULP_inst.blockl);
}
// public int decode(short decoded_data[], short encoded_data[], int mode)
// {
// return this.ULP_inst.blockl;
// }
public short decode( /* (o) Number of decoded samples */
short decoded_data[], /* (o) Decoded signal block*/
short encoded_data[], /* (i) Encoded bytes */
short mode) /* (i) 0=PL, 1=Normal */
{
int k;
float decblock [] = new float[ilbc_constants.BLOCKL_MAX];
float dtmp;
// char en_data[] = new char [this.ULP_inst.no_of_bytes];
bitstream en_data = new bitstream(this.ULP_inst.no_of_bytes);
/* check if mode is valid */
if ( (mode < 0) || (mode > 1)) {
System.out.println("\nERROR - Wrong mode - 0, 1 allowed\n");
}
/* do actual decoding of block */
for (k = 0; k < encoded_data.length; k++) {
en_data.buffer[2*k+1] = (char) (encoded_data[k] & 0xff);
en_data.buffer[2*k] = (char) ((encoded_data[k] >> 8) & 0xff);
// System.out.println("on decode " + (en_data.buffer[2*k]+0) + " et " + (en_data.buffer[2*k+1]+0));
}
iLBC_decode(decblock, en_data, mode);
/* convert to short */
for (k = 0; k < this.ULP_inst.blockl; k++) {
dtmp=decblock[k];
// System.out.println("on a eu : " + dtmp);
if (dtmp < ilbc_constants.MIN_SAMPLE)
dtmp = ilbc_constants.MIN_SAMPLE;
else if (dtmp > ilbc_constants.MAX_SAMPLE)
dtmp = ilbc_constants.MAX_SAMPLE;
decoded_data[k] = (short) dtmp;
}
return ((short) this.ULP_inst.blockl);
}
/*----------------------------------------------------------------*
* frame residual decoder function (subrutine to iLBC_decode)
*---------------------------------------------------------------*/
public void Decode(
float decresidual[], /* (o) decoded residual frame */
int start, /* (i) location of start
state */
int idxForMax, /* (i) codebook index for the
maximum value */
int idxVec[], /* (i) codebook indexes for the
samples in the start
state */
float syntdenum[], /* (i) the decoded synthesis
filter coefficients */
int cb_index[], /* (i) the indexes for the
adaptive codebook */
int gain_index[], /* (i) the indexes for the
corresponding gains */
int extra_cb_index[], /* (i) the indexes for the
adaptive codebook part
of start state */
int extra_gain_index[], /* (i) the indexes for the
corresponding gains */
int state_first) /* (i) 1 if non adaptive part
of start state comes
first 0 if that part
comes last */
{
float [] reverseDecresidual = new float[ilbc_constants.BLOCKL_MAX];
float [] mem = new float[ilbc_constants.CB_MEML];
int k, meml_gotten, Nfor, Nback, i;
int diff, start_pos;
int subcount, subframe;
diff = ilbc_constants.STATE_LEN - this.ULP_inst.state_short_len;
if (state_first == 1) {
start_pos = (start-1) * ilbc_constants.SUBL;
} else {
start_pos = (start-1) * ilbc_constants.SUBL + diff;
}
/* decode scalar part of start state */
ilbc_common.StateConstructW(idxForMax, idxVec,
syntdenum, (start-1)*(ilbc_constants.LPC_FILTERORDER+1),
decresidual, start_pos, this.ULP_inst.state_short_len);
if (state_first != 0) { /* put adaptive part in the end */
/* setup memory */
for (int li = 0; li < (ilbc_constants.CB_MEML-this.ULP_inst.state_short_len); li++)
mem[li] = 0.0f;
// memset(mem, 0,
// (CB_MEML-this.ULP_inst.state_short_len)*sizeof(float));
System.arraycopy(decresidual, start_pos,
mem, ilbc_constants.CB_MEML - this.ULP_inst.state_short_len,
this.ULP_inst.state_short_len);
// memcpy(mem+CB_MEML-this.ULP_inst.state_short_len,
// decresidual+start_pos,
// this.ULP_inst.state_short_len*sizeof(float));
/* construct decoded vector */
ilbc_common.iCBConstruct(decresidual, start_pos+this.ULP_inst.state_short_len,
extra_cb_index, 0, extra_gain_index, 0,
mem, ilbc_constants.CB_MEML - ilbc_constants.stMemLTbl,
ilbc_constants.stMemLTbl, diff, ilbc_constants.CB_NSTAGES);
}
else {/* put adaptive part in the beginning */
/* create reversed vectors for prediction */
for (k=0; k<diff; k++) {
reverseDecresidual[k] = decresidual[(start+1)*ilbc_constants.SUBL - 1 -
(k+this.ULP_inst.state_short_len)];
}
/* setup memory */
meml_gotten = this.ULP_inst.state_short_len;
for (k=0; k<meml_gotten; k++){
mem[ilbc_constants.CB_MEML-1-k] = decresidual[start_pos + k];
}
for (int li = 0; li < ilbc_constants.CB_MEML - k; li++)
mem[li] = 0.0f;
// memset(mem, 0, (CB_MEML-k)*sizeof(float));
/* construct decoded vector */
ilbc_common.iCBConstruct(reverseDecresidual, 0, extra_cb_index, 0,
extra_gain_index, 0,
mem, ilbc_constants.CB_MEML - ilbc_constants.stMemLTbl,
ilbc_constants.stMemLTbl, diff, ilbc_constants.CB_NSTAGES);
/* get decoded residual from reversed vector */
for (k=0; k<diff; k++) {
decresidual[start_pos-1-k] = reverseDecresidual[k];
}
}
/* counter for predicted sub-frames */
subcount=0;
/* forward prediction of sub-frames */
Nfor = this.ULP_inst.nsub-start-1;
if ( Nfor > 0 ){
/* setup memory */
for (int li = 0; li < ilbc_constants.CB_MEML - ilbc_constants.STATE_LEN; li++)
mem[li] = 0.0f;
// memset(mem, 0, (CB_MEML-STATE_LEN)*sizeof(float));
System.arraycopy(decresidual, (start - 1) * ilbc_constants.SUBL,
mem, ilbc_constants.CB_MEML - ilbc_constants.STATE_LEN,
ilbc_constants.STATE_LEN);
// memcpy(mem+CB_MEML-STATE_LEN, decresidual+(start-1)*SUBL,
// STATE_LEN*sizeof(float));
/* loop over sub-frames to encode */
for (subframe=0; subframe<Nfor; subframe++) {
/* construct decoded vector */
ilbc_common.iCBConstruct(decresidual, (start+1+subframe)*ilbc_constants.SUBL,
cb_index, subcount*ilbc_constants.CB_NSTAGES,
gain_index, subcount*ilbc_constants.CB_NSTAGES,
mem, ilbc_constants.CB_MEML-ilbc_constants.memLfTbl[subcount],
ilbc_constants.memLfTbl[subcount], ilbc_constants.SUBL,
ilbc_constants.CB_NSTAGES);
/* update memory */
System.arraycopy(mem, ilbc_constants.SUBL,
mem, 0,
ilbc_constants.CB_MEML - ilbc_constants.SUBL);
// memcpy(mem, mem+SUBL, (CB_MEML-SUBL)*sizeof(float));
System.arraycopy(decresidual, (start + 1 + subframe) * ilbc_constants.SUBL,
mem, ilbc_constants.CB_MEML - ilbc_constants.SUBL,
ilbc_constants.SUBL);
// memcpy(mem+CB_MEML-SUBL,
// &decresidual[(start+1+subframe)*SUBL],
// SUBL*sizeof(float));
subcount++;
}
}
/* backward prediction of sub-frames */
Nback = start-1;
if ( Nback > 0 ) {
/* setup memory */
meml_gotten = ilbc_constants.SUBL*(this.ULP_inst.nsub+1-start);
if ( meml_gotten > ilbc_constants.CB_MEML ) {
meml_gotten = ilbc_constants.CB_MEML;
}
for (k=0; k<meml_gotten; k++) {
mem[ilbc_constants.CB_MEML-1-k] = decresidual[(start-1)*ilbc_constants.SUBL + k];
}
for (int li = 0; li < (ilbc_constants.CB_MEML - k); li++)
mem[li] = 0.0f;
// memset(mem, 0, (ilbc_constants.CB_MEML-k)*sizeof(float));
/* loop over subframes to decode */
for (subframe=0; subframe<Nback; subframe++) {
/* construct decoded vector */
ilbc_common.iCBConstruct(reverseDecresidual, subframe * ilbc_constants.SUBL,
cb_index, subcount * ilbc_constants.CB_NSTAGES,
gain_index, subcount * ilbc_constants.CB_NSTAGES,
mem, ilbc_constants.CB_MEML - ilbc_constants.memLfTbl[subcount],
ilbc_constants.memLfTbl[subcount], ilbc_constants.SUBL,
ilbc_constants.CB_NSTAGES);
/* update memory */
System.arraycopy(mem, ilbc_constants.SUBL,
mem, 0,
ilbc_constants.CB_MEML - ilbc_constants.SUBL);
// memcpy(mem, mem+SUBL, (CB_MEML-SUBL)*sizeof(float));
System.arraycopy(reverseDecresidual, subframe * ilbc_constants.SUBL,
mem, ilbc_constants.CB_MEML - ilbc_constants.SUBL,
ilbc_constants.SUBL);
// memcpy(mem+CB_MEML-SUBL,
// &reverseDecresidual[subframe*SUBL],
// SUBL*sizeof(float));
subcount++;
}
/* get decoded residual from reversed vector */
for (i=0; i < ilbc_constants.SUBL*Nback; i++)
decresidual[ilbc_constants.SUBL*Nback - i - 1] =
reverseDecresidual[i];
}
}
/*----------------------------------------------------------------*
* main decoder function
*---------------------------------------------------------------*/
public void iLBC_decode(
float decblock[], /* (o) decoded signal block */
bitstream bytes, /* (i) encoded signal bits */
int mode ) /* (i) 0: bad packet, PLC,
1: normal */
{
float [] data = new float[ilbc_constants.BLOCKL_MAX];
float [] lsfdeq = new float[ilbc_constants.LPC_FILTERORDER * ilbc_constants.LPC_N_MAX];
float [] PLCresidual = new float[ilbc_constants.BLOCKL_MAX];
float [] PLClpc = new float[ilbc_constants.LPC_FILTERORDER + 1];
float [] zeros = new float[ilbc_constants.BLOCKL_MAX];
float [] one = new float[ilbc_constants.LPC_FILTERORDER + 1];
int k, i, start, idxForMax, pos, lastpart, ulp;
int lag, ilag;
float cc, maxcc;
int [] idxVec = new int[ilbc_constants.STATE_LEN];
int check;
int [] gain_index = new int[ilbc_constants.NASUB_MAX * ilbc_constants.CB_NSTAGES];
int [] extra_gain_index = new int[ilbc_constants.CB_NSTAGES];
int [] cb_index = new int[ilbc_constants.CB_NSTAGES * ilbc_constants.NASUB_MAX];
int [] extra_cb_index = new int[ilbc_constants.CB_NSTAGES];
int [] lsf_i = new int[ilbc_constants.LSF_NSPLIT * ilbc_constants.LPC_N_MAX];
int state_first;
int last_bit;
// unsigned char *pbytes;
float [] weightdenum = new float[(ilbc_constants.LPC_FILTERORDER + 1) *
ilbc_constants.NSUB_MAX];
int order_plus_one;
float [] syntdenum = new float[ilbc_constants.NSUB_MAX * (ilbc_constants.LPC_FILTERORDER + 1)];
float [] decresidual = new float[ilbc_constants.BLOCKL_MAX];
if (mode > 0) { /* the data are good */
/* decode data */
// pbytes=bytes;
pos=0;
/* Set everything to zero before decoding */
for (k=0; k<ilbc_constants.LSF_NSPLIT * ilbc_constants.LPC_N_MAX; k++) {
lsf_i[k]=0;
}
start = 0;
state_first = 0;
idxForMax = 0;
for (k = 0; k < this.ULP_inst.state_short_len; k++) {
idxVec[k]=0;
}
for (k=0; k<ilbc_constants.CB_NSTAGES; k++) {
extra_cb_index[k]=0;
}
for (k=0; k<ilbc_constants.CB_NSTAGES; k++) {
extra_gain_index[k]=0;
}
for (i=0; i<this.ULP_inst.nasub; i++) {
for (k=0; k<ilbc_constants.CB_NSTAGES; k++) {
cb_index[i*ilbc_constants.CB_NSTAGES+k]=0;
}
}
for (i=0; i<this.ULP_inst.nasub; i++) {
for (k=0; k<ilbc_constants.CB_NSTAGES; k++) {
gain_index[i*ilbc_constants.CB_NSTAGES+k]=0;
}
}
/* loop over ULP classes */
for (ulp=0; ulp<3; ulp++) {
/* LSF */
for (k=0; k<ilbc_constants.LSF_NSPLIT*this.ULP_inst.lpc_n; k++){
lastpart = bytes.unpack(this.ULP_inst.lsf_bits[k][ulp]);
// unpack( &pbytes, &lastpart,
// this.ULP_inst.lsf_bits[k][ulp], &pos);
lsf_i[k] = bytes.packcombine(lsf_i[k], lastpart,
this.ULP_inst.lsf_bits[k][ulp]);
// System.out.println("lsf_i["+k+"] = " + lsf_i[k]);
// packcombine(&lsf_i[k], lastpart,
// this.ULP_inst.lsf_bits[k][ulp]);
}
/* Start block info */
lastpart = bytes.unpack(this.ULP_inst.start_bits[ulp]);
// unpack( &pbytes, &lastpart,
// this.ULP_inst.start_bits[ulp], &pos);
start = bytes.packcombine(start, lastpart,
this.ULP_inst.start_bits[ulp]);
// System.out.println("start = " + start);
// packcombine(&start, lastpart,
// this.ULP_inst.start_bits[ulp]);
lastpart = bytes.unpack(this.ULP_inst.startfirst_bits[ulp]);
// unpack( &pbytes, &lastpart,
// this.ULP_inst.startfirst_bits[ulp], &pos);
state_first = bytes.packcombine(state_first, lastpart,
this.ULP_inst.startfirst_bits[ulp]);
// System.out.println("state_first = " + state_first);
// packcombine(&state_first, lastpart,
// this.ULP_inst.startfirst_bits[ulp]);
lastpart = bytes.unpack(this.ULP_inst.scale_bits[ulp]);
// unpack( &pbytes, &lastpart,
// this.ULP_inst.scale_bits[ulp], &pos);
idxForMax = bytes.packcombine(idxForMax, lastpart,
this.ULP_inst.scale_bits[ulp]);
// System.out.println("idxForMax = " + idxForMax);
// packcombine(&idxForMax, lastpart,
// this.ULP_inst.scale_bits[ulp]);
for (k=0; k<this.ULP_inst.state_short_len; k++) {
lastpart = bytes.unpack(this.ULP_inst.state_bits[ulp]);
// unpack( &pbytes, &lastpart,
// this.ULP_inst.state_bits[ulp], &pos);
idxVec[k] = bytes.packcombine(idxVec[k], lastpart,
this.ULP_inst.state_bits[ulp]);
// System.out.println("idxVec["+k+"] = " + idxVec[k]);
// packcombine(idxVec+k, lastpart,
// this.ULP_inst.state_bits[ulp]);
}
/* 23/22 (20ms/30ms) sample block */
for (k=0; k<ilbc_constants.CB_NSTAGES; k++) {
lastpart = bytes.unpack(this.ULP_inst.extra_cb_index[k][ulp]);
// unpack( &pbytes, &lastpart,
// this.ULP_inst.extra_cb_index[k][ulp],
// &pos);
extra_cb_index[k] = bytes.packcombine(extra_cb_index[k], lastpart,
this.ULP_inst.extra_cb_index[k][ulp]);
// System.out.println("extra_cb_index["+k+"] = " + extra_cb_index[k]);
// packcombine(extra_cb_index+k, lastpart,
// this.ULP_inst.extra_cb_index[k][ulp]);
}
for (k=0; k<ilbc_constants.CB_NSTAGES; k++) {
lastpart = bytes.unpack(this.ULP_inst.extra_cb_gain[k][ulp]);
// unpack( &pbytes, &lastpart,
// this.ULP_inst.extra_cb_gain[k][ulp],
// &pos);
extra_gain_index[k] = bytes.packcombine(extra_gain_index[k], lastpart,
this.ULP_inst.extra_cb_gain[k][ulp]);
// System.out.println("extra_gain_index["+k+"] = " + extra_gain_index[k]);
// packcombine(extra_gain_index+k, lastpart,
// this.ULP_inst.extra_cb_gain[k][ulp]);
}
/* The two/four (20ms/30ms) 40 sample sub-blocks */
for (i=0; i<this.ULP_inst.nasub; i++) {
for (k=0; k<ilbc_constants.CB_NSTAGES; k++) {
lastpart = bytes.unpack(this.ULP_inst.cb_index[i][k][ulp]);
// unpack( &pbytes, &lastpart,
// this.ULP_inst.cb_index[i][k][ulp],
// &pos);
cb_index[i * ilbc_constants.CB_NSTAGES + k] =
bytes.packcombine(cb_index[i*ilbc_constants.CB_NSTAGES+k], lastpart,
this.ULP_inst.cb_index[i][k][ulp]);
// System.out.println("cb_index["+(i*ilbc_constants.CB_NSTAGES+k)+"] = " + cb_index[(i*ilbc_constants.CB_NSTAGES+k)]);
// packcombine(cb_index+i*CB_NSTAGES+k, lastpart,
// this.ULP_inst.cb_index[i][k][ulp]);
}
}
for (i=0; i<this.ULP_inst.nasub; i++) {
for (k=0; k<ilbc_constants.CB_NSTAGES; k++) {
lastpart = bytes.unpack(this.ULP_inst.cb_gain[i][k][ulp]);
gain_index[i * ilbc_constants.CB_NSTAGES+k] =
bytes.packcombine(gain_index[i*ilbc_constants.CB_NSTAGES+k], lastpart,
this.ULP_inst.cb_gain[i][k][ulp]);
// System.out.println("gain_index["+(i*ilbc_constants.CB_NSTAGES+k)+"] = " + gain_index[(i*ilbc_constants.CB_NSTAGES+k)]);
}
}
}
/* Extract last bit. If it is 1 this indicates an
empty/lost frame */
last_bit = bytes.unpack(1);
// System.out.println("last_bit = " + last_bit);
/* Check for bit errors or empty/lost frames */
if (start < 1)
mode = 0;
if (this.ULP_inst.mode==20 && start>3)
mode = 0;
if (this.ULP_inst.mode==30 && start>5)
mode = 0;
if (last_bit==1)
mode = 0;
if (mode==1) { /* No bit errors was detected,
continue decoding */
/* adjust index */
index_conv_dec(cb_index);
// for (int li = 0; li < cb_index.length; li++)
// System.out.println("cb_index["+li+"] = " + cb_index[li]);
/* decode the lsf */
SimplelsfDEQ(lsfdeq, lsf_i, this.ULP_inst.lpc_n);
// for (int li = 0; li < lsfdeq.length; li++)
// System.out.println("lsfdeq["+li+"] = " + lsfdeq[li]);
check=ilbc_common.LSF_check(lsfdeq, ilbc_constants.LPC_FILTERORDER,
this.ULP_inst.lpc_n);
// System.out.println("check returns " + check);
DecoderInterpolateLSF(syntdenum, weightdenum,
lsfdeq, ilbc_constants.LPC_FILTERORDER);
// for (int li = 0; li < syntdenum.length; li++)
// System.out.println("syntdenum[" + li + "] = " + syntdenum[li]);
// for (int li = 0; li < weightdenum.length; li++)
// System.out.println("weightdenum[" + li + "] = " + weightdenum[li]);
Decode(decresidual, start, idxForMax,
idxVec, syntdenum, cb_index, gain_index,
extra_cb_index, extra_gain_index,
state_first);
// for (int li = 0; li < decresidual.length; li++)
// System.out.println("decresidual[" + li + "] = " + decresidual[li]);
/* preparing the plc for a future loss! */
doThePLC(PLCresidual, PLClpc, 0, decresidual,
syntdenum,
(ilbc_constants.LPC_FILTERORDER + 1)*(this.ULP_inst.nsub - 1),
last_lag);
System.arraycopy(PLCresidual, 0, decresidual, 0, this.ULP_inst.blockl);
// for (int li = 0; li < decresidual.length; li++)
// System.out.println("decresidual[" + li + "] = " + decresidual[li]);
// memcpy(decresidual, PLCresidual,
// this.ULP_inst.blockl*sizeof(float));
}
}
if (mode == 0) {
/* the data is bad (either a PLC call
* was made or a severe bit error was detected)
*/
/* packet loss conceal */
for (int li = 0; li < ilbc_constants.BLOCKL_MAX; li++)
zeros[li] = 0.0f;
// memset(zeros, 0, BLOCKL_MAX*sizeof(float));
one[0] = 1;
for (int li = 0; li < ilbc_constants.LPC_FILTERORDER; li++)
one[li+1] = 0.0f;
// memset(one+1, 0, LPC_FILTERORDER*sizeof(float));
start=0;
doThePLC(PLCresidual, PLClpc, 1, zeros, one, 0,
last_lag);
System.arraycopy(PLCresidual, 0, decresidual, 0, this.ULP_inst.blockl);
// memcpy(decresidual, PLCresidual,
// this.ULP_inst.blockl*sizeof(float));
order_plus_one = ilbc_constants.LPC_FILTERORDER + 1;
for (i = 0; i < this.ULP_inst.nsub; i++) {
System.arraycopy(PLClpc, 0, syntdenum, (i * order_plus_one), order_plus_one);
// memcpy(syntdenum+(i*order_plus_one), PLClpc,
// order_plus_one*sizeof(float));
}
}
if (this.use_enhancer == 1) {
/* post filtering */
this.last_lag = enhancerInterface(data, decresidual);
// System.out.println("last_lag : " + this.last_lag);
// for (int li = 0; li < data.length; li++)
// System.out.println("data["+li+"] = " + data[li]);
// for (li = 0; li <
/* synthesis filtering */
if (this.ULP_inst.mode == 20) {
/* Enhancer has 40 samples delay */
i = 0;
// System.out.println("run 1");
syntFilter(data,i * ilbc_constants.SUBL,
this.old_syntdenum,
(i+this.ULP_inst.nsub-1)*(ilbc_constants.LPC_FILTERORDER+1),
ilbc_constants.SUBL, this.syntMem);
// System.out.println("runs 2");
for (i=1; i < this.ULP_inst.nsub; i++) {
// System.out.println("pass " + i);
syntFilter(data, i * ilbc_constants.SUBL,
syntdenum, (i-1)*(ilbc_constants.LPC_FILTERORDER+1),
ilbc_constants.SUBL, this.syntMem);
// System.out.println("pass " + i + " ends");
}
// for (int li = 0; li < data.length; li++)
// System.out.println("psdata["+li+"] = " + data[li]);
} else if (this.ULP_inst.mode == 30) {
/* Enhancer has 80 samples delay */
// System.out.println("runs 3");
for (i = 0; i < 2; i++) {
syntFilter(data, i * ilbc_constants.SUBL,
this.old_syntdenum,
(i+this.ULP_inst.nsub-2)*(ilbc_constants.LPC_FILTERORDER+1),
ilbc_constants.SUBL, this.syntMem);
}
for (i=2; i < this.ULP_inst.nsub; i++) {
// System.out.println("runs 4");
syntFilter(data, i * ilbc_constants.SUBL,
syntdenum, (i-2)*(ilbc_constants.LPC_FILTERORDER+1),
ilbc_constants.SUBL, this.syntMem);
}
}
} else {
/* Find last lag */
lag = 20;
maxcc = xCorrCoef(decresidual,
ilbc_constants.BLOCKL_MAX - ilbc_constants.ENH_BLOCKL,
decresidual,
ilbc_constants.BLOCKL_MAX - ilbc_constants.ENH_BLOCKL-lag,
ilbc_constants.ENH_BLOCKL);
for (ilag = 21; ilag < 120; ilag++) {
cc = xCorrCoef(decresidual,
ilbc_constants.BLOCKL_MAX - ilbc_constants.ENH_BLOCKL,
decresidual,
ilbc_constants.BLOCKL_MAX - ilbc_constants.ENH_BLOCKL - ilag,
ilbc_constants.ENH_BLOCKL);
if (cc > maxcc) {
maxcc = cc;
lag = ilag;
}
}
this.last_lag = lag;
/* copy data and run synthesis filter */
System.arraycopy(decresidual, 0, data, 0, this.ULP_inst.blockl);
// memcpy(data, decresidual,
// this.ULP_inst.blockl*sizeof(float));
// System.out.println("runs 5");
for (i=0; i < this.ULP_inst.nsub; i++) {
syntFilter(data, i * ilbc_constants.SUBL,
syntdenum, i * (ilbc_constants.LPC_FILTERORDER + 1),
ilbc_constants.SUBL, this.syntMem);
}
}
/* high pass filtering on output if desired, otherwise
copy to out */
hpOutput(data, this.ULP_inst.blockl, decblock, this.hpomem);
/* memcpy(decblock,data,iLBCdec_inst->blockl*sizeof(float));*/
System.arraycopy(syntdenum, 0, this.old_syntdenum, 0,
this.ULP_inst.nsub * (ilbc_constants.LPC_FILTERORDER+1));
// memcpy(this.old_syntdenum, syntdenum,
// this.ULP_inst.nsub*(LPC_FILTERORDER+1)*sizeof(float));
this.prev_enh_pl=0;
if (mode==0) { /* PLC was used */
this.prev_enh_pl=1;
}
}
public ilbc_decoder(int init_mode, int init_enhancer)
{
ULP_inst = new ilbc_ulp(init_mode);
/* properties to initialize : */
syntMem = new float[ilbc_constants.LPC_FILTERORDER];
prevLpc = new float[ilbc_constants.LPC_FILTERORDER+1];
prevResidual = new float[ilbc_constants.NSUB_MAX*ilbc_constants.SUBL];
old_syntdenum = new float[(ilbc_constants.LPC_FILTERORDER + 1) * ilbc_constants.NSUB_MAX];
hpomem = new float[4];
enh_buf = new float[ilbc_constants.ENH_BUFL];
enh_period = new float[ilbc_constants.ENH_NBLOCKS_TOT];
lsfdeqold = new float[ilbc_constants.LPC_FILTERORDER];
for (int li = 0; li < syntMem.length; li++)
syntMem[li] = 0.0f;
System.arraycopy(ilbc_constants.lsfmeanTbl, 0, lsfdeqold, 0,
ilbc_constants.LPC_FILTERORDER);
// for (int li = 0; li < lsfdeqold.length; li++)
// lsfdeqold[li] = 0.0f;
for (int li = 0; li < old_syntdenum.length; li++)
old_syntdenum[li] = 0.0f;
for (int li = 0; li < ilbc_constants.NSUB_MAX; li++)
old_syntdenum[li * (ilbc_constants.LPC_FILTERORDER + 1)] = 1.0f;
last_lag = 20;
prevLag = 120;
per = 0.0f;
consPLICount = 0;
prevPLI = 0;
prevLpc[0] = 1.0f;
for (int li = 1; li < prevLpc.length; li++)
prevLpc[li] = 0.0f;
for (int li = 0; li < prevResidual.length; li++)
prevResidual[li] = 0.0f;
seed = 777;
for (int li = 0; li < hpomem.length; li++)
hpomem[li] = 0.0f;
use_enhancer = init_enhancer;
for (int li = 0; li < enh_buf.length; li++)
enh_buf[li] = 0.0f;
for (int li = 0; li < ilbc_constants.ENH_NBLOCKS_TOT; li++)
enh_period[li] = 40.0f;
prev_enh_pl = 0;
}
}