www.pudn.com > p_voice.rar > EXC2.C


/* 
** 
** File:    exc2.c 
** 
** Description: Functions that implement adaptive and fixed codebook 
**       operations. 
** 
** Functions: 
** 
**  Computing Open loop Pitch lag: 
** 
**      Estim_Pitch() 
** 
**  Harmonic noise weighting: 
** 
**      Comp_Pw() 
**      Filt_Pw() 
** 
**  Fixed Cobebook computation: 
** 
**      Find_Fcbk() 
**      Gen_Trn() 
**      Find_Best() 
**      Fcbk_Pack() 
**      Fcbk_Unpk() 
**      ACELP_LBC_code() 
**      Cor_h() 
**      Cor_h_X() 
**      reset_max_time() 
**      D4i64_LBC() 
**      G_code() 
**      search_T0() 
** 
**  Adaptive Cobebook computation: 
** 
**      Find_Acbk() 
**      Get_Rez() 
**      Decod_Acbk() 
** 
**  Pitch postfilter: 
**      Comp_Lpf() 
**      Find_B() 
**      Find_F() 
**      Filt_Lpf() 
** 
**  Residual interpolation: 
** 
**      Comp_Info() 
**      Regen() 
** 
** Functions used to avoid possible explosion of the decoder 
** excitation in case of series of long term unstable filters 
** and when the encoder and the decoder are de-synchronized 
** 
**      Update_Err() 
**      Test_Err() 
*/ 
 
/* 
    ITU-T G.723.1 Floating Point Speech Coder ANSI C Source Code.  Version 5.1F 
 
    Original fixed-point code copyright (c) 1995, 
    AudioCodes, DSP Group, France Telecom, Universite de Sherbrooke. 
    All rights reserved. 
 
    Floating-point code copyright (c) 1995, 
    Intel Corporation and France Telecom (CNET). 
    All rights reserved. 
*/ 
 
#include  
#include  
#include  
#include  
 
#include "typedef2.h" 
#include "cst2.h" 
#include "tab2.h" 
#include "lbccode2.h" 
#include "coder2.h" 
#include "util2.h" 
#include "exc2.h" 
#include "utilcng2.h" 
 
/* 
** 
** Function:        Estim_Pitch() 
** 
** Description: Open loop pitch estimation made twice per frame (one for 
**              the first two subframes and one for the last two). 
**              The method is based on the maximization of the 
**              crosscorrelation of the speech. 
** 
** Links to text:   Section 2.9 
** 
** Arguments: 
** 
**  FLOAT *Dpnt    Perceptually weighted speech 
**  int   Start    Starting index defining the subframes under study 
** 
** Outputs: 
** 
** Return value: 
** 
**  int      Open loop pitch period 
** 
*/ 
int Estim_Pitch(FLOAT *Dpnt, int Start) 
{ 
    int     i; 
 
    int     Pr,Indx = PitchMin; 
    FLOAT   MaxE = (FLOAT)1.0; 
    FLOAT   MaxC = (FLOAT)0.0; 
    FLOAT   E,C,C2,Diff; 
 
    Pr = Start - PitchMin + 1; 
 
    /* Init the energy estimate */ 
 
    E = DotProd(&Dpnt[Pr],&Dpnt[Pr],2*SubFrLen); 
 
    /* Main Open loop pitch search loop */ 
 
    for (i=PitchMin; i <= PitchMax-3; i++) 
    { 
        Pr--; 
 
        /* Update energy, compute cross */ 
 
        E = E - Dpnt[Pr+2*SubFrLen]*Dpnt[Pr+2*SubFrLen] + Dpnt[Pr]*Dpnt[Pr]; 
        C = DotProd(&Dpnt[Start],&Dpnt[Pr],2*SubFrLen); 
        C2 = C*C; 
 
        /* Check for new maximum */ 
 
        Diff = C2*MaxE - E*MaxC; 
        if (E > (FLOAT)0.0 && C > (FLOAT)0.0) 
        { 
            if ((Diff > (FLOAT)0.0 && ((i - Indx) < PitchMin)) 
                 || (Diff > (FLOAT)0.25*C2*MaxE)) 
            { 
                Indx = i; 
                MaxE = E; 
                MaxC = C2; 
            } 
        } 
    } 
    return Indx; 
} 
 
/* 
** 
** Function:        Comp_Pw() 
** 
** Description:     Computes harmonic noise filter coefficients. 
**                  For each subframe, the optimal lag is searched around the 
**                  open loop pitch lag based on only positive correlation 
**                  maximization. 
** 
** Links to text:   Section 2.11 
** 
** Arguments: 
** 
**  FLOAT *Dpnt    Formant perceptually weighted speech 
**  int   Start 
**  int   Olp      Open loop pitch lag 
** 
** Outputs:         None 
** 
** Return value: 
** 
**  PWDEF   Word16  Indx  lag of the harmonic noise shaping filter 
**          FLOAT   Gain  gain of the harmonic noise shaping filter 
** 
*/ 
PWDEF Comp_Pw(FLOAT *Dpnt, int Start, int Olp) 
{ 
 
    int     i, k; 
    FLOAT   Energy,C,E,C2,MaxE,MaxC2,MaxC,Gopt; 
    PWDEF   Pw; 
 
    /* Compute target energy */ 
 
    Energy = DotProd(&Dpnt[Start],&Dpnt[Start],SubFrLen); 
 
    /* Find position with maximum C2/E value */ 
 
    MaxE = (FLOAT)1.0; 
    MaxC = (FLOAT)0.0; 
    MaxC2 = (FLOAT)0.0; 
    Pw.Indx = -1; 
    Pw.Gain = (FLOAT)0.0; 
    k = Start - (Olp-PwRange); 
 
    for (i=0; i <= 2*PwRange; i++) 
    { 
        C = DotProd(&Dpnt[Start],&Dpnt[k],SubFrLen); 
        E = DotProd(&Dpnt[k],&Dpnt[k],SubFrLen); 
        k--; 
 
        if (E > (FLOAT)0.0 && C > (FLOAT)0.0) 
        { 
            C2 = C*C; 
            if (C2*MaxE > E*MaxC2) 
            { 
                Pw.Indx = i; 
                MaxE = E; 
                MaxC = C; 
                MaxC2 = C2; 
            } 
        } 
    } 
 
    if ( Pw.Indx == -1 ) 
    { 
        Pw.Indx = Olp ; 
        return Pw ; 
    } 
 
    Pw.Gain = (FLOAT)0.0; 
    if (MaxC2 > MaxE*Energy*(FLOAT)0.375) 
    { 
        if (MaxC > MaxE || MaxE == (FLOAT)0.0) 
            Gopt = (FLOAT)1.0; 
        else 
            Gopt = MaxC/MaxE; 
 
        Pw.Gain = (FLOAT)0.3125*Gopt; 
    } 
    Pw.Indx = Olp - PwRange + Pw.Indx; 
    return Pw; 
} 
 
/* 
** 
** Function:        Filt_Pw() 
** 
** Description:     Applies harmonic noise shaping filter. 
**                  Lth order FIR filter on each subframe (L: filter lag). 
** 
** Links to text:   Section 2.11 
** 
** Arguments: 
** 
**  FLOAT *DataBuff     Target vector 
**  FLOAT *Dpnt         Formant perceptually weighted speech 
**  int   Start 
**  PWDEF Pw            Parameters of the harmonic noise shaping filter 
** 
** Outputs: 
** 
**  FLOAT *DataBuff     Target vector 
** 
** Return value:        None 
** 
*/ 
void  Filt_Pw(FLOAT *DataBuff, FLOAT *Dpnt, int Start, PWDEF Pw) 
{ 
    int i; 
 
    /* Perform the harmonic weighting */ 
 
    for (i=0; i < SubFrLen; i++) 
        DataBuff[Start+i] = Dpnt[PitchMax+Start+i] - 
                            Pw.Gain*Dpnt[PitchMax+Start-Pw.Indx+i]; 
    return; 
} 
 
