/*
***********************************************************************
*
* Copyright (C) 1999 Ericsson Radio Systems AB
* 
* The Association of Radio Industries and Businesses (ARIB) has the
* licence to reproduce, distribute and publish the Bit Exact C Code
* programs in this CD-ROM together with the other parts of the RCR
* STD-27 (Personal Digital Cellular Telecommunication System)
* specification.
* 
* Ericsson has declared Option 1 (royalty-free licence) to ARIB for
* its Essential Industrial Property Rights related to the ACELP
* specification and the Bit Exact C Code programs. The royalty-free
* licence is limited to the development and manufacturing of
* products complying with the RCR STD-27H specification (or
* subsequent versions) for sale and use in Japan. Copying of the
* program(s) for any other purpose requires the prior written
* permission from Ericsson.
* 
* The user of the Bit Exact C Code hereby acknowledges the
* following:
* 
* 1.  Ericsson does not provide the user with any warranties,
*     whether express or implied, including but not limited to
*     warranties of merchantability and fitness for a particular
*     purpose relating to the Bit Exact C Code.
* 
* 2.  Ericsson shall have no responsibility whatsoever to indemnify
*     the user against actions or claims for infringement of any
*     intellectual property rights, e.g. patents, copyrights,
*     registered designs or any other rights, by reason of the
*     user's use of the Bit Exact C Code.
* 
***********************************************************************
*/

/***************************************************************************
 *
 *  FILE NAME:    dec_6k7.c
 *
 *  FUNCTIONS DEFINED IN THIS FILE:
 *                   Init_Decoder_6k7   and  Decoder_6k7
 *
 *
 *  Init_Decoder_6k7():
 *      Initialization of variables for the decoder section.
 *
 *  Decoder_6k7():
 *      Principle decoder routine operating on a frame basis.
 *
 ***************************************************************************/


#include <stdio.h>
#include "typedef.h"
#include "basic_op.h"
#include "sig_proc.h"
#include "codec.h"
#include "cnst.h"

/*---------------------------------------------------------------*
 *   Decoder constant parameters (defined in "cnst.h")           *
 *---------------------------------------------------------------*
 *   L_FRAME     : Frame size.                                   *
 *   L_FRAME_BY2 : Half the frame size.                          *
 *   L_SUBFR     : Sub-frame size.                               *
 *   M           : LPC order.                                    *
 *   MP1         : LPC order+1                                   *
 *   PIT_MIN     : Minimum pitch lag.                            *
 *   PIT_MAX     : Maximum pitch lag.                            *
 *   L_INTERPOL  : Length of filter for interpolation            *
 *   PRM_SIZE    : size of vector containing analysis parameters *
 *---------------------------------------------------------------*/

/*--------------------------------------------------------*
 *         Static memory allocation.                      *
 *--------------------------------------------------------*/

 /* Excitation vector */

static Word16 old_exc[L_SUBFR + PIT_MAX + L_INTERPOL];
static Word16 *exc;
Word16 exc_enhanced[L_SUBFR];

 /* Lsp (Line spectral pairs) */

static Word16 lsp_old[M] = {30000, 26000, 21000, 15000, 8000,
                            0, -8000, -15000, -21000, -26000};

static Word16 lsp_meanSave[M] = {1384, 2077,  3420,  5108,  6742,
                                 8122, 9863, 11092, 12714, 13701};

static Word16 past_lsf_q[M] = {1384, 2077,  3420,  5108,  6742,
                               8122, 9863, 11092, 12714, 13701};

 /* Filter's memory */

static Word16 mem_syn[M];

static Word16 sharp, old_T0;

static Word16 state = 0;

static Word16 past_qua_en[4] = {-14336, -14336, -14336, -14336};
/* old gc_predState */

/***************************************************************************
 *
 *   FUNCTION:  Init_Decoder_6k7
 *
 *   PURPOSE: Initialization of variables for the decoder section.
 *
 ***************************************************************************/

void Init_Decoder_6k7(void)
{
    /* Initialize static pointer */

    exc = old_exc + PIT_MAX + L_INTERPOL;

    /* Static vectors to zero */

    Set_zero(old_exc, PIT_MAX + L_INTERPOL);
    Set_zero(mem_syn, M);

    sharp = SHARPMIN;
    old_T0 = 60;

    return;
}

/***************************************************************************
 *
 *   FUNCTION:  Decoder_6k7
 *
 *   PURPOSE:   Principle decoder routine.
 *
 ***************************************************************************/

