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

/*************************************************************************
 *
 * FUNCTION:  Qua_gain()
 *
 * PURPOSE: Quantization of pitch and codebook gains.
 * MA prediction is performed on the innovation energy (in dB with mean
 * removed).
 *
 *************************************************************************/

#include "typedef.h"
#include "basic_op.h"
#include "oper_32b.h"
#include "sig_proc.h"
#include "cnst.h"

#include "qua_gain.tab"
static Word16 past_qua_en[4] =
    {-14336, -14336, -14336, -14336};

void reset_gainq_mem(Word16 x) /* Set all four old MA residuals to x */
{
   past_qua_en[0] = x;
   past_qua_en[1] = x;
   past_qua_en[2] = x;
   past_qua_en[3] = x;
   
}

Word16
Qua_gain(              /*  Return index of quantization.      */
    Word16 xn[],        /* (i)   :Target vector.               */
    Word16 y1[],        /* (i)   :Adaptive codebook.           */
    Word16 Y2[],        /* (i)   :Filtered innovative vector.  */
    Word16 code[],      /* (i)   :Innovative vector.           */
    Word16 g_coeff[],   /* (i)   :Correlations <xn y1> <y1 y1> */
                        /*        Compute in G_pitch().        */
    Word16 L_subfr,     /* (i)   :Subframe lenght.             */
    Word16 * gain_pit,  /* (o)   :Pitch gain.                  */
    Word16 * gain_cod,  /* (o)   :Code gain.                   */
    Word16 GpC_flag     /* (i)   : Gp Clipping flag            */
)
{
    Word16 i, j, index, *p;
    Word16 exp, frac, gcode0, exp_gcode0, e_max, exp_code, qua_ener;
    Word16 g_pitch, g2_pitch, g_code, g2_code, g_pit_cod;
    Word16 coeff[5], coeff_lo[5], exp_coeff[5];
    Word16 exp_max[5];
    Word32 L_tmp, s, dist_min;
    Word16 y2[L_SUBFR];

    /* Past quantized energies  */

    static Word16 pred[4] =
    {5571, 4751, 2785, 1556};

    for (i = 0; i < L_subfr; i++) {
        y2[i] = shr(Y2[i], 3);
    }

 /*------------------------------------------------------------------*
  *                                                                  *
  *  Compute coefficient need for the quantization.                  *
  *                                                                  *
  *  coeff[0] =    y1 y1                                             *
  *  coeff[1] = -2 xn y1                                             *
  *  coeff[2] =    y2 y2                                             *
  *  coeff[3] = -2 xn y2                                             *
  *  coeff[4] =  2 y1 y2                                             *
  *                                                                  *
  * Product <y1 y1> and <xn y1> have been compute in G_pitch() and   *
  * are in vector g_coeff[].                                         *
  *                                                                  *
  *------------------------------------------------------------------*/

    coeff[0] = g_coeff[0];
    exp_coeff[0] = g_coeff[1];
    coeff[1] = negate(g_coeff[2]);  /* coeff[1] = -2 xn y1 */
    exp_coeff[1] = add(g_coeff[3], 1);


    /* Compute scalar product <y2[],y2[]> */

    s = L_mac((Word32) 1, y2[0], y2[0]);
    for (i = 1; i < L_subfr; i++)
        s = L_mac(s, y2[i], y2[i]);

    exp = norm_l(s);
    coeff[2] = extract_h(L_shl(s, exp));
    exp_coeff[2] = sub(15 - 18, exp);

    /* Compute scalar product -2*<xn[],y2[]> */

    s = L_mac((Word32) 1, xn[0], y2[0]);
    for (i = 1; i < L_subfr; i++)
        s = L_mac(s, xn[i], y2[i]);

    exp = norm_l(s);
    coeff[3] = negate(extract_h(L_shl(s, exp)));
    exp_coeff[3] = sub(15 - 9 + 1, exp);


    /* Compute scalar product 2*<y1[],y2[]> */

    s = L_mac((Word32) 1, y1[0], y2[0]);
    for (i = 1; i < L_subfr; i++)
        s = L_mac(s, y1[i], y2[i]);

    exp = norm_l(s);
    coeff[4] = extract_h(L_shl(s, exp));
    exp_coeff[4] = sub(15 - 9 + 1, exp);


  /*-------------------------------*
   * Energy coming from code       *
   *-------------------------------*/

    L_tmp = L_mac((Word32) 0, code[0], code[0]);
    for (i = 1; i < L_subfr; i++)
        L_tmp = L_mac(L_tmp, code[i], code[i]);

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

    Log2(L_tmp, &exp, &frac);
    L_tmp = Mpy_32_16(exp, frac, -24660);

    L_tmp = L_mac(L_tmp, 32268, 32);  /* 28.75dB */

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

    L_tmp = L_shl(L_tmp, 10);
    for (i = 0; i < 4; i++)
        L_tmp = L_mac(L_tmp, pred[i], past_qua_en[i]);

    gcode0 = extract_h(L_tmp);

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

    L_tmp = L_mult(gcode0, 5443);
    L_tmp = L_shr(L_tmp, 8);
    L_Extract(L_tmp, &exp_gcode0, &frac);

    gcode0 = extract_l(Pow2(14, frac));

/*---------------------------------------------------------------------------*
 *                                                                           *
 * Find the best quantizer.                                                  *
 *                                                                           *
 *---------------------------------------------------------------------------*/

    exp_code = sub(exp_gcode0, 11);

    exp_max[0] = sub(exp_coeff[0], 13);
    exp_max[1] = sub(exp_coeff[1], 14);
    exp_max[2] = add(exp_coeff[2], add(15, shl(exp_code, 1)));
    exp_max[3] = add(exp_coeff[3], exp_code);
    exp_max[4] = add(exp_coeff[4], add(1, exp_code));


    /* Find maximum exponent */

    e_max = exp_max[0];
    for (i = 1; i < 5; i++) {   /* implemented flattened */
        if (sub(exp_max[i], e_max) > 0) {
            e_max = exp_max[i];
        }
    }

    e_max = add(e_max, 1);      /* To avoid overflow */

    for (i = 0; i < 5; i++) {
        j = sub(e_max, exp_max[i]);
        L_tmp = L_deposit_h(coeff[i]);
        L_tmp = L_shr(L_tmp, j);
        L_Extract(L_tmp, &coeff[i], &coeff_lo[i]);
    }

    /* Codebook search */

    dist_min = MAX_32;

    p = &table_gain[0];

    if(GpC_flag == 0)
        j = 128;
    else
        j = 96;

    for (i = 0; i < j; i++) {
        g_pitch = *p++;
        g_code = *p++;
        p++;           /* Past 20*log10(g_code) */

        g_code = mult(g_code, gcode0);
        g2_pitch = mult(g_pitch, g_pitch);
        g2_code = mult(g_code, g_code);
        g_pit_cod = mult(g_code, g_pitch);

        L_tmp = Mpy_32_16(coeff[0], coeff_lo[0], g2_pitch);
        L_tmp = L_add(L_tmp, Mpy_32_16(coeff[1], coeff_lo[1], g_pitch));
        L_tmp = L_add(L_tmp, Mpy_32_16(coeff[2], coeff_lo[2], g2_code));
        L_tmp = L_add(L_tmp, Mpy_32_16(coeff[3], coeff_lo[3], g_code));
        L_tmp = L_add(L_tmp, Mpy_32_16(coeff[4], coeff_lo[4], g_pit_cod));

        if (L_sub(L_tmp, dist_min) < (Word32) 0) {
            dist_min = L_tmp;
            index = i;
        }
    }

    /* Read the quantized gains */

    p = &table_gain[add(index, add(index, index))];
    *gain_pit = *p++;
    g_code = *p++;
    qua_ener = *p;

    L_tmp = L_mult(g_code, gcode0);
    L_tmp = L_shr(L_tmp, sub(10, exp_gcode0));
    *gain_cod = extract_h(L_tmp);

    /* update table of past quantized energies */

    for (i = 3; i > 0; i--)
        past_qua_en[i] = past_qua_en[i - 1];
    past_qua_en[0] = qua_ener;

    return index;
}