/* 
** 
** Function:        Find_Fcbk() 
** 
** Description:     Fixed codebook excitation computation. 
** 
** 
** Links to text:   Sections 2.15 & 2.16 
** 
** Arguments: 
** 
**  FLOAT  *Dpnt    Target vector 
**  FLOAT  *ImpResp Impulse response of the synthesis filter 
**  LineDef *Line   Excitation parameters for one subframe 
**  int    Sfc      Subframe index 
** 
** Outputs: 
** 
**  FLOAT  *Dpnt    Excitation vector 
**  LINEDEF *Line   Fixed codebook parameters for one subframe 
** 
** Return value:        None 
** 
*/ 
void  Find_Fcbk(FLOAT *Dpnt, FLOAT *ImpResp, LINEDEF *Line, int Sfc) 
{ 
    int      i; 
    int      Srate, T0_acelp; 
    FLOAT    gain_T0; 
 
    BESTDEF  Best; 
 
    switch(WrkRate) 
    { 
    case Rate63: 
        Srate = Nb_puls[Sfc]; 
        Best.MaxErr = (FLOAT)(-99999999.9); 
 
        Find_Best(&Best, Dpnt, ImpResp, Srate, SubFrLen); 
 
        if ((*Line).Olp[Sfc>>1] < SubFrLen-2) 
            Find_Best(&Best, Dpnt, ImpResp, Srate, (*Line).Olp[Sfc>>1]); 
 
        /* Reconstruct the excitation */ 
 
        for (i=0; i <  SubFrLen; i++) 
            Dpnt[i] = (FLOAT)0.0; 
 
        for (i=0; i < Srate; i++) 
            Dpnt[Best.Ploc[i]] = Best.Pamp[i]; 
 
        /* Code the excitation */ 
 
        Fcbk_Pack(Dpnt, &((*Line).Sfs[Sfc]), &Best, Srate); 
 
        if (Best.UseTrn == 1) 
            Gen_Trn(Dpnt, Dpnt, (*Line).Olp[Sfc>>1]); 
        break; 
 
    case Rate53: 
        T0_acelp = search_T0 ( (Word16) ((*Line).Olp[Sfc>>1]-1+(*Line).Sfs[Sfc].AcLg), 
                            (*Line).Sfs[Sfc].AcGn, &gain_T0); 
 
        (*Line).Sfs[Sfc].Ppos = ACELP_LBC_code(Dpnt, ImpResp, T0_acelp, Dpnt, 
                                   &(*Line).Sfs[Sfc].Mamp, 
                                   &(*Line).Sfs[Sfc].Grid, 
                                   &(*Line).Sfs[Sfc].Pamp, gain_T0); 
 
        (*Line).Sfs[Sfc].Tran = 0; 
        break; 
    } 
 
    return; 
} 
 
/* 
** 
** Function:        Gen_Trn() 
** 
** Description:     Generation of a train of Dirac functions with the period 
**                  Olp. 
** 
** Links to text:   Section 2.15 
** 
** Arguments: 
** 
**  FLOAT  *Dst     Fixed codebook excitation vector with  train of Dirac 
**  FLOAT  *Src     Fixed codebook excitation vector without train of Dirac 
**  int    Olp      Closed-loop pitch lag of subframe 0 (for subframes 0 & 1) 
**                  Closed-loop pitch lag of subframe 2 (for subframes 2 & 3) 
** 
** Outputs: 
** 
**  FLOAT  *Dst     excitation vector 
** 
** Return value:    None 
** 
*/ 
void  Gen_Trn(FLOAT *Dst, FLOAT *Src, int Olp) 
{ 
    int    i; 
    int    Tmp0; 
    FLOAT  Tmp[SubFrLen]; 
 
    Tmp0 = Olp; 
 
    for (i=0; i < SubFrLen; i++) { 
        Tmp[i] = Src[i]; 
        Dst[i] = Src[i]; 
    } 
 
    while (Tmp0 < SubFrLen) { 
        for (i=Tmp0; i < SubFrLen; i++) 
            Dst[i] += Tmp[i-Tmp0]; 
 
        Tmp0 += Olp; 
    } 
    return; 
} 
 
 
/* 
** 
** Function:        Find_Best() 
** 
** Description:     Fixed codebook search for the high rate encoder. 
**                  It performs the quantization of the residual signal. 
**                  The excitation made of Np positive or negative pulses 
**                  multiplied by a gain and whose positions on the grid are 
**                  either all odd or all even, should approximate as best as 
**                  possible the residual signal (perceptual criterion). 
** 
** Links to text:   Section 2.15 
** 
** Arguments: 
** 
**  BESTDEF *Best   Parameters of the best excitation model 
**  FLOAT  *Tv      Target vector 
**  FLOAT  *ImpResp Impulse response of the combined filter 
**  int    Np       Number of pulses (6 for even subframes, 5 for odd) 
**  int    Olp      Closed-loop pitch lag of subframe 0 (for subframes 0 & 1) 
**                  Closed-loop pitch lag of subframe 2 (for subframes 2 & 3) 
** 
** Outputs: 
** 
**  BESTDEF *Best 
** 
** Return value:    None 
** 
*/ 
void  Find_Best(BESTDEF *Best, FLOAT *Tv, FLOAT *ImpResp,int Np,int Olp) 
{ 
 
    int     i,j,k,l; 
    BESTDEF  Temp; 
 
    int     MaxAmpId; 
    FLOAT   MaxAmp; 
    FLOAT   Acc0,Acc1,Acc2; 
 
    FLOAT   Imr[SubFrLen]; 
    FLOAT   OccPos[SubFrLen]; 
    FLOAT   ImrCorr[SubFrLen]; 
    FLOAT   ErrBlk[SubFrLen]; 
    FLOAT   WrkBlk[SubFrLen]; 
 
 
    /* Update Impulse responce */ 
 
    if (Olp < (SubFrLen-2)) { 
        Temp.UseTrn = 1; 
        Gen_Trn(Imr, ImpResp, Olp); 
    } 
    else { 
        Temp.UseTrn = 0; 
        for (i = 0; i < SubFrLen; i++) 
            Imr[i] = ImpResp[i]; 
    } 
 
    /* Copy Imr */ 
 
    for (i=0; i < SubFrLen; i++) 
        OccPos[i] = Imr[i]; 
 
    /* Compute Imr AutoCorr function */ 
 
    for (i=0;i= Acc1) 
            { 
                Acc1 = Acc0; 
                Temp.Ploc[0] = i; 
            } 
        } 
 
        /* Quantize the maximum amplitude */ 
        Acc2 = Acc1; 
        Acc1 = (FLOAT)32767.0; 
        MaxAmpId = (NumOfGainLev - MlqSteps); 
 
        for (i=MaxAmpId; i >= MlqSteps; i--) 
        { 
            Acc0 = (FLOAT) fabs(FcbkGainTable[i]*ImrCorr[0] - Acc2); 
            if (Acc0 < Acc1) 
            { 
                Acc1 = Acc0; 
                MaxAmpId = i; 
            } 
        } 
        MaxAmpId --; 
 
        for (i=1; i <=2*MlqSteps; i++) 
        { 
            for (j=k; j < SubFrLen; j +=Sgrid) 
            { 
                WrkBlk[j] = ErrBlk[j]; 
                OccPos[j] = (FLOAT)0.0; 
            } 
            Temp.MampId = MaxAmpId - MlqSteps + i; 
 
            MaxAmp = FcbkGainTable[Temp.MampId]; 
 
            if (WrkBlk[Temp.Ploc[0]] >= (FLOAT)0.0) 
                Temp.Pamp[0] = MaxAmp; 
            else 
                Temp.Pamp[0] = -MaxAmp; 
 
            OccPos[Temp.Ploc[0]] = (FLOAT)1.0; 
 
            for (j=1; j < Np; j++) 
            { 
                Acc1 = (FLOAT)-32768.0; 
 
                for (l=k; l < SubFrLen; l +=Sgrid) 
                { 
                    if (OccPos[l] != (FLOAT)0.0) 
                        continue; 
 
                    Acc0 = WrkBlk[l] - Temp.Pamp[j-1]* 
                                        ImrCorr[abs(l-Temp.Ploc[j-1])]; 
                    WrkBlk[l] = Acc0; 
 
                    Acc0 = (FLOAT) fabs(Acc0); 
                    if (Acc0 > Acc1) 
                    { 
                        Acc1 = Acc0; 
                        Temp.Ploc[j] = l; 
                    } 
                } 
 
                if (WrkBlk[Temp.Ploc[j]] >= (FLOAT)0.0) 
                    Temp.Pamp[j] = MaxAmp; 
                else 
                    Temp.Pamp[j] = -MaxAmp; 
 
                OccPos[Temp.Ploc[j]] = (FLOAT)1.0; 
            } 
 
            /* Compute error vector */ 
 
            for (j=0; j < SubFrLen; j++) 
                OccPos[j] = (FLOAT)0.0; 
 
            for (j=0; j < Np; j++) 
                OccPos[Temp.Ploc[j]] = Temp.Pamp[j]; 
 
            for (l=SubFrLen-1; l >= 0; l--) 
            { 
                Acc0 = (FLOAT)0.0; 
                for (j=0; j <= l; j++) 
                    Acc0 += OccPos[j]*Imr[l-j]; 
                OccPos[l] = Acc0; 
            } 
 
            /* Evaluate error */ 
 
            Acc2 = ((FLOAT)2.0)*DotProd(Tv,OccPos,SubFrLen) 
                   - DotProd(OccPos,OccPos,SubFrLen); 
 
            if (Acc2 > (*Best).MaxErr) 
            { 
                (*Best).MaxErr = Acc2; 
                (*Best).GridId = Temp.GridId; 
                (*Best).MampId = Temp.MampId; 
                (*Best).UseTrn = Temp.UseTrn; 
                for (j = 0; j < Np; j++) 
                { 
                    (*Best).Pamp[j] = Temp.Pamp[j]; 
                    (*Best).Ploc[j] = Temp.Ploc[j]; 
                } 
            } 
        } 
    } 
    return; 
} 
 