void Decoder_6k7(
    Word16 parm[],   /* input : vector of synthesis parameters    */
    Word16 bfi,      /* bfi flag                                  */   
    Word16 synth[],  /* output: synthesis speech                  */
    Word16 A_t[]     /* output: decoded LP filter in 4 subframes  */
)
{

    /* LPC coefficients */

    Word16 *Az;                /* Pointer on A_t */

    /* LSPs */

    Word16 lsp_new[M];

    /* LSFs */
    
    Word16 prev_lsf[M];
    Word16 lsf_i[M];    
 
    /* Algebraic codevector */

    Word16 code[L_SUBFR];

    /* excitation */

    Word16 excp[L_SUBFR];

    /* Scalars */

    Word16 i, i_subfr;
    Word16 T0, T0_frac, index;
    Word16 gain_pit, gain_code, pit_flag;
    Word16 pppc;
    Word16 temp;
    Word32 L_temp;
    Word16 gain_code_mix;
    extern Flag Overflow;

    /* For error concealment */

    static Word16 prev_bf=0;   /* previous bfi flag */
    static Word16 gbuf[5] = {1, 1, 1, 1, 1};
    static Word16 past_gain_code = 0;
    static Word16 prev_gc = 1;
    static Word16 pbuf[5] = {1640, 1640, 1640, 1640, 1640};
    static Word16 past_gain_pit = 0;
    static Word16 prev_gp = 16384;

    /* set state machine */

    if (bfi != 0)
        state = add(state, 1);
    else {
        if (sub(state, 6) == 0) {
            state = 5;
        } else {
            state = 0;
        }
    }
    if (sub(state, 6) > 0) {
        state = 6;
    }

   /* save old LSFs for CB gain smoothing */
    Copy (past_lsf_q, prev_lsf, M);
    
    D_plsf_3(past_lsf_q, parm, lsp_new, bfi);
    parm += 3;        /* Advance synthesis parameters pointer */

    /* Interpolation of LPC for the 4 subframes */

    Int_lpc(lsp_old, lsp_new, A_t);

    /* update the LSFs for the next frame */

    for (i = 0; i < M; i++) {
        lsp_old[i] = lsp_new[i];
    }

/*------------------------------------------------------------------------*
 *          Loop for every subframe in the analysis frame                 *
 *------------------------------------------------------------------------*
 * The subframe size is L_SUBFR and the loop is repeated L_FRAME/L_SUBFR  *
 *  times                                                                 *
 *     - decode the pitch delay                                           *
 *     - decode algebraic code                                            *
 *     - decode pitch and codebook gains                                  *
 *     - find the excitation and compute synthesis speech                 *
 *------------------------------------------------------------------------*/

    Az = A_t;     /* pointer to interpolated LPC parameters */

    for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR) {
        pit_flag = i_subfr;  /* flag for first and 3th subframe */
        if (sub(i_subfr, L_FRAME_BY2) == 0) {
            pit_flag = 0;
        }
        index = *parm++;        /* pitch index */

        if (bfi == 0) {
            Dec_lag3(index, PIT_MIN, PIT_MAX, pit_flag, &T0, &T0_frac);
        } else {
            if (sub(old_T0, PIT_MAX) < 0)
                old_T0 = add(old_T0, 1);
            T0 = old_T0;
            T0_frac = 0;
        }


   /*-------------------------------------------------*
    * - Find the adaptive codebook vector.            *
    *-------------------------------------------------*/

        Pred_lt_3(exc, T0, T0_frac, L_SUBFR);

   /*-------------------------------------------------------*
    * - Decode innovative codebook.                         *
    * - Add the fixed-gain pitch contribution to code[].    *
    *-------------------------------------------------------*/

        index = *parm++;        /* index of position */
        i = *parm++;            /* signs             */
 
        Decod_ACELP(i, index, code);

   /*-------------------------------------------------------*
    * - Add the gain pitch contribution to code[].          *
    *-------------------------------------------------------*/

        for (i = T0; i < L_SUBFR; i++) {
            temp = mult(code[i - T0], shl(sharp, 1));
            code[i] = add(code[i], temp);
        }


   /*-------------------------------------------------*
    * - Decode pitch and codebook gain.               *
    *-------------------------------------------------*/

        index = *parm++;        /* index of gains */

        if (bfi == 0)
        {
           Dec_gain(index, code, L_SUBFR, past_qua_en, &gain_pit, 
                    &gain_code);

        }
        else
        {
           ec_gain_pitch (pbuf, &past_gain_pit, state, &gain_pit);

           ec_gain_code (gbuf, &past_gain_code, past_qua_en, state,
                         &gain_code);
        }


            ec_gain_pitch_update(pbuf, &past_gain_pit, &prev_gp,
                                bfi, prev_bf, &gain_pit);

            ec_gain_code_update(gbuf, &past_gain_code, &prev_gc,
                                bfi, prev_bf, &gain_code);

   /*------------------------------------------------------------*
    * - Update pitch sharpening "sharp" with quantized gain_pit  *
    *------------------------------------------------------------*/
        sharp = gain_pit;
        if (sub(sharp, SHARPMAX) > 0) {
            sharp = SHARPMAX;
        }
        pppc = shl(sharp, 1);
        if (sub(pppc, 16384) > 0) {
            for (i = 0; i < L_SUBFR; i++) {
                temp = mult(exc[i], pppc);
                L_temp = L_mult(temp, gain_pit);
                excp[i] = round(L_temp);
            }
        }

        /*-------------------------------------------------------*
         *  Calculate CB mixed gain                              *
         *-------------------------------------------------------*/
        Int_lsf(prev_lsf, past_lsf_q, i_subfr, lsf_i); 
        gain_code_mix = Cb_gain_average(gain_code, lsf_i, lsp_meanSave);

   /*-------------------------------------------------------*
    * - Find the total excitation.                          *
    * - copy unscaled LTP excitation to exc_enhanced        *
    * - (used in phase dispersion below)                    *
    * - compute total excitation for LTP feedback           *
    *-------------------------------------------------------*/

        /* copy unscaled LTP excitation to exc_enhanced (used in phase
         * dispersion below) and compute total excitation for LTP feedback
         */
        for (i = 0; i < L_SUBFR; i++) {
           
           exc_enhanced[i] = exc[i];

           /* exc[i] = gain_pit*exc[i] + gain_code*code[i]; */
           L_temp = L_mult (exc[i], gain_pit);
           L_temp = L_mac (L_temp, code[i], gain_code);
           L_temp = L_shl (L_temp, 1);                   /* Q16 */
           exc[i] = round (L_temp);
        }
        
   /*-------------------------------------------------------*
    * - Add adaptive phase dispersion to innovation         *
    *-------------------------------------------------------*/
        ph_disp(exc_enhanced, gain_code_mix, gain_pit, code,
                gain_pit, 1);       

   /*-----------------------------------------------------------*
    * - Find synthesis speech corresponding to exc_enhanced[].  *
    *-----------------------------------------------------------*/

        if (sub(pppc, 16384) > 0) {
            for (i = 0; i < L_SUBFR; i++) {
                excp[i] = add(excp[i], exc_enhanced[i]);
            }
            agc2(exc_enhanced, excp, L_SUBFR);
            Overflow = 0;
            Syn_filt(Az, excp, &synth[i_subfr], L_SUBFR, mem_syn, 0);
        } else {
            Overflow = 0;
            Syn_filt(Az, exc_enhanced, &synth[i_subfr], L_SUBFR, mem_syn, 0);
        }
        if (Overflow != 0) {
	    for (i = 0; i < PIT_MAX+L_INTERPOL+L_SUBFR; i++) {
                old_exc[i] = shr(old_exc[i], 2);
	    }
            for (i = 0; i < L_SUBFR; i++) {
                exc_enhanced[i] = shr(exc_enhanced[i], 2);       
	    }
            Syn_filt(Az, exc_enhanced, &synth[i_subfr], L_SUBFR, mem_syn, 1);
        } else
        {
            Copy(&synth[i_subfr+L_SUBFR-M], mem_syn, M);
        }

        Az += MP1;    /* interpolated LPC parameters for next subframe */

   /*--------------------------------------------------*
    * Update signal for next frame.                    *
    * -> shift to the left by L_FRAME  exc[]           *
    *--------------------------------------------------*/

        Copy(&old_exc[L_SUBFR], &old_exc[0], PIT_MAX + L_INTERPOL);

    }

    old_T0 = T0;

    /* store bfi for next subframe */
    prev_bf = bfi;

    /*--------------------------------------------------*
     * Calculate the LSF averages on the eight          *
     * previous frames                                  *
     *--------------------------------------------------*/

    lsp_avg(lsp_meanSave, past_lsf_q);

    return;
}
