/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 PacketVideo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */
/****************************************************************************************
Portions of this file are derived from the following 3GPP standard:

    3GPP TS 26.073
    ANSI-C code for the Adaptive Multi-Rate (AMR) speech codec
    Available from http://www.3gpp.org

(C) 2004, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC)
Permission to distribute, modify and use this file under the standard license
terms listed above has been obtained from the copyright holder.
****************************************************************************************/
/*

 Pathname: ./audio/gsm-amr/c/src/gc_pred.c
 Functions:
            gc_pred_reset
            gc_pred
            gc_pred_update
            gc_pred_average_limited

------------------------------------------------------------------------------
 MODULE DESCRIPTION

 This file contains the functions that perform codebook gain MA prediction.

------------------------------------------------------------------------------
*/

/*----------------------------------------------------------------------------
; INCLUDES
----------------------------------------------------------------------------*/
#include "gc_pred.h"
#include "basicop_malloc.h"
#include "basic_op.h"
#include "cnst.h"
#include "log2.h"

/*----------------------------------------------------------------------------
; MACROS
; Define module specific macros here
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; DEFINES
; Include all pre-processor statements here. Include conditional
; compile variables also.
----------------------------------------------------------------------------*/
#define NPRED 4  /* number of prediction taps */

/* average innovation energy.                               */
/* MEAN_ENER  = 36.0/constant, constant = 20*Log10(2)       */
#define MEAN_ENER_MR122  783741L  /* 36/(20*log10(2)) (Q17) */

/* minimum quantized energy: -14 dB */
#define MIN_ENERGY       -14336       /* 14                 Q10 */
#define MIN_ENERGY_MR122  -2381       /* 14 / (20*log10(2)) Q10 */

/*----------------------------------------------------------------------------
; LOCAL FUNCTION DEFINITIONS
; Function Prototype declaration
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; LOCAL VARIABLE DEFINITIONS
; Variable declaration - defined here and used outside this module
----------------------------------------------------------------------------*/

/* MA prediction coefficients (Q13) */
static const Word16 pred[NPRED] = {5571, 4751, 2785, 1556};

/* MA prediction coefficients (Q6)  */
static const Word16 pred_MR122[NPRED] = {44, 37, 22, 12};

/*
------------------------------------------------------------------------------
 FUNCTION NAME: gc_pred_reset
------------------------------------------------------------------------------
 INPUT AND OUTPUT DEFINITIONS

 Inputs:
    state = pointer to a structure of type gc_predState

 Outputs:
    past_qua_en field in the structure pointed to by state is initialized
      to MIN_ENERGY
    past_qua_en_MR122 field in the structure pointed to by state is
      initialized to MIN_ENERGY_MR122

 Returns:
    return_value = 0, if reset was successful; -1, otherwise (int)

 Global Variables Used:
    None

 Local Variables Needed:
    None

------------------------------------------------------------------------------
 FUNCTION DESCRIPTION

 This function initializes the state memory used by gc_pred to zero.

------------------------------------------------------------------------------
 REQUIREMENTS

 None

------------------------------------------------------------------------------
 REFERENCES

 gc_pred.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001

------------------------------------------------------------------------------
 PSEUDO-CODE

int gc_pred_reset (gc_predState *state)
{
   Word16 i;

   if (state == (gc_predState *) NULL){
      fprintf(stderr, "gc_pred_reset: invalid parameter\n");
      return -1;
   }

   for(i = 0; i < NPRED; i++)
   {
      state->past_qua_en[i] = MIN_ENERGY;
      state->past_qua_en_MR122[i] = MIN_ENERGY_MR122;
   }
  return 0;
}

------------------------------------------------------------------------------
 RESOURCES USED [optional]

 When the code is written for a specific target processor the
 the resources used should be documented below.

 HEAP MEMORY USED: x bytes

 STACK MEMORY USED: x bytes

 CLOCK CYCLES: (cycle count equation for this function) + (variable
                used to represent cycle count for each subroutine
                called)
     where: (cycle count variable) = cycle count for [subroutine
                                     name]

------------------------------------------------------------------------------
 CAUTION [optional]
 [State any special notes, constraints or cautions for users of this function]

------------------------------------------------------------------------------
*/

Word16 gc_pred_reset(gc_predState *state)
{
    Word16 i;

    if (state == (gc_predState *) NULL)
    {
        /* fprintf(stderr, "gc_pred_reset: invalid parameter\n"); */
        return -1;
    }

    for (i = 0; i < NPRED; i++)
    {
        state->past_qua_en[i] = MIN_ENERGY;
        state->past_qua_en_MR122[i] = MIN_ENERGY_MR122;
    }

    return(0);
}

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