/* 
** 
** Function:        Fcbk_Pack() 
** 
** Description:     Encoding of the pulse positions and gains for the high 
**                  rate case. 
**                  Combinatorial encoding is used to transmit the optimal 
**                  combination of pulse locations. 
** 
** Links to text:   Section 2.15 
** 
** Arguments: 
** 
**  FLOAT  *Dpnt    Excitation vector 
**  SFSDEF *Sfs     Encoded parameters of the excitation model 
**  BESTDEF *Best   Parameters of the best excitation model 
**  int    Np       Number of pulses (6 for even subframes; 5 for odd subframes) 
** 
** Outputs: 
** 
**  SFSDEF *Sfs     Encoded parameters of the excitation model 
** 
** Return value:    None 
** 
*/ 
void  Fcbk_Pack(FLOAT *Dpnt, SFSDEF *Sfs, BESTDEF *Best, int Np) 
{ 
    int i,j; 
 
    /* Code the amplitudes and positions */ 
 
    j = MaxPulseNum - Np; 
 
    (*Sfs).Pamp = 0; 
    (*Sfs).Ppos = 0; 
 
    for (i=0; i < SubFrLen/Sgrid; i++) 
    { 
        if (Dpnt[(*Best).GridId + Sgrid*i] == 0) 
            (*Sfs).Ppos = (*Sfs).Ppos + CombinatorialTable[j][i]; 
        else 
        { 
            (*Sfs).Pamp = (*Sfs).Pamp << 1; 
            if (Dpnt[(*Best).GridId + Sgrid*i] < 0) 
                (*Sfs).Pamp++; 
            j++; 
 
            /* Check for end  */ 
 
            if (j == MaxPulseNum) 
                break; 
        } 
    } 
 
    (*Sfs).Mamp = (*Best).MampId; 
    (*Sfs).Grid = (*Best).GridId; 
    (*Sfs).Tran = (*Best).UseTrn; 
    return; 
} 
 
 
/* 
** 
** Function:        Fcbk_Unpk() 
** 
** Description:     Decoding of the fixed codebook excitation for both rates. 
**                  Gains, pulse positions, grid position (odd or even), signs 
**                  are decoded and used to reconstruct the excitation. 
** 
** Links to text:   Section 2.17 & 3.5 
** 
** Arguments: 
** 
**  FLOAT  *Tv      Decoded excitation vector 
**  SFSDEF Sfs      Encoded parameters of the excitation (for one subframe) 
**  int    Olp      Closed loop adaptive pitch lag 
**  int    Sfc      Subframe index 
** 
** Outputs: 
** 
**  FLOAT  *Tv      Decoded excitation vector 
** 
** Return value:    None 
** 
*/ 
void  Fcbk_Unpk(FLOAT *Tv, SFSDEF Sfs, int Olp, int Sfc) 
{ 
    int    i,j,Np; 
    FLOAT  Tv_tmp[SubFrLen+4]; 
    FLOAT  acelp_gain,gain_T0; 
    int    acelp_sign, acelp_shift, acelp_pos; 
    int    offset, ipos, T0_acelp; 
    Word32 Acc0; 
 
    switch(WrkRate) 
    { 
        case Rate63: 
        { 
            Np = Nb_puls[Sfc]; 
 
            for (i=0; i < SubFrLen; i++) 
                Tv[i] = (FLOAT)0.0; 
 
            if (Sfs.Ppos >= MaxPosTable[Sfc]) 
                return; 
 
            /*  Decode the amplitudes and positions */ 
 
            j = MaxPulseNum - Np; 
            Acc0 = Sfs.Ppos; 
 
            for (i = 0; i < SubFrLen/Sgrid; i++) 
            { 
                Acc0 -= CombinatorialTable[j][i]; 
 
                if (Acc0 < (Word32) 0) 
                { 
                    Acc0 += CombinatorialTable[j][i]; 
                    j++; 
 
                    if ((Sfs.Pamp & (1 << (MaxPulseNum-j))) != 0) 
                        Tv[Sfs.Grid + Sgrid*i] = -FcbkGainTable[Sfs.Mamp]; 
                    else 
                        Tv[Sfs.Grid + Sgrid*i] =  FcbkGainTable[Sfs.Mamp]; 
 
                    if (j == MaxPulseNum) 
                        break; 
                } 
            } 
 
            if (Sfs.Tran == 1) 
                Gen_Trn(Tv, Tv, Olp); 
            break; 
        } 
 
        case Rate53: 
        { 
            for (i = 0; i < SubFrLen+4; i++) 
                Tv_tmp[i] = (FLOAT)0.0; 
 
            acelp_gain = FcbkGainTable[Sfs.Mamp]; 
            acelp_shift = Sfs.Grid; 
            acelp_sign = Sfs.Pamp; 
            acelp_pos = (int)Sfs.Ppos; 
 
            offset  = 0; 
            for (i=0; i<4; i++) 
            { 
                ipos = (acelp_pos & 7); 
                ipos = (ipos << 3) + acelp_shift + offset; 
 
                if ((acelp_sign & 1)== 1) 
                    Tv_tmp[ipos] = acelp_gain; 
                else 
                    Tv_tmp[ipos] = -acelp_gain; 
 
                offset += 2; 
                acelp_pos = acelp_pos >> 3; 
                acelp_sign = acelp_sign >> 1; 
            } 
            for (i = 0; i < SubFrLen; i++) 
                Tv[i] = Tv_tmp[i]; 
 
            T0_acelp = search_T0( (Olp-1+Sfs.AcLg), Sfs.AcGn, &gain_T0); 
            if (T0_acelp < SubFrLen-2) 
            { 
                for (i = T0_acelp; i < SubFrLen; i++) 
                    Tv[i] += Tv[i-T0_acelp]*gain_T0; 
            } 
            break; 
        } 
    } 
    return; 
} 
 
