/*
***********************************************************************
*
* 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.
* 
***********************************************************************
*/

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


/*
**************************************************************************
*
*  Function    : ec_gain_code
*  Purpose     : conceal the codebook gain
*                Call this function only in BFI (instead of normal gain
*                decoding function)
*
**************************************************************************
*/
void ec_gain_code (
    Word16 *gbuf,
    Word16 *past_gain_code,
    Word16 *past_qua_en,    /* i/o : MA predictor state               */
    Word16 state,           /* i   : state of the state machine       */
    Word16 *gain_code       /* o   : decoded innovation gain          */
)
{
    static const Word16 cdown[7] = 
    {32767, 32112, 32112, 32112, 32112, 32112, 22937};

    Word16 tmp, i;
    Word16 qua_ener;
    
    /* calculate median of last five gain values */
    tmp = gmed5 (gbuf);

    /* new gain = minimum(median, past_gain) * cdown[state] */
    if (sub (tmp, *past_gain_code) > 0)
    {
        tmp = *past_gain_code;
    }
    tmp = mult (tmp, cdown[state]);
    *gain_code = tmp;

    /* update table of past quantized energies with
       average of current values */

    /* do averageing (20*log10() domain) */
    qua_ener = 0;
    for (i = 0; i < 4; i++) {
        qua_ener = add(qua_ener, past_qua_en[i]);
    }
    qua_ener = mult (qua_ener, 8192);

    if (sub (qua_ener, -14336) < 0) {
        qua_ener = -14336;
    }

    for (i = 3; i > 0; i--) {
        past_qua_en[i] = past_qua_en[i - 1];
    }
    past_qua_en[0] = qua_ener;              /* 20*log10(qua_err), Q10 */
}

/*
**************************************************************************
*
*  Function    : ec_gain_code_update
*  Purpose     : update the codebook gain concealment state;
*                limit gain_code if the previous frame was bad
*                Call this function always after decoding (or concealing)
*                the gain
*
**************************************************************************
*/
void ec_gain_code_update (
    Word16 *gbuf,
    Word16 *past_gain_code,
    Word16 *prev_gc,
    Word16 bfi,               /* i   : flag: frame is bad               */
    Word16 prev_bf,           /* i   : flag: previous frame was bad     */
    Word16 *gain_code         /* i/o : decoded innovation gain          */
)
{
    Word16 i;
    
    /* limit gain_code by previous good gain if previous frame was bad */
    if (bfi == 0) {
        if (prev_bf != 0) {
            if (sub (*gain_code, *prev_gc) > 0) {
                *gain_code = *prev_gc;
            }
        }
        *prev_gc = *gain_code;
    }

    /* update EC states: previous gain, gain buffer */
    *past_gain_code = *gain_code;
    
    for (i = 1; i < 5; i++) {
        gbuf[i - 1] = gbuf[i];
    }
    gbuf[4] = *gain_code;

    return;
}

/*
**************************************************************************
*
*  Function    : ec_gain_pitch
*  Purpose     : conceal the pitch gain
*                Call this function only in BFI (instead of normal gain
*                decoding function)
*
**************************************************************************
*/
void ec_gain_pitch (
    Word16 *pbuf,
    Word16 *past_gain_pit,
    Word16 state,           /* i   : state of the state machine        */
    Word16 *gain_pitch      /* o   : pitch gain (Q14)                  */
)
{
    static const Word16 pdown[7] =
    {32767, 32112, 32112, 26214, 9830, 6553, 6553};

    Word16 tmp;

    /* calculate median of last five gains */
    tmp = gmed5 (pbuf);

    /* new gain = minimum(median, past_gain) * pdown[state] */
    if (sub (tmp, *past_gain_pit) > 0)
    {
        tmp = *past_gain_pit;
    }
    *gain_pitch = mult (tmp, pdown[state]);
}

/*
**************************************************************************
*
*  Function    : ec_gain_pitch_update
*  Purpose     : update the pitch gain concealment state;
*                limit gain_pitch if the previous frame was bad
*                Call this function always after decoding (or concealing)
*                the gain
*
**************************************************************************
*/
void ec_gain_pitch_update (
    Word16 *pbuf,
    Word16 *past_gain_pit,
    Word16 *prev_gp,
    Word16 bfi,             /* i   : flag: frame is bad                */
    Word16 prev_bf,         /* i   : flag: previous frame was bad      */
    Word16 *gain_pitch      /* i/o : pitch gain                        */
)
{
    Word16 i;

    if (bfi == 0)
    {
        if (prev_bf != 0)
        {
            if (sub (*gain_pitch, *prev_gp) > 0)
            {
                *gain_pitch = *prev_gp;
            }
        }
        *prev_gp = *gain_pitch;
    }
    
    *past_gain_pit = *gain_pitch;

    if (sub (*past_gain_pit, 16384) > 0)  /* if (past_gain_pit > 1.0) */
    {
        *past_gain_pit = 16384;
    }
    for (i = 1; i < 5; i++) {
        pbuf[i - 1] = pbuf[i];
    }
    pbuf[4] = *past_gain_pit;
}
