
/******************************************************************

    iLBC Speech Coder ANSI-C Source Code

    iLBC_decode.c 

    Copyright (C) The Internet Society (2004). 
    All Rights Reserved.

******************************************************************/

#include <math.h>
#include <stdlib.h>

#include "iLBC_define.h"
#include "iLBC_decode.h"
#include "StateConstructW.h"
#include "LPCdecode.h"
#include "iCBConstruct.h"
#include "doCPLC.h"
#include "helpfun.h"
#include "constants.h"
#include "packing.h"
#include "string.h"
#include "enhancer.h"
#include "hpOutput.h"
#include "syntFilter.h"

/*----------------------------------------------------------------*
 *  Initiation of decoder instance.
 *---------------------------------------------------------------*/

short initDecode(                   /* (o) Number of decoded 
                                           samples */
    iLBC_Dec_Inst_t *iLBCdec_inst,  /* (i/o) Decoder instance */
    int mode,                       /* (i) frame size mode */
    int use_enhancer                /* (i) 1 to use enhancer
                                           0 to run without 
                                             enhancer */
){
    int i;

    iLBCdec_inst->mode = mode;

    if (mode==30) {
        iLBCdec_inst->blockl = BLOCKL_30MS;
        iLBCdec_inst->nsub = NSUB_30MS;
        iLBCdec_inst->nasub = NASUB_30MS;
        iLBCdec_inst->lpc_n = LPC_N_30MS;


        iLBCdec_inst->no_of_bytes = NO_OF_BYTES_30MS;
        iLBCdec_inst->no_of_words = NO_OF_WORDS_30MS;
        iLBCdec_inst->state_short_len=STATE_SHORT_LEN_30MS;
        /* ULP init */
        iLBCdec_inst->ULP_inst=&ULP_30msTbl;
    }
    else if (mode==20) {
        iLBCdec_inst->blockl = BLOCKL_20MS;
        iLBCdec_inst->nsub = NSUB_20MS;
        iLBCdec_inst->nasub = NASUB_20MS;
        iLBCdec_inst->lpc_n = LPC_N_20MS;
        iLBCdec_inst->no_of_bytes = NO_OF_BYTES_20MS;
        iLBCdec_inst->no_of_words = NO_OF_WORDS_20MS;
        iLBCdec_inst->state_short_len=STATE_SHORT_LEN_20MS;
        /* ULP init */
        iLBCdec_inst->ULP_inst=&ULP_20msTbl;
    }
    else {
        exit(2);
    }

    memset(iLBCdec_inst->syntMem, 0, 
        LPC_FILTERORDER*sizeof(float));
    memcpy((*iLBCdec_inst).lsfdeqold, lsfmeanTbl, 
        LPC_FILTERORDER*sizeof(float));

    memset(iLBCdec_inst->old_syntdenum, 0, 
        ((LPC_FILTERORDER + 1)*NSUB_MAX)*sizeof(float));
    for (i=0; i<NSUB_MAX; i++)
        iLBCdec_inst->old_syntdenum[i*(LPC_FILTERORDER+1)]=1.0;

    iLBCdec_inst->last_lag = 20;

    iLBCdec_inst->prevLag = 120;
    iLBCdec_inst->per = 0.0;
    iLBCdec_inst->consPLICount = 0;
    iLBCdec_inst->prevPLI = 0;
    iLBCdec_inst->prevLpc[0] = 1.0;
    memset(iLBCdec_inst->prevLpc+1,0,
        LPC_FILTERORDER*sizeof(float));
    memset(iLBCdec_inst->prevResidual, 0, BLOCKL_MAX*sizeof(float));
    iLBCdec_inst->seed=777;

    memset(iLBCdec_inst->hpomem, 0, 4*sizeof(float));

    iLBCdec_inst->use_enhancer = use_enhancer;
    memset(iLBCdec_inst->enh_buf, 0, ENH_BUFL*sizeof(float));
    for (i=0;i<ENH_NBLOCKS_TOT;i++) 
        iLBCdec_inst->enh_period[i]=(float)40.0;

    iLBCdec_inst->prev_enh_pl = 0;

    return (iLBCdec_inst->blockl);
}