/*
------------------------------------------------------------------------------
 FUNCTION NAME: gc_pred
------------------------------------------------------------------------------
 INPUT AND OUTPUT DEFINITIONS

 Inputs:
    st = pointer to a structure of type gc_predState
    mode = AMR mode (enum Mode)
    code = pointer to the innovative codebook vector; Q12 in MR122 mode,
           otherwise, Q13 (Word16)
    exp_gcode0 = pointer to the exponent part of predicted gain factor
             (Q0) (Word16)
    frac_gcode0 = pointer to the fractional part of predicted gain factor
              (Q15) (Word16)
    exp_en = pointer to the exponent part of the innovation energy; this
         is calculated for MR795 mode, Q0 (Word16)
    frac_en = pointer to the fractional part of the innovation energy;
          this is calculated for MR795 mode, Q15 (Word16)
    pOverflow = pointer to overflow (Flag)

 Outputs:
    store pointed to by exp_gcode0 contains the exponent part of the
      recently calculated predicted gain factor
    store pointed to by frac_gcode0 contains the fractional part of the
      recently calculated predicted gain factor
    store pointed to by exp_en contains the exponent part of the
      recently calculated innovation energy
    store pointed to by frac_en contains the fractional part of the
      recently calculated innovation energy
    pOverflow = 1 if the math functions called by gc_pred
                results in overflow else zero.

 Returns:
    None

 Global Variables Used:
    None

 Local Variables Needed:
    pred = table of MA prediction coefficients (Q13) (Word16)
    pred_MR122 = table of MA prediction coefficients (Q6) (Word16)

------------------------------------------------------------------------------
 FUNCTION DESCRIPTION

 This function performs the MA prediction of the innovation energy (in
 dB/(20*log10(2))), with the mean removed.

------------------------------------------------------------------------------
 REQUIREMENTS

 None

------------------------------------------------------------------------------
 REFERENCES

 gc_pred.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001

------------------------------------------------------------------------------
 PSEUDO-CODE

The original etsi reference code uses a global flag Overflow. However, in the
actual implementation a pointer to a the overflow flag is passed in.

void
gc_pred(
    gc_predState *st,   // i/o: State struct
    enum Mode mode,     // i  : AMR mode
    Word16 *code,       // i  : innovative codebook vector (L_SUBFR)
                        //      MR122: Q12, other modes: Q13
    Word16 *exp_gcode0, // o  : exponent of predicted gain factor, Q0
    Word16 *frac_gcode0,// o  : fraction of predicted gain factor  Q15
    Word16 *exp_en,     // o  : exponent of innovation energy,     Q0
                        //      (only calculated for MR795)
    Word16 *frac_en     // o  : fraction of innovation energy,     Q15
                        //      (only calculated for MR795)
)
{
    Word16 i;
    Word32 ener_code;
    Word16 exp, frac;

     *-------------------------------------------------------------------*
     *  energy of code:                                                  *
     *  ~~~~~~~~~~~~~~~                                                  *
     *  ener_code = sum(code[i]^2)                                       *
     *-------------------------------------------------------------------*
    ener_code = L_mac((Word32) 0, code[0], code[0]);
                                                 // MR122:  Q12*Q12 -> Q25
                                                 // others: Q13*Q13 -> Q27
    for (i = 1; i < L_SUBFR; i++)
        ener_code = L_mac(ener_code, code[i], code[i]);

    if (sub (mode, MR122) == 0)
    {
        Word32 ener;

        // ener_code = ener_code / lcode; lcode = 40; 1/40 = 26214 Q20
        ener_code = L_mult (pv_round (ener_code), 26214);   // Q9  * Q20 -> Q30

         *-------------------------------------------------------------------*
         *  energy of code:                                                  *
         *  ~~~~~~~~~~~~~~~                                                  *
         *  ener_code(Q17) = 10 * Log10(energy) / constant                   *
         *                 = 1/2 * Log2(energy)                              *
         *                                           constant = 20*Log10(2)  *
         *-------------------------------------------------------------------*
        // ener_code = 1/2 * Log2(ener_code); Note: Log2=log2+30
        Log2(ener_code, &exp, &frac);
        ener_code = L_Comp (sub (exp, 30), frac);     // Q16 for log()
                                                    // ->Q17 for 1/2 log()

         *-------------------------------------------------------------------*
         *  predicted energy:                                                *
         *  ~~~~~~~~~~~~~~~~~                                                *
         *  ener(Q24) = (Emean + sum{pred[i]*past_en[i]})/constant           *
         *            = MEAN_ENER + sum(pred[i]*past_qua_en[i])              *
         *                                           constant = 20*Log10(2)  *
         *-------------------------------------------------------------------*

        ener = MEAN_ENER_MR122;                      // Q24 (Q17)
        for (i = 0; i < NPRED; i++)
        {
            ener = L_mac (ener, st->past_qua_en_MR122[i], pred_MR122[i]);
                                                     // Q10 * Q13 -> Q24
                                                     // Q10 * Q6  -> Q17
        }

         *-------------------------------------------------------------------*
         *  predicted codebook gain                                          *
         *  ~~~~~~~~~~~~~~~~~~~~~~~                                          *
         *  gc0     = Pow10( (ener*constant - ener_code*constant) / 20 )     *
         *          = Pow2(ener-ener_code)                                   *
         *          = Pow2(int(d)+frac(d))                                   *
         *                                                                   *
         *  (store exp and frac for pow2())                                  *
         *-------------------------------------------------------------------*

        ener = L_shr (L_sub (ener, ener_code), 1);                // Q16
        L_Extract(ener, exp_gcode0, frac_gcode0);
    }
    else // all modes except 12.2
    {
        Word32 L_tmp;
        Word16 exp_code, gcode0;

         *-----------------------------------------------------------------*
         *  Compute: means_ener - 10log10(ener_code/ L_sufr)               *
         *-----------------------------------------------------------------*

        exp_code = norm_l (ener_code);
        ener_code = L_shl (ener_code, exp_code);

        // Log2 = log2 + 27
        Log2_norm (ener_code, exp_code, &exp, &frac);

        // fact = 10/log2(10) = 3.01 = 24660 Q13
        L_tmp = Mpy_32_16(exp, frac, -24660); // Q0.Q15 * Q13 -> Q14

         *   L_tmp = means_ener - 10log10(ener_code/L_SUBFR)
         *         = means_ener - 10log10(ener_code) + 10log10(L_SUBFR)
         *         = K - fact * Log2(ener_code)
         *         = K - fact * log2(ener_code) - fact*27
         *
         *   ==> K = means_ener + fact*27 + 10log10(L_SUBFR)
         *
         *   means_ener =       33    =  540672    Q14  (MR475, MR515, MR59)
         *   means_ener =       28.75 =  471040    Q14  (MR67)
         *   means_ener =       30    =  491520    Q14  (MR74)
         *   means_ener =       36    =  589824    Q14  (MR795)
         *   means_ener =       33    =  540672    Q14  (MR102)
         *   10log10(L_SUBFR) = 16.02 =  262481.51 Q14
         *   fact * 27                = 1331640    Q14
         *   -----------------------------------------
         *   (MR475, MR515, MR59)   K = 2134793.51 Q14 ~= 16678 * 64 * 2
         *   (MR67)                 K = 2065161.51 Q14 ~= 32268 * 32 * 2
         *   (MR74)                 K = 2085641.51 Q14 ~= 32588 * 32 * 2
         *   (MR795)                K = 2183945.51 Q14 ~= 17062 * 64 * 2
         *   (MR102)                K = 2134793.51 Q14 ~= 16678 * 64 * 2


        if (sub (mode, MR102) == 0)
        {
            // mean = 33 dB
            L_tmp = L_mac(L_tmp, 16678, 64);     // Q14
        }
        else if (sub (mode, MR795) == 0)
        {
            // ener_code  = <xn xn> * 2^27*2^exp_code
            // frac_en    = ener_code / 2^16
            //            = <xn xn> * 2^11*2^exp_code
            // <xn xn>    = <xn xn>*2^11*2^exp * 2^exp_en
            //           := frac_en            * 2^exp_en

            // ==> exp_en = -11-exp_code;

            *frac_en = extract_h (ener_code);
            *exp_en = sub (-11, exp_code);

            // mean = 36 dB
            L_tmp = L_mac(L_tmp, 17062, 64);     // Q14
        }
        else if (sub (mode, MR74) == 0)
        {
            // mean = 30 dB
            L_tmp = L_mac(L_tmp, 32588, 32);     // Q14
        }
        else if (sub (mode, MR67) == 0)
        {
            // mean = 28.75 dB
            L_tmp = L_mac(L_tmp, 32268, 32);     // Q14
        }
        else // MR59, MR515, MR475
        {
            // mean = 33 dB
            L_tmp = L_mac(L_tmp, 16678, 64);     // Q14
        }

         *-----------------------------------------------------------------*
         * Compute gcode0.                                                 *
         *  = Sum(i=0,3) pred[i]*past_qua_en[i] - ener_code + mean_ener    *
         *-----------------------------------------------------------------*

        L_tmp = L_shl(L_tmp, 10);                // Q24
        for (i = 0; i < 4; i++)
            L_tmp = L_mac(L_tmp, pred[i], st->past_qua_en[i]);
                                                 // Q13 * Q10 -> Q24

        gcode0 = extract_h(L_tmp);               // Q8

         *-----------------------------------------------------------------*
         * gcode0 = pow(10.0, gcode0/20)                                   *
         *        = pow(2, 3.3219*gcode0/20)                               *
         *        = pow(2, 0.166*gcode0)                                   *
         *-----------------------------------------------------------------*

        // 5439 Q15 = 0.165985
        // (correct: 1/(20*log10(2)) 0.166096 = 5443 Q15)
        if (sub (mode, MR74) == 0) // For IS641 bitexactness
            L_tmp = L_mult(gcode0, 5439);  // Q8 * Q15 -> Q24
        else
            L_tmp = L_mult(gcode0, 5443);  // Q8 * Q15 -> Q24

        L_tmp = L_shr(L_tmp, 8);                   //          -> Q16
        L_Extract(L_tmp, exp_gcode0, frac_gcode0); //       -> Q0.Q15
    }
}

------------------------------------------------------------------------------
 RESOURCES USED [optional]

 When the code is written for a specific target processor the
 the resources used should be documented below.

 HEAP MEMORY USED: x bytes

 STACK MEMORY USED: x bytes

 CLOCK CYCLES: (cycle count equation for this function) + (variable
                used to represent cycle count for each subroutine
                called)
     where: (cycle count variable) = cycle count for [subroutine
                                     name]

------------------------------------------------------------------------------
 CAUTION [optional]
 [State any special notes, constraints or cautions for users of this function]

------------------------------------------------------------------------------
*/