/* 
** 
** Function:        ACELP_LBC_code() 
** 
** Description:     Find Algebraic codebook for low bit rate LBC encoder 
** 
** Links to text:   Section 2.16 
** 
** Arguments: 
** 
**   FLOAT  X[]              Target vector.     (in Q0) 
**   FLOAT  h[]              Impulse response.  (in Q12) 
**   int    T0               Pitch period. 
**   FLOAT  code[]           Innovative vector.        (in Q12) 
**   int    gain             Innovative vector gain.   (in Q0) 
**   int    sign             Signs of the 4 pulses. 
**   int    shift            Shift of the innovative vector 
**   FLOAT  gain_T0          Gain for pitch synchronous fiter 
** 
** Inputs : 
** 
**   FLOAT  X[]              Target vector.     (in Q0) 
**   FLOAT  h[]              Impulse response.  (in Q12) 
**   int    T0               Pitch period. 
**   FLOAT  gain_T0          Gain for pitch synchronous fiter 
** 
** Outputs: 
** 
**   FLOAT  code[]           Innovative vector.        (in Q12) 
**   int    gain             Innovative vector gain.   (in Q0) 
**   int    sign             Signs of the 4 pulses. 
**   int    shift            Shift of the innovative vector. 
** 
** Return value: 
** 
**   int    index            Innovative codebook index 
** 
*/ 
int ACELP_LBC_code(FLOAT X[], FLOAT h[], int T0, FLOAT code[], 
    int *ind_gain, int *shift, int *sign, FLOAT gain_T0) 
{ 
    int i, index; 
    FLOAT gain_q; 
    FLOAT Dn[SubFrLen2], tmp_code[SubFrLen2]; 
    FLOAT rr[DIM_RR]; 
 
    /*  Include fixed-gain pitch contribution into impulse resp. h[] */ 
 
    if (T0 < SubFrLen-2) 
        for (i = T0; i < SubFrLen; i++) 
            h[i] += gain_T0*h[i-T0]; 
 
    /*  Compute correlations of h[] needed for the codebook search */ 
 
    Cor_h(h, rr); 
 
    /*  Compute correlation of target vector with impulse response. */ 
 
    Cor_h_X(h, X, Dn); 
 
    /*  Find codebook index */ 
 
    index = D4i64_LBC(Dn, rr, h, tmp_code, rr, shift, sign); 
 
    /*  Compute innovation vector gain. */ 
    /*  Include fixed-gain pitch contribution into code[]. */ 
 
    *ind_gain = G_code(X, rr, &gain_q); 
 
    for (i=0; i < SubFrLen; i++) 
        code[i] = tmp_code[i]*gain_q; 
 
    if (T0 < SubFrLen-2) 
        for (i=T0; i < SubFrLen; i++) 
            code[i] += code[i-T0]*gain_T0; 
 
    return index; 
} 
 
 
/* 
** 
** Function:        Cor_h() 
** 
** Description:     Compute correlations of h[] needed for the codebook search. 
** 
** Links to text:   Section 2.16 
** 
** Arguments: 
** 
**  FLOAT  h[]              Impulse response. 
**  FLOAT  rr[]             Correlations. 
** 
**  Outputs: 
** 
**  FLOAT  rr[]             Correlations. 
** 
**  Return value :          None 
*/ 
void Cor_h(FLOAT *H, FLOAT *rr) 
{ 
 
    /*   Compute  correlations of h[]  needed for the codebook search. */ 
    /*     h[]              :Impulse response. */ 
    /*     rr[]             :Correlations. */ 
 
    FLOAT *rri0i0, *rri1i1, *rri2i2, *rri3i3; 
    FLOAT *rri0i1, *rri0i2, *rri0i3; 
    FLOAT *rri1i2, *rri1i3, *rri2i3; 
 
    FLOAT *p0, *p1, *p2, *p3; 
    FLOAT cor, *h2; 
    int   i, k, m, t; 
    FLOAT h[SubFrLen2]; 
 
    for (i=0; i=0; i--) 
    { 
        cor += h[m+0]*h[m+0] + h[m+1]*h[m+1];   rri3i3[i] = cor; 
        cor += h[m+2]*h[m+2] + h[m+3]*h[m+3];   rri2i2[i] = cor; 
        cor += h[m+4]*h[m+4] + h[m+5]*h[m+5];   rri1i1[i] = cor; 
        cor += h[m+6]*h[m+6] + h[m+7]*h[m+7];   rri0i0[i] = cor; 
 
        m += 8; 
    } 
 
    /*  Compute elements of: rri0i1[], rri0i3[], rri1i2[] and rri2i3[] */ 
 
    h2 = h+2; 
    p3 = rri2i3 + MSIZE-1; 
    p2 = rri1i2 + MSIZE-1; 
    p1 = rri0i1 + MSIZE-1; 
    p0 = rri0i3 + MSIZE-2; 
 
    for (k=0; k 17 bits; 4 pulses in a frame of 60 samples 
** 
**                     The code length is 60, containing 4 nonzero pulses 
**                     i0, i1, i2, i3. Each pulse can have 8 possible 
**                     positions (positive or negative): 
** 
**                     i0 (+-1) : 0, 8,  16, 24, 32, 40, 48, 56 
**                     i1 (+-1) : 2, 10, 18, 26, 34, 42, 50, 58 
**                     i2 (+-1) : 4, 12, 20, 28, 36, 44, 52, (60) 
**                     i3 (+-1) : 6, 14, 22, 30, 38, 46, 54, (62) 
** 
**                     All the pulse can be shifted by one. 
**                     The last position of the last 2 pulses falls outside the 
**                     frame and signifies that the pulse is not present. 
**                     The threshold controls if a section of the innovative 
**                     codebook should be searched or not. 
** 
**  Links to the text: Section 2.16 
** 
**  Input arguments: 
** 
**      FLOAT  Dn[]       Correlation between target vector & impulse resp h[] 
**      FLOAT  rr[]       Correlations of impulse response h[] 
**      FLOAT  h[]        Impulse response of filters 
** 
**  Output arguments: 
** 
**      FLOAT  cod[]      Selected algebraic codeword 
**      FLOAT  y[]        Filtered codeword 
**      int    code_shift Shift of the codeword 
**      int    sign       Signs of the 4 pulses. 
** 
**  Return value: 
** 
**      int    Index of selected codevector 
** 
*/ 
 
int D4i64_LBC(FLOAT Dn[], FLOAT rr[], FLOAT h[], FLOAT cod[], 
        FLOAT y[], int *code_shift, int *sign) 
{ 
    int  i0, i1, i2, i3, ip0, ip1, ip2, ip3; 
    int  i, j, time; 
    int  shif, shift; 
 
    FLOAT  ps0, ps1, ps2, ps3; 
    FLOAT  alp0, alp1, alp2, alp3; 
    FLOAT  ps0a, ps1a, ps2a; 
    FLOAT  ps3c, psc, alpha; 
    FLOAT  means, max0, max1, max2, thres; 
 
    FLOAT *rri0i0,*rri1i1,*rri2i2,*rri3i3; 
    FLOAT *rri0i1,*rri0i2,*rri0i3; 
    FLOAT *rri1i2,*rri1i3,*rri2i3; 
 
    FLOAT *ptr_ri0i0,*ptr_ri1i1,*ptr_ri2i2,*ptr_ri3i3; 
    FLOAT *ptr_ri0i1,*ptr_ri0i2,*ptr_ri0i3; 
    FLOAT *ptr_ri1i2,*ptr_ri1i3,*ptr_ri2i3; 
 
    int  p_sign[SubFrLen2/2],p_sign2[SubFrLen2/2]; 
 
    /*  Init pointers  */ 
 
    rri0i0 = rr; 
    rri1i1 = rri0i0 + NB_POS; 
    rri2i2 = rri1i1 + NB_POS; 
    rri3i3 = rri2i2 + NB_POS; 
 
    rri0i1 = rri3i3 + NB_POS; 
    rri0i2 = rri0i1 + MSIZE; 
    rri0i3 = rri0i2 + MSIZE; 
    rri1i2 = rri0i3 + MSIZE; 
    rri1i3 = rri1i2 + MSIZE; 
    rri2i3 = rri1i3 + MSIZE; 
 
    /*  Extend the backward filtered target vector by zeros                 */ 
 
    for (i=SubFrLen; i < SubFrLen2; i++) 
        Dn[i] = (FLOAT)0.0; 
 
    /*  Chose the sign of the impulse.                                      */ 
 
    for (i=0; i= (FLOAT)0.0) 
        { 
            p_sign[i/2] = 1; 
            p_sign2[i/2] = 2; 
        } 
        else 
        { 
            p_sign[i/2] = -1; 
            p_sign2[i/2] = -2; 
            Dn[i] = -Dn[i]; 
            Dn[i+1] = -Dn[i+1]; 
        } 
    } 
    p_sign[30] = p_sign[31] = 1; 
    p_sign2[30] = p_sign2[31] = 2; 
 
    /*  - Compute the search threshold after three pulses                  */ 
    /*  odd positions  */ 
    /*  Find maximum of Dn[i0]+Dn[i1]+Dn[i2] */ 
 
    max0 = Dn[0]; 
    max1 = Dn[2]; 
    max2 = Dn[4]; 
    for (i=8; i < SubFrLen; i+=STEP) 
    { 
        if (Dn[i] > max0) 
            max0 = Dn[i]; 
        if (Dn[i+2] > max1) 
            max1 = Dn[i+2]; 
        if (Dn[i+4] > max2) 
            max2 = Dn[i+4]; 
    } 
    max0 = max0 + max1 + max2; 
 
    /*  Find means of Dn[i0]+Dn[i1]+Dn[i] */ 
 
    means = (FLOAT)0.0; 
    for (i=0; i < SubFrLen; i+=STEP) 
        means += Dn[i+4] + Dn[i+2] + Dn[i]; 
 
    means *= (FLOAT)0.125; 
    thres = means + (max0-means)*(FLOAT)0.5; 
 
 
    /*  even positions */ 
    /*  Find maximum of Dn[i0]+Dn[i1]+Dn[i2] */ 
 
    max0 = Dn[1]; 
    max1 = Dn[3]; 
    max2 = Dn[5]; 
    for (i=9; i < SubFrLen; i+=STEP) 
    { 
        if (Dn[i] > max0) 
            max0 = Dn[i]; 
        if (Dn[i+2] > max1) 
            max1 = Dn[i+2]; 
        if (Dn[i+4] > max2) 
            max2 = Dn[i+4]; 
    } 
    max0 = max0 + max1 + max2; 
 
    /*  Find means of Dn[i0]+Dn[i1]+Dn[i2]  */ 
 
    means = (FLOAT)0.0; 
    for (i=1; i < SubFrLen; i+=STEP) 
        means += Dn[i+4] + Dn[i+2] + Dn[i]; 
 
    means *= (FLOAT)0.125; 
    max1 = means + (max0-means)*(FLOAT)0.5; 
 
    /*  Keep maximum threshold between odd and even position  */ 
 
    if (max1 > thres) 
        thres = max1; 
 
    /*  Modification of rrixiy[] to take signs into account. */ 
 
    ptr_ri0i1 = rri0i1; 
    ptr_ri0i2 = rri0i2; 
    ptr_ri0i3 = rri0i3; 
 
    for (i0=0; i0 ps2) 
                { 
                    shift = 1; 
                    ps2   = ps2a; 
                } 
 
                /*  Test threshold  */ 
 
                if (ps2 > thres) 
                { 
 
                    /*  Init. pointers that depend on 4th loop */ 
 
                    ptr_ri3i3 = rri3i3; 
 
                    /*  4th pulse loop */ 
 
                    for (i3 = 6; i3 < SubFrLen2; i3 +=STEP) 
                    { 
                        ps3 = ps2 + Dn[i3+shift]; 
                        alp3 = alp2 + *ptr_ri3i3++ + 
                        *ptr_ri0i3++ + *ptr_ri1i3++ + *ptr_ri2i3++; 
 
                        ps3c = ps3 * ps3; 
                        if ((ps3c * alpha) > (psc * alp3)) 
                        { 
                            psc = ps3c; 
                            alpha = alp3; 
                            ip0 = i0; 
                            ip1 = i1; 
                            ip2 = i2; 
                            ip3 = i3; 
                            shif = shift; 
                        } 
                    } 
 
                    time--; 
 
                    /*  Maximum time finish  */ 
 
                    if (time <= 0) 
                        goto end_search; 
                    ptr_ri0i3 -= NB_POS; 
                    ptr_ri1i3 -= NB_POS; 
                } 
 
                else 
                    ptr_ri2i3 += NB_POS; 
            } 
 
            ptr_ri0i2 -= NB_POS; 
            ptr_ri1i3 += NB_POS; 
        } 
 
        ptr_ri0i2 += NB_POS; 
        ptr_ri0i3 += NB_POS; 
    } 
 