/*----------------------------------------------------------------*
 *  frame residual decoder function (subrutine to iLBC_decode) 
 *---------------------------------------------------------------*/

static void Decode(
    iLBC_Dec_Inst_t *iLBCdec_inst,  /* (i/o) the decoder state 
                                             structure */
    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[BLOCKL_MAX], mem[CB_MEML];
    int k, meml_gotten, Nfor, Nback, i;
    int diff, start_pos;
    int subcount, subframe;

    diff = STATE_LEN - iLBCdec_inst->state_short_len;
    
    if (state_first == 1) {
        start_pos = (start-1)*SUBL;
    } else {
        start_pos = (start-1)*SUBL + diff;
    }

    /* decode scalar part of start state */

    StateConstructW(idxForMax, idxVec, 
        &syntdenum[(start-1)*(LPC_FILTERORDER+1)], 
        &decresidual[start_pos], iLBCdec_inst->state_short_len);

    
    if (state_first) { /* put adaptive part in the end */
                


        /* setup memory */

        memset(mem, 0, 
            (CB_MEML-iLBCdec_inst->state_short_len)*sizeof(float));
        memcpy(mem+CB_MEML-iLBCdec_inst->state_short_len, 
            decresidual+start_pos, 
            iLBCdec_inst->state_short_len*sizeof(float));
        
        /* construct decoded vector */

        iCBConstruct(
            &decresidual[start_pos+iLBCdec_inst->state_short_len],
            extra_cb_index, extra_gain_index, mem+CB_MEML-stMemLTbl,
            stMemLTbl, diff, 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)*SUBL-1-
                        (k+iLBCdec_inst->state_short_len)];
        }
        
        /* setup memory */

        meml_gotten = iLBCdec_inst->state_short_len;
        for (k=0; k<meml_gotten; k++){ 
            mem[CB_MEML-1-k] = decresidual[start_pos + k];
        } 
        memset(mem, 0, (CB_MEML-k)*sizeof(float));
        
        /* construct decoded vector */

        iCBConstruct(reverseDecresidual, extra_cb_index, 
            extra_gain_index, mem+CB_MEML-stMemLTbl, stMemLTbl,
            diff, 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 = iLBCdec_inst->nsub-start-1;


    
    if ( Nfor > 0 ){
        
        /* setup memory */

        memset(mem, 0, (CB_MEML-STATE_LEN)*sizeof(float));
        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 */

            iCBConstruct(&decresidual[(start+1+subframe)*SUBL], 
                cb_index+subcount*CB_NSTAGES, 
                gain_index+subcount*CB_NSTAGES, 
                mem+CB_MEML-memLfTbl[subcount], 
                memLfTbl[subcount], SUBL, CB_NSTAGES);

            /* update memory */

            memmove(mem, mem+SUBL, (CB_MEML-SUBL)*sizeof(float));
            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 = SUBL*(iLBCdec_inst->nsub+1-start);
        
        if ( meml_gotten > CB_MEML ) { 
            meml_gotten=CB_MEML;
        }
        for (k=0; k<meml_gotten; k++) { 
            mem[CB_MEML-1-k] = decresidual[(start-1)*SUBL + k];
        }
        memset(mem, 0, (CB_MEML-k)*sizeof(float));

        /* loop over subframes to decode */



        for (subframe=0; subframe<Nback; subframe++) {
            
            /* construct decoded vector */

            iCBConstruct(&reverseDecresidual[subframe*SUBL], 
                cb_index+subcount*CB_NSTAGES, 
                gain_index+subcount*CB_NSTAGES, 
                mem+CB_MEML-memLfTbl[subcount], memLfTbl[subcount], 
                SUBL, CB_NSTAGES);

            /* update memory */

            memmove(mem, mem+SUBL, (CB_MEML-SUBL)*sizeof(float));
            memcpy(mem+CB_MEML-SUBL, 
                &reverseDecresidual[subframe*SUBL],
                SUBL*sizeof(float));

            subcount++;
        }

        /* get decoded residual from reversed vector */

        for (i=0; i<SUBL*Nback; i++)
            decresidual[SUBL*Nback - i - 1] = 
            reverseDecresidual[i];
    }
}