void gc_pred(
    gc_predState *st,   /* i/o: State struct                           */
    enum Mode mode,     /* i  : AMR mode                               */
    Word16 *code,       /* i  : innovative codebook vector (L_SUBFR)   */
    /*      MR122: Q12, other modes: Q13           */
    Word16 *exp_gcode0, /* o  : exponent of predicted gain factor, Q0  */
    Word16 *frac_gcode0,/* o  : fraction of predicted gain factor  Q15 */
    Word16 *exp_en,     /* o  : exponent of innovation energy,     Q0  */
    /*      (only calculated for MR795)            */
    Word16 *frac_en,    /* o  : fraction of innovation energy,     Q15 */
    /*      (only calculated for MR795)            */
    Flag   *pOverflow
)
{
    Word16 i;
    Word32 L_temp1, L_temp2;
    Word32 L_tmp;
    Word32 ener_code;
    Word32 ener;
    Word16 exp, frac;
    Word16 exp_code, gcode0;
    Word16 tmp;
    Word16 *p_code = &code[0];

    /*-------------------------------------------------------------------*
     *  energy of code:                                                  *
     *  ~~~~~~~~~~~~~~~                                                  *
     *  ener_code = sum(code[i]^2)                                       *
     *-------------------------------------------------------------------*/
    ener_code = 0;

    /* MR122:  Q12*Q12 -> Q25 */
    /* others: Q13*Q13 -> Q27 */

    for (i = L_SUBFR >> 2; i != 0; i--)
    {
        tmp = *(p_code++);
        ener_code += ((Word32) tmp * tmp) >> 3;
        tmp = *(p_code++);
        ener_code += ((Word32) tmp * tmp) >> 3;
        tmp = *(p_code++);
        ener_code += ((Word32) tmp * tmp) >> 3;
        tmp = *(p_code++);
        ener_code += ((Word32) tmp * tmp) >> 3;
    }

    ener_code <<= 4;

    if (ener_code < 0)      /*  Check for saturation */
    {
        ener_code = MAX_32;
    }

    if (mode == MR122)
    {
        /* ener_code = ener_code / lcode; lcode = 40; 1/40 = 26214 Q20 */
        /* Q9  * Q20 -> Q30 */

        ener_code = ((Word32)(pv_round(ener_code, pOverflow) * 26214)) << 1;

        /*-------------------------------------------------------------*
         *  energy of code:                                            *
         *  ~~~~~~~~~~~~~~~                                            *
         *  ener_code(Q17) = 10 * Log10(energy) / constant             *
         *                 = 1/2 * Log2(energy)                        *
         *  constant = 20*Log10(2)                                     *
         *-------------------------------------------------------------*/
        /* ener_code = 1/2 * Log2(ener_code); Note: Log2=log2+30 */
        Log2(ener_code, &exp, &frac, pOverflow);

        /* Q16 for log()    */
        /* ->Q17 for 1/2 log()*/

        L_temp1 = (Word32)(exp - 30) << 16;
        ener_code = L_temp1 + ((Word32)frac << 1);

        /*-------------------------------------------------------------*
         *  predicted energy:                                          *
         *  ~~~~~~~~~~~~~~~~~                                          *
         *  ener(Q24) = (Emean + sum{pred[i]*past_en[i]})/constant     *
         *            = MEAN_ENER + sum(pred[i]*past_qua_en[i])        *
         *  constant = 20*Log10(2)                                     *
         *-------------------------------------------------------------*/

        ener = MEAN_ENER_MR122;                   /* Q24 (Q17) */
        for (i = 0; i < NPRED; i++)
        {
            L_temp1 = (((Word32) st->past_qua_en_MR122[i]) *
                       pred_MR122[i]) << 1;
            ener = L_add(ener, L_temp1, pOverflow);

            /* Q10 * Q13 -> Q24 */
            /* Q10 * Q6  -> Q17 */
        }

        /*---------------------------------------------------------------*
         *  predicted codebook gain                                      *
         *  ~~~~~~~~~~~~~~~~~~~~~~~                                      *
         *  gc0     = Pow10( (ener*constant - ener_code*constant) / 20 ) *
         *          = Pow2(ener-ener_code)                               *
         *          = Pow2(int(d)+frac(d))                               *
         *                                                               *
         *  (store exp and frac for pow2())                              *
         *---------------------------------------------------------------*/
        /* Q16 */

        L_temp1 = L_sub(ener, ener_code, pOverflow);


        *exp_gcode0 = (Word16)(L_temp1 >> 17);

        L_temp2 = (Word32) * exp_gcode0 << 15;
        L_temp1 >>= 2;

        *frac_gcode0 = (Word16)(L_temp1 - L_temp2);

    }
    else /* all modes except 12.2 */
    {
        /*-----------------------------------------------------------------*
         *  Compute: means_ener - 10log10(ener_code/ L_sufr)               *
         *-----------------------------------------------------------------*/

        exp_code = norm_l(ener_code);
        ener_code = L_shl(ener_code, exp_code, pOverflow);

        /* Log2 = log2 + 27 */
        Log2_norm(ener_code, exp_code, &exp, &frac);

        /* fact = 10/log2(10) = 3.01 = 24660 Q13 */
        /* Q0.Q15 * Q13 -> Q14 */

        L_temp2 = (((Word32) exp) * -24660) << 1;
        L_tmp = (((Word32) frac) * -24660) >> 15;

        /* Sign-extend resulting product */
        if (L_tmp & (Word32) 0x00010000L)
        {
            L_tmp = L_tmp | (Word32) 0xffff0000L;
        }

        L_tmp = L_tmp << 1;
        L_tmp = L_add(L_tmp, L_temp2, pOverflow);


        /*   L_tmp = means_ener - 10log10(ener_code/L_SUBFR)
         *         = means_ener - 10log10(ener_code) + 10log10(L_SUBFR)
         *         = K - fact * Log2(ener_code)
         *         = K - fact * log2(ener_code) - fact*27
         *
         *   ==> K = means_ener + fact*27 + 10log10(L_SUBFR)
         *
         *   means_ener =       33    =  540672    Q14  (MR475, MR515, MR59)
         *   means_ener =       28.75 =  471040    Q14  (MR67)
         *   means_ener =       30    =  491520    Q14  (MR74)
         *   means_ener =       36    =  589824    Q14  (MR795)
         *   means_ener =       33    =  540672    Q14  (MR102)
         *   10log10(L_SUBFR) = 16.02 =  262481.51 Q14
         *   fact * 27                = 1331640    Q14
         *   -----------------------------------------
         *   (MR475, MR515, MR59)   K = 2134793.51 Q14 ~= 16678 * 64 * 2
         *   (MR67)                 K = 2065161.51 Q14 ~= 32268 * 32 * 2
         *   (MR74)                 K = 2085641.51 Q14 ~= 32588 * 32 * 2
         *   (MR795)                K = 2183945.51 Q14 ~= 17062 * 64 * 2
         *   (MR102)                K = 2134793.51 Q14 ~= 16678 * 64 * 2
         */

        if (mode == MR102)
        {
            /* mean = 33 dB */
            L_temp2 = (Word32) 16678 << 7;
            L_tmp = L_add(L_tmp, L_temp2, pOverflow);     /* Q14 */
        }
        else if (mode == MR795)
        {
            /* ener_code  = <xn xn> * 2^27*2^exp_code
               frac_en    = ener_code / 2^16
                          = <xn xn> * 2^11*2^exp_code
               <xn xn>    = <xn xn>*2^11*2^exp * 2^exp_en
            :                 = frac_en            * 2^exp_en
                          ==> exp_en = -11-exp_code;      */
            *frac_en = (Word16)(ener_code >> 16);
            *exp_en = sub(-11, exp_code, pOverflow);

            /* mean = 36 dB */
            L_temp2 = (Word32) 17062 << 7;
            L_tmp = L_add(L_tmp, L_temp2, pOverflow);     /* Q14 */
        }
        else if (mode == MR74)
        {
            /* mean = 30 dB */
            L_temp2 = (Word32) 32588 << 6;
            L_tmp = L_add(L_tmp, L_temp2, pOverflow);     /* Q14 */
        }
        else if (mode == MR67)
        {
            /* mean = 28.75 dB */
            L_temp2 = (Word32) 32268 << 6;
            L_tmp = L_add(L_tmp, L_temp2, pOverflow);     /* Q14 */
        }
        else /* MR59, MR515, MR475 */
        {
            /* mean = 33 dB */
            L_temp2 = (Word32) 16678 << 7;
            L_tmp = L_add(L_tmp, L_temp2, pOverflow);     /* Q14 */
        }

        /*-------------------------------------------------------------*
         * Compute gcode0.                                              *
         *  = Sum(i=0,3) pred[i]*past_qua_en[i] - ener_code + mean_ener *
         *--------------------------------------------------------------*/
        /* Q24 */
        if (L_tmp > (Word32) 0X001fffffL)
        {
            *pOverflow = 1;
            L_tmp = MAX_32;
        }
        else if (L_tmp < (Word32) 0xffe00000L)
        {
            *pOverflow = 1;
            L_tmp = MIN_32;
        }
        else
        {
            L_tmp = L_tmp << 10;
        }

        for (i = 0; i < 4; i++)
        {
            L_temp2 = ((((Word32) pred[i]) * st->past_qua_en[i]) << 1);
            L_tmp = L_add(L_tmp, L_temp2, pOverflow);  /* Q13 * Q10 -> Q24 */
        }

        gcode0 = (Word16)(L_tmp >> 16);               /* Q8  */

        /*-----------------------------------------------------------*
         * gcode0 = pow(10.0, gcode0/20)                             *
         *        = pow(2, 3.3219*gcode0/20)                         *
         *        = pow(2, 0.166*gcode0)                             *
         *-----------------------------------------------------------*/

        /* 5439 Q15 = 0.165985                                       */
        /* (correct: 1/(20*log10(2)) 0.166096 = 5443 Q15)            */

        if (mode == MR74) /* For IS641 bitexactness */
        {
            L_tmp = (((Word32) gcode0) * 5439) << 1;  /* Q8 * Q15 -> Q24 */
        }
        else
        {
            L_tmp = (((Word32) gcode0) * 5443) << 1;  /* Q8 * Q15 -> Q24 */
        }

        if (L_tmp < 0)
        {
            L_tmp = ~((~L_tmp) >> 8);
        }
        else
        {
            L_tmp = L_tmp >> 8;     /* -> Q16 */
        }

        *exp_gcode0 = (Word16)(L_tmp >> 16);
        if (L_tmp < 0)
        {
            L_temp1 = ~((~L_tmp) >> 1);
        }
        else
        {
            L_temp1 = L_tmp >> 1;
        }
        L_temp2 = (Word32) * exp_gcode0 << 15;
        *frac_gcode0 = (Word16)(L_sub(L_temp1, L_temp2, pOverflow));
        /* -> Q0.Q15 */
    }

    return;
}

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