end_search: 
 
    extra = time; 
 
    /*  Set the sign of impulses  */ 
 
    i0 = p_sign[(ip0 >> 1)]; 
    i1 = p_sign[(ip1 >> 1)]; 
    i2 = p_sign[(ip2 >> 1)]; 
    i3 = p_sign[(ip3 >> 1)]; 
 
    /*  Find the codeword corresponding to the selected positions  */ 
 
    for (i=0; i 0) 
    { 
        ip0++; 
        ip1++; 
        ip2++; 
        ip3++; 
    } 
 
    cod[ip0] =  (FLOAT)i0; 
    cod[ip1] =  (FLOAT)i1; 
    if (ip2 0) 
        for (i=ip0, j=0; i 0) 
        for (i=ip1, j=0; i 0) 
            for (i=ip2, j=0; i 0) 
            for (i=ip3, j=0; i 0) 
        *sign += 1; 
    if (i1 > 0) 
        *sign += 2; 
    if (i2 > 0) 
        *sign += 4; 
    if (i3 > 0) 
        *sign += 8; 
 
    i = ((ip3 >> 3) << 9) + ((ip2 >> 3) << 6) + ((ip1 >> 3) << 3) + (ip0 >> 3); 
 
    return i; 
} 
 
 
/* 
** 
**  Function:  G_code() 
** 
**  Description: Compute the gain of innovative code. 
** 
** 
**  Links to the text: Section 2.16 
** 
** Input arguments: 
** 
**      FLOAT  X[]        Code target.  (in Q0) 
**      FLOAT  Y[]        Filtered innovation code. (in Q12) 
** 
** Output: 
** 
**      FLOAT  *gain_q    Gain of innovation code.  (in Q0) 
** 
**  Return value: 
** 
**      int     index of innovation code gain 
** 
*/ 
int G_code(FLOAT X[], FLOAT Y[], FLOAT *gain_q) 
{ 
    int     i; 
    FLOAT   xy, yy, gain_nq; 
    int     gain; 
    FLOAT   dist, dist_min; 
 
    /*  Compute scalar product  */ 
 
    xy = DotProd(X,Y,SubFrLen); 
 
    if (xy <= 0) 
    { 
        gain = 0; 
        *gain_q =FcbkGainTable[gain]; 
        return(gain); 
    } 
 
    /*  Compute scalar product   */ 
 
    yy = DotProd(Y,Y,SubFrLen); 
 
    if (yy > (FLOAT) FLT_MIN) 
        gain_nq = xy/yy; 
    else 
        gain_nq = (FLOAT)0.0; 
 
    gain = 0; 
    dist_min = (FLOAT)fabs(gain_nq - FcbkGainTable[0]); 
 
    for (i=1; i = (SubFrLen-2) ) 
            ptr_tab = tabgain170; 
    } 
    else { 
        ptr_tab = tabgain170; 
    } 
    beta = ptr_tab[(int)AcGn]; 
 
 
    if (Lag <= (SubFrLen/2)) 
    { 
        Worst0 = CodStat.Err[0]*beta + Err0; 
        Worst1 = Worst0; 
    } 
    else 
    { 
        iz = (int)(((Word32)Lag*1092L) >> 15); 
        temp2 = 30*(iz+1); 
 
        if (temp2 != Lag) 
        { 
            if (iz == 1) 
            { 
                Worst0 = CodStat.Err[0]*beta + Err0; 
                Worst1 = CodStat.Err[1]*beta + Err0; 
 
                if (Worst0 > Worst1) 
                    Worst1 = Worst0; 
                else 
                    Worst0 = Worst1; 
            } 
            else 
            { 
                wtemp = CodStat.Err[iz-1]*beta + Err0; 
                Worst0 = CodStat.Err[iz-2]*beta + Err0; 
                if (wtemp > Worst0) 
                    Worst0 = wtemp; 
                Worst1 = CodStat.Err[iz]*beta + Err0; 
                if (wtemp > Worst1) 
                    Worst1 = wtemp; 
            } 
        } 
        else 
        { 
            Worst0 = CodStat.Err[iz-1]*beta + Err0; 
            Worst1 = CodStat.Err[iz]*beta + Err0; 
        } 
    } 
 
    if (Worst0 > MAXV) 
        Worst0 = MAXV; 
    if (Worst1 > MAXV) 
        Worst1 = MAXV; 
 
    for (i=4; i>=2; i--) 
        CodStat.Err[i] = CodStat.Err[i-2]; 
 
    CodStat.Err[0] = Worst0; 
    CodStat.Err[1] = Worst1; 
 
    return; 
} 
 