/*----------------------------------------------------------------*
 *  main decoder function 
 *---------------------------------------------------------------*/

void iLBC_decode( 
    float *decblock,            /* (o) decoded signal block */
    unsigned char *bytes,           /* (i) encoded signal bits */
    iLBC_Dec_Inst_t *iLBCdec_inst,  /* (i/o) the decoder state 
                                             structure */
    int mode                    /* (i) 0: bad packet, PLC, 
                                           1: normal */
){
    float data[BLOCKL_MAX];
    float lsfdeq[LPC_FILTERORDER*LPC_N_MAX];
    float PLCresidual[BLOCKL_MAX], PLClpc[LPC_FILTERORDER + 1];
    float zeros[BLOCKL_MAX], one[LPC_FILTERORDER + 1];
    int k, i, start, idxForMax, pos, lastpart, ulp;
    int lag, ilag;
    float cc, maxcc;
    int idxVec[STATE_LEN];
    int check;
    int gain_index[NASUB_MAX*CB_NSTAGES], 
        extra_gain_index[CB_NSTAGES];
    int cb_index[CB_NSTAGES*NASUB_MAX], extra_cb_index[CB_NSTAGES];
    int lsf_i[LSF_NSPLIT*LPC_N_MAX];
    int state_first;


    int last_bit;
    unsigned char *pbytes;
    float weightdenum[(LPC_FILTERORDER + 1)*NSUB_MAX];
    int order_plus_one;
    float syntdenum[NSUB_MAX*(LPC_FILTERORDER+1)]; 
    float decresidual[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<LSF_NSPLIT*LPC_N_MAX; k++) {
            lsf_i[k]=0;
        }
        start=0;
        state_first=0;
        idxForMax=0;
        for (k=0; k<iLBCdec_inst->state_short_len; k++) {
            idxVec[k]=0;
        }
        for (k=0; k<CB_NSTAGES; k++) {
            extra_cb_index[k]=0;
        }
        for (k=0; k<CB_NSTAGES; k++) {
            extra_gain_index[k]=0;
        }
        for (i=0; i<iLBCdec_inst->nasub; i++) {
            for (k=0; k<CB_NSTAGES; k++) {
                cb_index[i*CB_NSTAGES+k]=0;
            }
        }
        for (i=0; i<iLBCdec_inst->nasub; i++) {
            for (k=0; k<CB_NSTAGES; k++) {
                gain_index[i*CB_NSTAGES+k]=0;
            }
        }

        /* loop over ULP classes */

        for (ulp=0; ulp<3; ulp++) {
        
            /* LSF */
            for (k=0; k<LSF_NSPLIT*iLBCdec_inst->lpc_n; k++){
                unpack( &pbytes, &lastpart, 
                    iLBCdec_inst->ULP_inst->lsf_bits[k][ulp], &pos);
                packcombine(&lsf_i[k], lastpart,
                    iLBCdec_inst->ULP_inst->lsf_bits[k][ulp]);
            }



            /* Start block info */

            unpack( &pbytes, &lastpart, 
                iLBCdec_inst->ULP_inst->start_bits[ulp], &pos);
            packcombine(&start, lastpart, 
                iLBCdec_inst->ULP_inst->start_bits[ulp]);

            unpack( &pbytes, &lastpart, 
                iLBCdec_inst->ULP_inst->startfirst_bits[ulp], &pos);
            packcombine(&state_first, lastpart,
                iLBCdec_inst->ULP_inst->startfirst_bits[ulp]);

            unpack( &pbytes, &lastpart, 
                iLBCdec_inst->ULP_inst->scale_bits[ulp], &pos);
            packcombine(&idxForMax, lastpart, 
                iLBCdec_inst->ULP_inst->scale_bits[ulp]);

            for (k=0; k<iLBCdec_inst->state_short_len; k++) {
                unpack( &pbytes, &lastpart, 
                    iLBCdec_inst->ULP_inst->state_bits[ulp], &pos);
                packcombine(idxVec+k, lastpart,
                    iLBCdec_inst->ULP_inst->state_bits[ulp]);
            }

            /* 23/22 (20ms/30ms) sample block */

            for (k=0; k<CB_NSTAGES; k++) {
                unpack( &pbytes, &lastpart, 
                    iLBCdec_inst->ULP_inst->extra_cb_index[k][ulp], 
                    &pos);
                packcombine(extra_cb_index+k, lastpart, 
                    iLBCdec_inst->ULP_inst->extra_cb_index[k][ulp]);
            }
            for (k=0; k<CB_NSTAGES; k++) {
                unpack( &pbytes, &lastpart, 
                    iLBCdec_inst->ULP_inst->extra_cb_gain[k][ulp], 
                    &pos);
                packcombine(extra_gain_index+k, lastpart,
                    iLBCdec_inst->ULP_inst->extra_cb_gain[k][ulp]);
            }
                
            /* The two/four (20ms/30ms) 40 sample sub-blocks */

            for (i=0; i<iLBCdec_inst->nasub; i++) {
                for (k=0; k<CB_NSTAGES; k++) {
                    unpack( &pbytes, &lastpart, 
                    iLBCdec_inst->ULP_inst->cb_index[i][k][ulp], 
                        &pos);
                    packcombine(cb_index+i*CB_NSTAGES+k, lastpart, 
                    iLBCdec_inst->ULP_inst->cb_index[i][k][ulp]);
                }
            }
            
            for (i=0; i<iLBCdec_inst->nasub; i++) {


                for (k=0; k<CB_NSTAGES; k++) {
                    unpack( &pbytes, &lastpart, 

                    iLBCdec_inst->ULP_inst->cb_gain[i][k][ulp], 
                        &pos);
                    packcombine(gain_index+i*CB_NSTAGES+k, lastpart,
                        iLBCdec_inst->ULP_inst->cb_gain[i][k][ulp]);
                }
            }
        }
        /* Extract last bit. If it is 1 this indicates an 
           empty/lost frame */
        unpack( &pbytes, &last_bit, 1, &pos);

        /* Check for bit errors or empty/lost frames */
        if (start<1)
            mode = 0;
        if (iLBCdec_inst->mode==20 && start>3)
            mode = 0;
        if (iLBCdec_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);

            /* decode the lsf */

            SimplelsfDEQ(lsfdeq, lsf_i, iLBCdec_inst->lpc_n);
            check=LSF_check(lsfdeq, LPC_FILTERORDER, 
                iLBCdec_inst->lpc_n);
            DecoderInterpolateLSF(syntdenum, weightdenum, 
                lsfdeq, LPC_FILTERORDER, iLBCdec_inst);
        
            Decode(iLBCdec_inst, decresidual, start, idxForMax, 
                idxVec, syntdenum, cb_index, gain_index, 
                extra_cb_index, extra_gain_index, 
                state_first);

            /* preparing the plc for a future loss! */

            doThePLC(PLCresidual, PLClpc, 0, decresidual, 
                syntdenum + 
                (LPC_FILTERORDER + 1)*(iLBCdec_inst->nsub - 1),
                (*iLBCdec_inst).last_lag, iLBCdec_inst);

        
            memcpy(decresidual, PLCresidual, 
                iLBCdec_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 */

        memset(zeros, 0, BLOCKL_MAX*sizeof(float));
        
        one[0] = 1;
        memset(one+1, 0, LPC_FILTERORDER*sizeof(float));
        
        start=0;
        
        doThePLC(PLCresidual, PLClpc, 1, zeros, one,
            (*iLBCdec_inst).last_lag, iLBCdec_inst);
        memcpy(decresidual, PLCresidual, 
            iLBCdec_inst->blockl*sizeof(float));
        
        order_plus_one = LPC_FILTERORDER + 1;
        for (i = 0; i < iLBCdec_inst->nsub; i++) {
            memcpy(syntdenum+(i*order_plus_one), PLClpc, 
                order_plus_one*sizeof(float));
        }
    }

    if (iLBCdec_inst->use_enhancer == 1) {

        /* post filtering */
        
        iLBCdec_inst->last_lag = 
            enhancerInterface(data, decresidual, iLBCdec_inst);

        /* synthesis filtering */
        
        if (iLBCdec_inst->mode==20) {
            /* Enhancer has 40 samples delay */
            i=0;
            syntFilter(data + i*SUBL, 
                iLBCdec_inst->old_syntdenum + 
                (i+iLBCdec_inst->nsub-1)*(LPC_FILTERORDER+1), 
                SUBL, iLBCdec_inst->syntMem);
            for (i=1; i < iLBCdec_inst->nsub; i++) {
                syntFilter(data + i*SUBL, 
                    syntdenum + (i-1)*(LPC_FILTERORDER+1), 
                    SUBL, iLBCdec_inst->syntMem);
            }
        } else if (iLBCdec_inst->mode==30) {
            /* Enhancer has 80 samples delay */
            for (i=0; i < 2; i++) {
                syntFilter(data + i*SUBL, 


                    iLBCdec_inst->old_syntdenum + 
                    (i+iLBCdec_inst->nsub-2)*(LPC_FILTERORDER+1),
                    SUBL, iLBCdec_inst->syntMem);
            }
            for (i=2; i < iLBCdec_inst->nsub; i++) {
                syntFilter(data + i*SUBL, 
                    syntdenum + (i-2)*(LPC_FILTERORDER+1), SUBL,
                    iLBCdec_inst->syntMem);
            }
        }

    } else {

        /* Find last lag */
        lag = 20;
        maxcc = xCorrCoef(&decresidual[BLOCKL_MAX-ENH_BLOCKL], 
            &decresidual[BLOCKL_MAX-ENH_BLOCKL-lag], ENH_BLOCKL);
        
        for (ilag=21; ilag<120; ilag++) {
            cc = xCorrCoef(&decresidual[BLOCKL_MAX-ENH_BLOCKL], 
                &decresidual[BLOCKL_MAX-ENH_BLOCKL-ilag], 
                ENH_BLOCKL);
        
            if (cc > maxcc) {
                maxcc = cc;
                lag = ilag;
            }
        }
        iLBCdec_inst->last_lag = lag;

        /* copy data and run synthesis filter */

        memcpy(data, decresidual, 
            iLBCdec_inst->blockl*sizeof(float));
        for (i=0; i < iLBCdec_inst->nsub; i++) {
            syntFilter(data + i*SUBL, 
                syntdenum + i*(LPC_FILTERORDER+1), SUBL, 
                iLBCdec_inst->syntMem);
        }
    }

    /* high pass filtering on output if desired, otherwise 
       copy to out */

    hpOutput(data, iLBCdec_inst->blockl, 
                decblock,iLBCdec_inst->hpomem);

    /* memcpy(decblock,data,iLBCdec_inst->blockl*sizeof(float));*/

    memcpy(iLBCdec_inst->old_syntdenum, syntdenum, 

        iLBCdec_inst->nsub*(LPC_FILTERORDER+1)*sizeof(float));

    iLBCdec_inst->prev_enh_pl=0;



    if (mode==0) { /* PLC was used */
        iLBCdec_inst->prev_enh_pl=1;
    }
}