/*
------------------------------------------------------------------------------
 FUNCTION NAME: gc_pred_update
------------------------------------------------------------------------------
 INPUT AND OUTPUT DEFINITIONS

 Inputs:
    st = pointer to a structure of type gc_predState
    qua_ener_MR122 = quantized energy for update (Q10); calculated as
             (log2(qua_err)) (Word16)
    qua_ener = quantized energy for update (Q10); calculated as
           (20*log10(qua_err)) (Word16)

 Outputs:
    structure pointed to by st contains the calculated quantized energy
      for update

 Returns:
    None

 Global Variables Used:
    None

 Local Variables Needed:
    None

------------------------------------------------------------------------------
 FUNCTION DESCRIPTION

 This function updates the MA predictor with the last quantized energy.

------------------------------------------------------------------------------
 REQUIREMENTS

 None

------------------------------------------------------------------------------
 REFERENCES

 gc_pred.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001

------------------------------------------------------------------------------
 PSEUDO-CODE

void gc_pred_update(
    gc_predState *st,      // i/o: State struct
    Word16 qua_ener_MR122, // i  : quantized energy for update, Q10
                           //      (log2(qua_err))
    Word16 qua_ener        // i  : quantized energy for update, Q10
                           //      (20*log10(qua_err))
)
{
    Word16 i;

    for (i = 3; i > 0; i--)
    {
        st->past_qua_en[i] = st->past_qua_en[i - 1];
        st->past_qua_en_MR122[i] = st->past_qua_en_MR122[i - 1];
    }

    st->past_qua_en_MR122[0] = qua_ener_MR122;  //    log2 (qua_err), Q10

    st->past_qua_en[0] = qua_ener;              // 20*log10(qua_err), Q10

}

------------------------------------------------------------------------------
 RESOURCES USED [optional]

 When the code is written for a specific target processor the
 the resources used should be documented below.

 HEAP MEMORY USED: x bytes

 STACK MEMORY USED: x bytes

 CLOCK CYCLES: (cycle count equation for this function) + (variable
                used to represent cycle count for each subroutine
                called)
     where: (cycle count variable) = cycle count for [subroutine
                                     name]

------------------------------------------------------------------------------
 CAUTION [optional]
 [State any special notes, constraints or cautions for users of this function]

------------------------------------------------------------------------------
*/