/* 
** 
** Function:    Test_Err() 
** 
** Description:   Check the error excitation maximum for 
**          the subframe and computes an index iTest used to 
**          calculate the maximum nb of filters (in Find_Acbk) : 
**          Bound = Min(Nmin + iTest x pas, Nmax) , with 
**          AcbkGainTable085 : pas = 2, Nmin = 51, Nmax = 85 
**          AcbkGainTable170 : pas = 4, Nmin = 93, Nmax = 170 
**          iTest depends on the relative difference between 
**          errmax and a fixed threshold 
** 
** Links to text:   Section 
** 
** Arguments: 
** 
**  Word16 Lag1    1st long term Lag of the tested zone 
**  Word16 Lag2    2nd long term Lag of the tested zone 
** 
** Outputs: None 
** 
** Return value: 
**  Word16      index iTest used to compute Acbk number of filters 
*/ 
int Test_Err(int Lag1, int Lag2) 
{ 
    int     i, i1, i2; 
    int     zone1, zone2, iTest; 
    FLOAT   Err_max; 
 
    i2 = Lag2 + ClPitchOrd/2; 
    zone2 = i2/30; 
 
    i1 = - SubFrLen + 1 + Lag1 - ClPitchOrd/2; 
    if (i1 <= 0) 
        i1 = 1; 
    zone1 = i1/30; 
 
    Err_max = (FLOAT)-1.0; 
    for (i=zone2; i>=zone1; i--) 
    { 
        if (CodStat.Err[i] > Err_max) 
            Err_max = CodStat.Err[i]; 
    } 
    if ((Err_max > ThreshErr) || (CodStat.SinDet < 0 ) ) 
    { 
        iTest = 0; 
    } 
    else 
    { 
        iTest = (Word16)(ThreshErr - Err_max); 
    } 
 
    return(iTest); 
} 
 
/* 
** 
** Function:        Find_Acbk() 
** 
** Description:     Computation of adaptive codebook contribution in 
**                  closed-loop around open-loop pitch lag (subframes 0 & 2) 
**                  around the previous subframe closed-loop pitch lag 
**                  (subframes 1 & 3).  For subframes 0 & 2, the pitch lag is 
**                  encoded whereas for subframes 1 & 3, only the difference 
**                  with the previous value is encoded (-1, 0, +1 or +2). 
**                  The pitch predictor gains are quantized using one of two 
**                  codebooks (85 entries or 170 entries) depending on the 
**                  rate and on the pitch lag value. 
**                  Finally, the contribution of the pitch predictor is decoded 
**                  and subtracted to obtain the residual signal. 
** 
** Links to text:   Section 2.14 
** 
** Arguments: 
** 
**  FLOAT  *Tv      Target vector 
**  FLOAT  *ImpResp Impulse response of the combined filter 
**  FLOAT  *PrevExc Previous excitation vector 
**  LINEDEF *Line   Contains pitch parameters (open/closed loop lag, gain) 
**  int    Sfc      Subframe index 
** 
** Outputs: 
** 
**  FLOAT  *Tv     Residual vector 
**  LINEDEF *Line  Contains pitch related parameters (closed loop lag, gain) 
** 
** Return value:    None 
** 
*/ 
void  Find_Acbk(FLOAT *Tv, FLOAT *ImpResp, FLOAT *PrevExc, 
                LINEDEF *Line, int Sfc) 
{ 
    int i,j,k,l; 
 
    FLOAT Acc0,Max; 
 
    FLOAT RezBuf[SubFrLen+ClPitchOrd-1]; 
    FLOAT FltBuf[ClPitchOrd][SubFrLen]; 
    FLOAT CorVct[4*(2*ClPitchOrd + ClPitchOrd*(ClPitchOrd-1)/2)]; 
    FLOAT *lPnt; 
    FLOAT *sPnt; 
 
    int   Olp,Lid,Gid,Hb; 
    int   Bound[2]; 
    int   Lag1, Lag2; 
    int   off_filt; 
 
    Olp = (*Line).Olp[Sfc>>1]; 
    Lid = Pstep; 
    Gid = 0; 
    Hb  = 3 + (Sfc & 1); 
 
    /*  For even frames only */ 
 
    if ((Sfc & 1) == 0) 
    { 
        if (Olp == PitchMin) 
            Olp++; 
        if (Olp > (PitchMax-5)) 
            Olp = PitchMax-5; 
    } 
 
    lPnt = CorVct; 
    for (k=0; k < Hb; k++) 
    { 
 
        /*  Get residual from the exitation buffer */ 
 
        Get_Rez(RezBuf, PrevExc, Olp-Pstep+k); 
 
        /*  Filter the last one (ClPitchOrd-1) using the impulse responce */ 
 
        for (i=0; i < SubFrLen; i++) 
        { 
            Acc0 = (FLOAT)0.0; 
            for (j=0; j <= i; j++) 
                Acc0 += RezBuf[ClPitchOrd-1+j]*ImpResp[i-j]; 
 
            FltBuf[ClPitchOrd-1][i] = Acc0; 
        } 
 
        /*  Update the others (ClPitchOrd-2 down to 0) */ 
 
        for (i=ClPitchOrd-2; i >= 0; i --) 
        { 
            FltBuf[i][0] = RezBuf[i]; 
            for (j = 1; j < SubFrLen; j++) 
                FltBuf[i][j] = RezBuf[i]*ImpResp[j] + FltBuf[i+1][j-1]; 
        } 
 
        /*  Compute the cross products with the signal */ 
 
        for (i=0; i < ClPitchOrd; i++) 
            *lPnt++ = DotProd(Tv, FltBuf[i], SubFrLen); 
 
        /*  Compute the energies */ 
 
        for (i=0; i < ClPitchOrd; i++) 
            *lPnt++ = ((FLOAT)0.5)*DotProd(FltBuf[i], FltBuf[i], SubFrLen); 
 
        /*  Compute the between crosses */ 
 
        for (i=1; i < ClPitchOrd; i++) 
            for (j = 0; j < i; j++) 
                *lPnt++ = DotProd(FltBuf[i], FltBuf[j], SubFrLen); 
    } 
 
    /* Test potential error */ 
    Lag1 = Olp - Pstep; 
    Lag2 = Olp - Pstep + Hb - 1; 
 
    off_filt = Test_Err(Lag1, Lag2); 
 
    Bound[0] =  NbFilt085_min + (off_filt << 2); 
    if (Bound[0] > NbFilt085) 
        Bound[0] = NbFilt085; 
    Bound[1] =  NbFilt170_min + (off_filt << 3); 
    if (Bound[1] > NbFilt170) 
        Bound[1] = NbFilt170; 
 
    Max = (FLOAT)0.0; 
    for (k=0; k < Hb; k++) 
    { 
 
        /*  Select Quantization table */ 
        l = 0; 
        if (WrkRate == Rate63) 
        { 
            if ((Sfc & 1) == 0) 
            { 
                if (Olp-Pstep+k >= SubFrLen-2) 
                    l = 1; 
            } 
            else 
            { 
                if (Olp >= SubFrLen-2) 
                    l = 1; 
            } 
        } 
        else 
            l = 1; 
 
        /*  Search for maximum */ 
 
        sPnt = AcbkGainTablePtr[l]; 
 
        for (i=0; i < Bound[l]; i++) 
        { 
            Acc0 = DotProd(&CorVct[k*20],sPnt,20); 
            sPnt += 20; 
 
            if (Acc0 > Max) 
            { 
                Max = Acc0; 
                Gid = i; 
                Lid = k; 
            } 
        } 
    } 
 
    /*  Modify Olp for even sub frames */ 
 
    if ((Sfc & 1) == 0) 
    { 
        Olp = Olp - Pstep + Lid; 
        Lid = Pstep; 
    } 
 
 
    /*  Save Lag, Gain and Olp */ 
 
    (*Line).Sfs[Sfc].AcLg = Lid; 
    (*Line).Sfs[Sfc].AcGn = Gid; 
    (*Line).Olp[Sfc>>1] = Olp; 
 
    /*  Decode the Acbk contribution and subtract it */ 
 
    Decod_Acbk(RezBuf, PrevExc, Olp, Lid, Gid); 
 
    for (i=0; i < SubFrLen; i++) 
    { 
        Acc0 = Tv[i]; 
 
        for (j=0; j <= i; j++) 
            Acc0 -= RezBuf[j]*ImpResp[i-j]; 
 
        Tv[i] = Acc0; 
    } 
} 
 
 
/* 
** 
** Function:        Get_Rez() 
** 
** Description:     Gets delayed contribution from the previous excitation 
**                  vector. 
** 
** Links to text:   Sections 2.14, 2.18 & 3.4 
** 
** Arguments: 
** 
**  FLOAT  *Tv      delayed excitation 
**  FLOAT  *PrevExc Previous excitation vector 
**  int    Lag      Closed loop pitch lag 
** 
** Outputs: 
** 
**  FLOAT  *Tv      delayed excitation 
** 
** Return value:    None 
** 
*/ 
void  Get_Rez(FLOAT *Tv, FLOAT *PrevExc, int Lag) 
{ 
    int i; 
 
    for (i=0; i < ClPitchOrd/2; i++) 
        Tv[i] = PrevExc[PitchMax - Lag - ClPitchOrd/2 + i]; 
 
    for (i=0; i < SubFrLen+ClPitchOrd/2; i++) 
        Tv[ClPitchOrd/2+i] = PrevExc[PitchMax - Lag + i%Lag]; 
} 
 
 
/* 
** 
** Function:        Decod_Acbk() 
** 
** Description:     Computes the adaptive codebook contribution from the previous 
**                  excitation vector. 
**                  With the gain index, the closed loop pitch lag, the jitter 
**                  which when added to this pitch lag gives the actual closed 
**                  loop value, and after having selected the proper codebook, 
**                  the pitch contribution is reconstructed using the previous 
**                  excitation buffer. 
** 
** Links to text:   Sections 2.14, 2.18 & 3.4 
** 
** Arguments: 
** 
**  FLOAT  *Tv      Reconstructed excitation vector 
**  FLOAT  *PrevExc Previous excitation vector 
**  int    Olp      closed-loop pitch period 
**  int    Lid      Jitter around pitch period 
**  int    Gid      Gain vector index in 5- dimensional 
**                      adaptive gain vector codebook 
** 
** Outputs: 
** 
**  FLOAT  *Tv      Reconstructed excitation vector 
** 
** Return value:    None 
** 
*/ 
void  Decod_Acbk(FLOAT *Tv, FLOAT *PrevExc, int Olp, int Lid, int Gid) 
{ 
    int      i; 
    FLOAT    RezBuf[SubFrLen+ClPitchOrd-1]; 
    FLOAT   *sPnt; 
 
    Get_Rez(RezBuf, PrevExc, (Olp + Lid) - Pstep); 
 
 
    i = 0; 
    if (WrkRate == Rate63) 
    { 
        if (Olp >= (SubFrLen-2)) 
            i++; 
    } 
    else 
        i=1; 
 
    sPnt = AcbkGainTablePtr[i] + Gid*20; 
 
    /*  Compute output vector */ 
 
    for (i=0; i < SubFrLen; i++) 
        Tv[i] = DotProd(&RezBuf[i], sPnt, ClPitchOrd); 
} 
 