void gc_pred_update(
    gc_predState *st,      /* i/o: State struct                     */
    Word16 qua_ener_MR122, /* i  : quantized energy for update, Q10 */
    /*      (log2(qua_err))                  */
    Word16 qua_ener        /* i  : quantized energy for update, Q10 */
    /*      (20*log10(qua_err))              */
)
{
    st->past_qua_en[3] = st->past_qua_en[2];
    st->past_qua_en_MR122[3] = st->past_qua_en_MR122[2];

    st->past_qua_en[2] = st->past_qua_en[1];
    st->past_qua_en_MR122[2] = st->past_qua_en_MR122[1];

    st->past_qua_en[1] = st->past_qua_en[0];
    st->past_qua_en_MR122[1] = st->past_qua_en_MR122[0];

    st->past_qua_en_MR122[0] = qua_ener_MR122; /*    log2 (qua_err), Q10 */

    st->past_qua_en[0] = qua_ener;            /* 20*log10(qua_err), Q10 */

    return;
}

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

/*
------------------------------------------------------------------------------
 FUNCTION NAME: gc_pred_average_limited
------------------------------------------------------------------------------
 INPUT AND OUTPUT DEFINITIONS

 Inputs:
    st = pointer to a structure of type gc_predState
    ener_avg_MR122 = pointer to the averaged quantized energy (Q10);
             calculated as (log2(qua_err)) (Word16)
    ener_avg = pointer to the averaged quantized energy (Q10); calculated
           as (20*log10(qua_err)) (Word16)
    pOverflow = pointer to overflow (Flag)

 Outputs:
    store pointed to by ener_avg_MR122 contains the new averaged quantized
      energy
    store pointed to by ener_avg contains the new averaged quantized
      energy
    pOverflow = 1 if the math functions called by gc_pred_average_limited
            results in overflow else zero.

 Returns:
    None

 Global Variables Used:
    None

 Local Variables Needed:
    None

------------------------------------------------------------------------------
 FUNCTION DESCRIPTION

 This function calculates the average of MA predictor state values (with a
 lower limit) used in error concealment.

------------------------------------------------------------------------------
 REQUIREMENTS

 None

------------------------------------------------------------------------------
 REFERENCES

 gc_pred.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001

------------------------------------------------------------------------------
 PSEUDO-CODE

The original etsi reference code uses a global flag Overflow. However, in the
actual implementation a pointer to a the overflow flag is passed in.

void gc_pred_average_limited(
    gc_predState *st,       // i: State struct
    Word16 *ener_avg_MR122, // o: everaged quantized energy,  Q10
                            //    (log2(qua_err))
    Word16 *ener_avg        // o: averaged quantized energy,  Q10
                            //    (20*log10(qua_err))
)
{
    Word16 av_pred_en;
    Word16 i;

    // do average in MR122 mode (log2() domain)
    av_pred_en = 0;
    for (i = 0; i < NPRED; i++)
    {
        av_pred_en = add (av_pred_en, st->past_qua_en_MR122[i]);
    }

    // av_pred_en = 0.25*av_pred_en
    av_pred_en = mult (av_pred_en, 8192);

    // if (av_pred_en < -14/(20Log10(2))) av_pred_en = ..

    if (sub (av_pred_en, MIN_ENERGY_MR122) < 0)
    {
        av_pred_en = MIN_ENERGY_MR122;
    }
    *ener_avg_MR122 = av_pred_en;

    // do average for other modes (20*log10() domain)
    av_pred_en = 0;
    for (i = 0; i < NPRED; i++)
    {
        av_pred_en = add (av_pred_en, st->past_qua_en[i]);
    }

    // av_pred_en = 0.25*av_pred_en
    av_pred_en = mult (av_pred_en, 8192);

    // if (av_pred_en < -14) av_pred_en = ..

    if (sub (av_pred_en, MIN_ENERGY) < 0)
    {
        av_pred_en = MIN_ENERGY;
    }
    *ener_avg = av_pred_en;
}

------------------------------------------------------------------------------
 RESOURCES USED [optional]

 When the code is written for a specific target processor the
 the resources used should be documented below.

 HEAP MEMORY USED: x bytes

 STACK MEMORY USED: x bytes

 CLOCK CYCLES: (cycle count equation for this function) + (variable
                used to represent cycle count for each subroutine
                called)
     where: (cycle count variable) = cycle count for [subroutine
                                     name]

------------------------------------------------------------------------------
 CAUTION [optional]
 [State any special notes, constraints or cautions for users of this function]

------------------------------------------------------------------------------
*/

void gc_pred_average_limited(
    gc_predState *st,       /* i: State struct                    */
    Word16 *ener_avg_MR122, /* o: everaged quantized energy,  Q10 */
    /*    (log2(qua_err))                 */
    Word16 *ener_avg,       /* o: averaged quantized energy,  Q10 */
    /*    (20*log10(qua_err))             */
    Flag *pOverflow
)
{
    Word16 av_pred_en;
    Word16 i;

    /* do average in MR122 mode (log2() domain) */
    av_pred_en = 0;
    for (i = 0; i < NPRED; i++)
    {
        av_pred_en =
            add(av_pred_en, st->past_qua_en_MR122[i], pOverflow);
    }

    /* av_pred_en = 0.25*av_pred_en  (with sign-extension)*/
    if (av_pred_en < 0)
    {
        av_pred_en = (av_pred_en >> 2) | 0xc000;
    }
    else
    {
        av_pred_en >>= 2;
    }

    /* if (av_pred_en < -14/(20Log10(2))) av_pred_en = .. */
    if (av_pred_en < MIN_ENERGY_MR122)
    {
        av_pred_en = MIN_ENERGY_MR122;
    }
    *ener_avg_MR122 = av_pred_en;

    /* do average for other modes (20*log10() domain) */
    av_pred_en = 0;
    for (i = 0; i < NPRED; i++)
    {
        av_pred_en = add(av_pred_en, st->past_qua_en[i], pOverflow);
    }

    /* av_pred_en = 0.25*av_pred_en  (with sign-extension)*/
    if (av_pred_en < 0)
    {
        av_pred_en = (av_pred_en >> 2) | 0xc000;
    }
    else
    {
        av_pred_en >>= 2;
    }

    /* if (av_pred_en < -14) av_pred_en = .. */
    if (av_pred_en < MIN_ENERGY)
    {
        av_pred_en = MIN_ENERGY;
    }
    *ener_avg = av_pred_en;
}