/* 
** 
** Function:        Comp_Lpf() 
** 
** Description:     Computes pitch postfilter parameters. 
**                  The pitch postfilter lag is first derived (Find_B 
**                  and Find_F). Then, the one that gives the largest 
**                  contribution is used to calculate the gains (Get_Ind). 
** 
** 
** Links to text:   Section 3.6 
** 
** Arguments: 
** 
**  FLOAT  *Buff    decoded excitation 
**  int    Olp      Decoded pitch lag 
**  int    Sfc      Subframe index 
** 
** Outputs: 
** 
** 
** Return value: 
** 
**  PFDEF       Pitch postfilter parameters: PF.Gain    Pitch Postfilter gain 
**                                           PF.ScGn    Pitch Postfilter scaling gain 
**                                           PF.Indx    Pitch postfilter lag 
*/ 
PFDEF Comp_Lpf(FLOAT *Buff, int Olp, int Sfc) 
{ 
    PFDEF  Pf; 
    FLOAT  Lcr[5]; 
    int    Bindx, Findx; 
    FLOAT  Acc0,Acc1; 
 
    /*  Initialize  */ 
 
    Pf.Indx = 0; 
    Pf.Gain = (FLOAT)0.0; 
    Pf.ScGn = (FLOAT)1.0; 
 
    /*  Find both indices */ 
 
    Bindx = Find_B(Buff, Olp, Sfc); 
    Findx = Find_F(Buff, Olp, Sfc); 
 
    /*  Combine the results */ 
 
    if ((Bindx==0) && (Findx==0)) 
        return Pf; 
 
    /*  Compute target energy  */ 
 
    Lcr[0] = DotProd(&Buff[PitchMax+Sfc*SubFrLen], 
                    &Buff[PitchMax+Sfc*SubFrLen],SubFrLen); 
 
    if (Bindx != 0) 
    { 
        Lcr[1] = DotProd(&Buff[PitchMax+Sfc*SubFrLen], 
                        &Buff[PitchMax+Sfc*SubFrLen+Bindx],SubFrLen); 
        Lcr[2] = DotProd(&Buff[PitchMax+Sfc*SubFrLen+Bindx], 
                        &Buff[PitchMax+Sfc*SubFrLen+Bindx],SubFrLen); 
    } 
 
    if (Findx != 0) 
    { 
        Lcr[3] = DotProd(&Buff[PitchMax+Sfc*SubFrLen], 
                        &Buff[PitchMax+Sfc*SubFrLen+Findx],SubFrLen); 
        Lcr[4] = DotProd(&Buff[PitchMax+Sfc*SubFrLen+Findx], 
                        &Buff[PitchMax+Sfc*SubFrLen+Findx],SubFrLen); 
    } 
 
    /*  Select the best pair  */ 
 
    if ((Bindx != 0) && (Findx == 0)) 
        Pf = Get_Ind(Bindx, Lcr[0], Lcr[1], Lcr[2]); 
 
    if ((Bindx == 0) && (Findx != 0)) 
        Pf = Get_Ind(Findx, Lcr[0], Lcr[3], Lcr[4]); 
 
    if ((Bindx != 0) && (Findx != 0)) 
    { 
        Acc0 = Lcr[4] * Lcr[1] * Lcr[1]; 
        Acc1 = Lcr[2] * Lcr[3] * Lcr[3]; 
        if (Acc0 > Acc1) 
            Pf = Get_Ind(Bindx, Lcr[0], Lcr[1], Lcr[2]); 
        else 
            Pf = Get_Ind(Findx, Lcr[0], Lcr[3], Lcr[4]); 
    } 
 
    return Pf; 
} 
 
/* 
** 
** Function:        Find_B() 
** 
** Description:     Computes best pitch postfilter backward lag by 
**                  backward cross correlation maximization around the 
**                  decoded pitch lag 
**                  of the subframe 0 (for subrames 0 & 1) 
**                  of the subframe 2 (for subrames 2 & 3) 
** 
** Links to text:   Section 3.6 
** 
** Arguments: 
** 
**  FLOAT  *Buff    decoded excitation 
**  int    Olp      Decoded pitch lag 
**  int    Sfc      Subframe index 
** 
** Outputs:     None 
** 
** Return value: 
** 
**  Word16   Pitch postfilter backward lag 
*/ 
int  Find_B(FLOAT *Buff, int Olp, int Sfc) 
{ 
    int  i; 
 
    int  Indx = 0; 
 
    FLOAT  Acc0,Acc1; 
 
    if (Olp > (PitchMax-3)) 
        Olp = (PitchMax-3); 
 
    Acc1 = (FLOAT)0.0; 
 
    for (i=Olp-3; i<=Olp+3; i++) 
    { 
        Acc0 = DotProd(&Buff[PitchMax+Sfc*SubFrLen], 
                    &Buff[PitchMax+Sfc*SubFrLen-i],SubFrLen); 
 
        /* return index of largest cross correlation */ 
 
        if (Acc0 > Acc1) 
        { 
            Acc1 = Acc0; 
            Indx = i; 
        } 
    } 
    return -Indx; 
} 
 
 
/* 
** 
** Function:        Find_F() 
** 
** Description:     Computes best pitch postfilter forward lag by 
**                  forward cross correlation maximization around the 
**                  decoded pitch lag 
**                  of the subframe 0 (for subrames 0 & 1) 
**                  of the subframe 2 (for subrames 2 & 3) 
** 
** Links to text:   Section 3.6 
** 
** Arguments: 
** 
**  FLOAT  *Buff    decoded excitation 
**  int    Olp      Decoded pitch lag 
**  int    Sfc      Subframe index 
** 
** Outputs:     None 
** 
** Return value: 
** 
**  int       Pitch postfilter forward lag 
*/ 
int  Find_F(FLOAT *Buff, int Olp, int Sfc) 
{ 
    int    i; 
    int    Indx = 0; 
    FLOAT  Acc0,Acc1; 
 
    if (Olp > (PitchMax-3)) 
        Olp = (PitchMax-3); 
 
    Acc1 = (FLOAT)0.0; 
 
    for (i=Olp-3; i<=Olp+3; i++) 
    { 
        if (!((Sfc*SubFrLen+SubFrLen+i) > Frame)) 
        { 
            Acc0 = DotProd(&Buff[PitchMax+Sfc*SubFrLen], 
                            &Buff[PitchMax+Sfc*SubFrLen+i],SubFrLen); 
 
            /* return index of largest cross correlation */ 
 
            if (Acc0 > Acc1) 
            { 
                Acc1 = Acc0; 
                Indx = i; 
            } 
        } 
    } 
 
    return Indx; 
} 
 
/* 
** 
** Function:        Filt_Lpf() 
** 
** Description:     Applies the pitch postfilter for each subframe. 
** 
** Links to text:   Section 3.6 
** 
** Arguments: 
** 
**  FLOAT  *Tv      Pitch postfiltered excitation 
**  FLOAT  *Buff    decoded excitation 
**  PFDEF Pf        Pitch postfilter parameters 
**  int    Sfc      Subframe index 
** 
** Outputs: 
** 
**  FLOAT  *Tv      Pitch postfiltered excitation 
** 
** Return value: None 
** 
*/ 
void  Filt_Lpf(FLOAT *Tv, FLOAT *Buff, PFDEF Pf, int Sfc) 
{ 
    int  i; 
 
    for (i = 0; i < SubFrLen; i++) 
        Tv[Sfc*SubFrLen+i]= Buff[PitchMax+Sfc*SubFrLen+i]*Pf.ScGn + 
                            Buff[PitchMax+Sfc*SubFrLen+Pf.Indx+i]*Pf.Gain; 
} 
 
 
/* 
** 
** Function:        Get_Ind() 
** 
** Description:     Computes gains of the pitch postfilter. 
**                  The gains are calculated using the cross correlation 
**                  (forward or backward, the one with the greatest contribution) 
**                  and the energy of the signal. Also, a test is performed on 
**                  the prediction gain to see whether the pitch postfilter 
**                  should be used or not. 
** 
** 
** 
** Links to text:   Section 3.6 
** 
** Arguments: 
** 
**  int    Ind      Pitch postfilter lag 
**  FLOAT  Ten      energy of the current subframe excitation vector 
**  FLOAT  Ccr      Crosscorrelation of the excitation 
**  FLOAT  Enr      Energy of the (backward or forward) "delayed" excitation 
** 
** Outputs:     None 
** 
** Return value: 
** 
**  PFDEF 
**         int      Indx    Pitch postfilter lag 
**         FLOAT    Gain    Pitch postfilter gain 
**         FLOAT    ScGn    Pitch postfilter scaling gain 
** 
*/ 
PFDEF Get_Ind(int Ind, FLOAT Ten, FLOAT Ccr, FLOAT Enr) 
{ 
    FLOAT  Acc0,Acc1; 
    FLOAT  Exp; 
 
    PFDEF Pf; 
 
 
    Pf.Indx = Ind; 
 
    /*  Check valid gain > 2db */ 
 
    Acc0 = (Ten * Enr)/(FLOAT)4.0; 
    Acc1 = Ccr * Ccr; 
 
    if (Acc1 > Acc0) 
    { 
        if (Ccr >= Enr) 
            Pf.Gain = LpfConstTable[WrkRate]; 
        else 
            Pf.Gain = (Ccr/Enr) * LpfConstTable[WrkRate]; 
 
        /*  Compute scaling gain  */ 
 
        Exp  = Ten + 2*Ccr*Pf.Gain + Pf.Gain*Pf.Gain*Enr; 
 
        if (fabs(Exp) < (FLOAT) FLT_MIN) 
            Pf.ScGn = (FLOAT)0.0; 
        else 
            Pf.ScGn = (FLOAT)sqrt(Ten/Exp); 
    } 
    else 
    { 
        Pf.Gain = (FLOAT)0.0; 
        Pf.ScGn = (FLOAT)1.0; 
    } 
 
    Pf.Gain = Pf.Gain * Pf.ScGn; 
 
    return Pf; 
} 
 
/* 
** 
** Function:        Comp_Info() 
** 
** Description:     Voiced/unvoiced classifier. 
**                  It is based on a cross correlation maximization over the 
**                  last 120 samples of the frame and with an index varying 
**                  around the decoded pitch lag (from L-3 to L+3). Then the 
**                  prediction gain is tested to declare the frame voiced or 
**                  unvoiced. 
** 
** Links to text:   Section 3.10.2 
** 
** Arguments: 
** 
**  FLOAT  *Buff  decoded excitation 
**  int    Olp    Decoded pitch lag 
**  FLOAT  *Gain 
** 
** Outputs: None 
** 
** Return value: 
** 
**      Word16    Estimated pitch value 
*/ 
Word16  Comp_Info(FLOAT *Buff, int Olp, FLOAT *Gain) 
{ 
    int    i; 
    FLOAT  Acc0; 
    FLOAT  Tenr; 
    FLOAT  Ccr,Enr; 
    int    Indx; 
 
    if (Olp > (PitchMax-3)) 
        Olp = (PitchMax-3); 
 
    Indx = Olp; 
    Ccr =  (FLOAT)0.0; 
 
    for (i=Olp-3; i <= Olp+3; i++) 
    { 
        Acc0 = DotProd(&Buff[PitchMax+Frame-2*SubFrLen], 
                        &Buff[PitchMax+Frame-2*SubFrLen-i],2*SubFrLen); 
 
        if (Acc0 > Ccr) 
        { 
            Ccr = Acc0; 
            Indx = i; 
        } 
    } 
 
    /*  Compute target energy  */ 
 
    Tenr = DotProd(&Buff[PitchMax+Frame-2*SubFrLen], 
                    &Buff[PitchMax+Frame-2*SubFrLen],2*SubFrLen); 
    *Gain = Tenr; 
 
    /*  Compute best energy */ 
 
    Enr = DotProd(&Buff[PitchMax+Frame-2*SubFrLen-Indx], 
                    &Buff[PitchMax+Frame-2*SubFrLen-Indx],2*SubFrLen); 
 
    if (Ccr <= (FLOAT)0.0) 
        return 0; 
 
    if (((((FLOAT)0.125)*Enr*Tenr) - (Ccr*Ccr)) < (FLOAT)0.0) 
        return (Word16) Indx; 
 
    return 0; 
} 
 
 
/* 
** 
** Function:        Regen() 
** 
** Description:     Performs residual interpolation depending of the frame 
**                  classification. 
**                  If the frame is previously declared unvoiced, the excitation 
**                  is regenerated using a random number generator. Otherwise 
**                  a periodic excitation is generated with the period previously 
**                  found. 
** 
** Links to text:   Section 3.10.2 
** 
** Arguments: 
** 
**  FLOAT  *DataBuff current subframe decoded excitation 
**  FLOAT  *Buff     past decoded excitation 
**  Word16 Lag       Decoded pitch lag from previous frame 
**  FLOAT  Gain      Interpolated gain from previous frames 
**  int    Ecount    Number of erased frames 
**  Word16 *Sd       Random number used in unvoiced cases 
** 
** Outputs: 
** 
**  Word16 *DataBuff current subframe decoded excitation 
**  Word16 *Buff     updated past excitation 
** 
** Return value:    None 
** 
*/ 
void    Regen(FLOAT *DataBuff, FLOAT *Buff, Word16 Lag, FLOAT Gain, 
              int Ecount, Word16 *Sd) 
{ 
    int  i; 
 
    /*  Test for clearing */ 
 
    if (Ecount >= ErrMaxNum) 
    { 
        for (i = 0; i < Frame; i++) 
            DataBuff[i] = (FLOAT)0.0; 
        for (i = 0; i < Frame+PitchMax; i++) 
            Buff[i] = (FLOAT)0.0; 
    } 
    else 
    { 
 
        /*  Interpolate accordingly to the voicing estimation */ 
 
        if (Lag != 0) 
        { 
            /*  Voiced case */ 
            for (i = 0; i < Frame; i++) 
                Buff[PitchMax+i] = Buff[PitchMax-Lag+i]; 
            for (i = 0; i < Frame; i++) 
                DataBuff[i] = Buff[PitchMax+i] = Buff[PitchMax+i] * (FLOAT)0.75; 
        } 
        else 
        { 
 
            /* Unvoiced case */ 
 
            for (i = 0; i < Frame; i++) 
                DataBuff[i] = Gain*(FLOAT)Rand_lbc(Sd)*((FLOAT)1.0/(FLOAT)32768.0); 
 
            /* Clear buffer to reset memory */ 
 
            for (i = 0; i < Frame+PitchMax; i++) 
                Buff[i] = (FLOAT)0.0; 
        } 
    } 
}