/*====================================================================================
    EVS Codec 3GPP TS26.443 Nov 13, 2018. Version 12.11.0 / 13.7.0 / 14.3.0 / 15.1.0
  ====================================================================================*/

#include <math.h>
#include "options.h"
#include "prot.h"
#include "rom_com.h"
#include "basop_util.h"
#include "basop_mpy.h"
#include "stl.h"

namespace evs { 



/*-------------------------------------------------------------------
 * Local constants
 *-------------------------------------------------------------------*/

#define MIN_BITS_FIX 0
#define HQ_16k40_BIT  (HQ_16k40/50) /* 16400/50=328 , FOR FIX TMP */
#define C1_QRk        (1<<SWB_BWE_LR_QRk) /* 1 */
#define Qbf           14
#define C1_Qbf        (1<<Qbf)            /* 1 */
#define BITS_FACT_1p10 (Word16)(1.10f*(float)pow(2, Qbf)+0.5f)
#define BITS_FACT_1p05 (Word16)(1.05f*(float)pow(2, Qbf)+0.5f)
#define BITS_FACT_1p00 (Word16)(1.00f*(float)pow(2, Qbf)+0.5f)
#define BITS_FACT_0p97 (Word16)(0.97f*(float)pow(2, Qbf)+0.5f)
#define BITS_FACT_0p92 (Word16)(0.92f*(float)pow(2, Qbf)+0.5f)

#define L_Comp(hi, lo) L_mac(L_deposit_h (hi), lo, 1)

/*-------------------------------------------------------------------
 * div_s_ss()
 *
 *
 *-------------------------------------------------------------------*/

static Word16 div_s_ss(     /* o: result of division (Word16 Q0) */
    const Word16 n,         /* i: numerator   (Word16 Q0         */
    const Word16 d          /* i: denominator (Word16 Q0)        */
)
{
    Word16 norm_n, norm_d;
    Word16 ns, ds;
    Word16 res;

    test();
    IF ( n == 0 || d == 0 )
    {
        return 0;
    }

    norm_n = norm_s(n);
    norm_n = sub(norm_n, 1);
    ns = shl(n, norm_n);

    norm_d = norm_s(d);
    ds = shl(d, norm_d);

    res = shr(div_s(ns, ds), add(sub(norm_n, norm_d), 15));

    return res;
}


/*-------------------------------------------------------------------*
 * Bits2indvsb()
 *
 * Bit allocation to individual SB's in a group
 *-------------------------------------------------------------------*/
static
void Bits2indvsb_fx (
    const Word32 *L_be,                 /* i  : Qbe Band Energy of sub-band                       */
    const Word16 start_band,            /* i  : Q0  start band indices                            */
    const Word16 end_band,              /* i  : Q0  end band indices                              */
    const Word16 Bits,                  /* i  : Q0  Total number of bits allocated to a group     */
    const Word32 L_Bits_needed,         /* i  : QRk smallest bit number for allocation in group   */
    Word32 *L_Rsubband,           /* o  : QRk bit allocation of sub-band                    */
    Word16 *p2aflags_fx           /* i/o: Q0  peaky/noise subband flag                      */
)
{
    Word16 i,j,k;
    Word32 L_R_temp[14]; /* QRk = QL_Rsubband; */
    Word16 Ravg_fx;
    Word16 QRavg;

    const Word32 *L_y_ptr;
    Word32 *L_R_ptr;

    Word16 Bits_avg_fx;
    Word16 QBavg;
    Word16 scale_fact_fx;

    Word16 band_num_fx;
    Word16 index_fx[14];

    Word16 y_index_fx[14];

    Word16 be_sum_fx; /* Q0 */

    Word16 exp_normn, exp_normd;
    Word16 enr_diffcnt_fx;
    Word16 th_5_fx;
    Word16 Rcnt_fx;

    Word16 be_cnt_fx;
    Word16 *p2aflags_fx_ptr;

    Word32 L_temp1;
    Word32 L_temp2;

    band_num_fx = sub(end_band, start_band);
    L_y_ptr = L_be + start_band;
    L_R_ptr = L_Rsubband + start_band;
    p2aflags_fx_ptr = p2aflags_fx+start_band;

    FOR ( i = 0; i < band_num_fx; i++ )
    {
        y_index_fx[i] = extract_h(L_shr(L_y_ptr[i], sub(SWB_BWE_LR_Qbe,16)));
        move16();
        index_fx[i] = i;
        move16();
    }


    /* Rearrange norm vector in decreasing order */
    reordvct(y_index_fx, band_num_fx, index_fx);

    be_sum_fx = 0;
    move16();
    be_cnt_fx = 0;
    move16();
    FOR( j=0; j<band_num_fx; j++ )
    {
        test();
        IF ( y_index_fx[j] <= 0 || p2aflags_fx_ptr[index_fx[j]] == 0 )
        {
            y_index_fx[j] = 0;
            move16();
            L_R_temp[j] = 0x0L;
            move32();
        }
        ELSE
        {
            L_R_temp[j] = C1_QRk;
            move32(); /* filled not zero value */
            be_cnt_fx = add(be_cnt_fx, 1);
        }

    }

    i = sub(be_cnt_fx, 1);
    FOR(k = 0; k <=i ; k++)
    {
        test();
        if( L_R_temp[k] > 0 )
        {
            be_sum_fx = add(be_sum_fx, y_index_fx[k]);
        }
    }
    QBavg = 0;
    move16();

    /*Ravg = (float) be_sum/be_cnt;*/
    Ravg_fx = 0;
    move16();
    QRavg = 0;
    move16();
    IF( be_cnt_fx != 0x0 )
    {
        exp_normn = norm_s(be_sum_fx);
        exp_normn = sub(exp_normn, 1);
        exp_normd = norm_s(be_cnt_fx);
        Ravg_fx = div_s(shl(be_sum_fx, exp_normn), shl(be_cnt_fx, exp_normd));

        Ravg_fx = shr(Ravg_fx, 2); /* safe shift */
        QRavg = add(sub(exp_normn, exp_normd), 15-2);
    }

    enr_diffcnt_fx = 0;
    move16();
    th_5_fx = shl(5, QRavg);
    FOR (j = 0; j < be_cnt_fx; j++)
    {
        IF( sub(abs_s(sub(Ravg_fx, shl(y_index_fx[j], QRavg))), th_5_fx) > 0 )
        {
            enr_diffcnt_fx = add(enr_diffcnt_fx, 1);
        }
    }

    IF( enr_diffcnt_fx > 0 )
    {
        scale_fact_fx = 11468;
        move16(); /* 0.35f 11468.8(Q15) */
    }
    ELSE
    {
        scale_fact_fx = 19661;
        move16(); /* 0.60f 19660.8(Q15) */
    }

    /* Bits allocation to individual SB's in a group based on Band Energies */
    FOR (j = 0; j < be_cnt_fx; j++)
    {
        Rcnt_fx = add(i, 1);

        /* Ravg = (float) be_sum/Rcnt; */
        exp_normn = norm_s(be_sum_fx);
        exp_normn = sub(exp_normn, 1);
        exp_normd = norm_s(Rcnt_fx);
        Ravg_fx = div_s(shl(be_sum_fx, exp_normn), shl(Rcnt_fx, exp_normd));
        Ravg_fx = shr(Ravg_fx, 2); /* safe shift */
        QRavg = add(sub(exp_normn, exp_normd), 15-2);

        test();
        if(be_sum_fx <= 0)
        {
            be_sum_fx = 1;
            move16();
        }

        /* Bits_avg = (float) Bits/(be_sum+EPSILON); */
        Bits_avg_fx = 0;
        move16();
        QBavg = 0;
        move16();
        IF ( Bits != 0 )
        {
            exp_normn = norm_s(Bits);
            exp_normn = sub(exp_normn, 1);
            exp_normd = norm_s(be_sum_fx);
            Bits_avg_fx = div_s(shl(Bits, exp_normn), shl(be_sum_fx, exp_normd));
            Bits_avg_fx = shr(Bits_avg_fx, 2); /* safe_shift */
            QBavg = add(sub(exp_normn, exp_normd), 15-2);
        }
        FOR (k = 0; k <=i; k++)
        {
            IF(L_R_temp[k] > 0) /* Rtemp -> SWB_BWE_LR_QRk */
            {
                /* Allocate more bits to SB, if SB bandenergy is higher than average energy */
                /* R_temp[k] = (float)( Bits_avg * y_index[k]+( scale_fact * (y_index[k] - Ravg))); */
                L_temp1 = L_mult(Bits_avg_fx, y_index_fx[k]);                              /* QBavg+1 */
                L_temp2 = L_mult(scale_fact_fx, sub(shl(y_index_fx[k], QRavg), Ravg_fx));  /* 15+QRavg+1 */
                L_R_temp[k] = L_add(L_shr(L_temp1, sub(add(QBavg, 1), SWB_BWE_LR_QRk)), L_shr(L_temp2, sub(add(QRavg, 16), SWB_BWE_LR_QRk))); /* SWB_BWE_LR_QRk */
            }
        }
        IF (  L_sub(L_R_temp[i], L_Bits_needed) < 0 )
        {
            L_R_temp[i] = 0x0L;
            move32();

            p2aflags_fx_ptr[index_fx[i]] = 0;
            move16();

            /* be_sum -= y_index[i]; */
            be_sum_fx = sub(be_sum_fx, y_index_fx[i]);

            i = sub(i, 1);
        }
        ELSE
        {
            BREAK;
        }
    }

    /* Rearrange the bit allocation to align with original */
    FOR ( k = 0 ; k < band_num_fx; k++ )
    {
        j = index_fx[k];
        move16();
        L_R_ptr[j] = L_R_temp[k];
        move32();
    }

    return;
}

/*-------------------------------------------------------------------*
 * hq2_bit_alloc_har()
 *
 * Bit allocation mechanism for HQ_HARMONIC mode
 *-------------------------------------------------------------------*/

void hq2_bit_alloc_har (
    float *y,                          /* i  : band energy of sub-vectors                    */
    int   B_fx,                        /* i  : number of available bits                      */
    short N_fx,                        /* i  : number of sub-vectors                         */
    Word32 *L_Rsubband,
    short p2a_bands_fx,
    long  L_core_brate,                 /* i  : core bit rate                                 */
    short p2a_flags_fx[],
    short band_width_fx[]
)
{
    Word16 i, j, k;

    Word32 L_norm_sum;                     /* Qbe */
    Word32 L_Ravg_sub[GRP_SB];             /* Qbe */
    Word32 L_temp_band_energy[BANDS_MAX];  /* Qbe */

    Word16 j_fx, k_fx, Bits_grp_fx[GRP_SB];

    Word32 L_temp_band_energydiff[BANDS_MAX];
    Word16 G1_BE_DIFF_POS_fx; /* Q0 */
    Word32 L_G1_BE_DIFF_VAL;  /* Qbe  Word32 */
    Word16 final_gr_fact_pos_fx, gmax_range_fx[2], temp_fx;
    Word16 bits_fact_fx, bits_fact1_fx;   /* Q? */
    Word16 grp_rngmax_fx[2] = {0};
    Word16 index_fx[NB_SWB_SUBBANDS_HAR], y_index_fx[NB_SWB_SUBBANDS_HAR], esthf_bits_fx, grp_bit_avg_fx, harmonic_band_fx;
    Word32 L_norm_sum_avg;
    Word32 L_norm_diff; /* Qbe */
    Word16 bits_allocweigh_fx; /* Q15 */
    Word16 grp_bound_fx[5];
    Word32 L_grp_thr[GRP_SB]; /* not require Word32 precission */
    Word16 lf_hf_ge_r_fx; /* Q15 */
    Word32 L_avg_enhf_en_diff; /* Qbe */

    Word16 B_norm_fx;

    Word32 L_temp, L_temp2;
    Word16 exp, frac;

    Word32 L_THR1, L_THR2, L_THR3;

    Word16 exp_norm;
    Word16 norm_sum_fx;
    Word16 Qns; /* Q value for norm_sum_fx */
    Word16 Inv_norm_sum_fx; /* 1/norm_sum */
    Word16 QIns; /* Q value for Inv_norm_sum_fx */

    Word16 exp_normn, exp_normd;
    Word16 div_fx;

    Word16 Inv_p2a_bands_fx;
    Word16 QIpb;

    Word16 exp_shift;

    Word32 L_y[BANDS_MAX];
    for(i=0; i<N_fx; i++)
    {
        L_y[i] = (Word32)(y[i]*(float)pow(2.0f, SWB_BWE_LR_Qbe));
    }

    L_THR1 = L_shl(L_deposit_l(THR1), SWB_BWE_LR_QRk);
    L_THR2 = L_shl(L_deposit_l(THR2), SWB_BWE_LR_QRk);
    L_THR3 = L_shl(L_deposit_l(THR3), SWB_BWE_LR_QRk);

    set_val_Word16(Bits_grp_fx, 0, GRP_SB);

    /* Initialize subbands bits allocation vector based on harmonic bands */
    harmonic_band_fx = add(sub(N_fx, p2a_bands_fx), 1);
    /*printf("harmonic_band= %d %d\n", harmonic_band, harmonic_band_fx);*/
    FOR (k = 0; k < N_fx; k++)
    {
        L_Rsubband[k] = (Word32)(C1_QRk);
        move32(); /* Constant Value */
        L_temp_band_energy[k] = L_y[k];
        move32();   /* SWB_BWE_LR_Qbe */
    }
    final_gr_fact_pos_fx = 2;
    move16();
    bits_fact_fx =  C1_Qbf;
    move16();
    bits_fact1_fx = C1_Qbf;
    move16();

    gmax_range_fx[0]= G1_RANGE;
    move16();
    gmax_range_fx[1]= G1G2_RANGE;
    move16();

    IF( L_sub(L_core_brate, HQ_16k40) == 0 )
    {
        gmax_range_fx[1] = add(gmax_range_fx[1], 2);
        move16();
    }

    /* decide each group range, for grouping spectral coefficients */
    grp_rngmax_fx[1] = 16;
    move16();
    grp_rngmax_fx[0] =  7;
    move16();
    temp_fx = 0;
    move16();
    FOR( i=0; i<2; i++ )
    {
        j_fx = gmax_range_fx[i];
        move16();
        k_fx = 0;
        move16();
        test();
        WHILE( L_sub(L_temp_band_energy[gmax_range_fx[i]-1], L_temp_band_energy[j_fx] ) >= 0x0L && sub(j_fx, grp_rngmax_fx[i]) < 0x0 )
        {
            test();
            k_fx = add(k_fx, 1);
            j_fx = add(j_fx, 1);
        }

        temp_fx = k_fx;
        move16();
        IF( sub(temp_fx, 1) > 0 )
        {
            FOR( temp_fx = 2; temp_fx <= k_fx ; )
            {
                IF( L_sub(L_temp_band_energy[gmax_range_fx[i]+temp_fx-1], L_temp_band_energy[gmax_range_fx[i]+temp_fx]) < 0 )
                {
                    BREAK;
                }
                ELSE IF( L_sub(L_temp_band_energy[gmax_range_fx[i]+temp_fx-1], L_temp_band_energy[gmax_range_fx[i]+temp_fx]) >= 0 )
                {
                    temp_fx = add(temp_fx, 1);;
                    IF( sub(temp_fx, k_fx) > 0 )
                    {
                        temp_fx = sub(temp_fx, 1);
                        BREAK;
                    }
                }
            }

            gmax_range_fx[i] = add(gmax_range_fx[i], temp_fx);
        }
        ELSE
        {
            gmax_range_fx[i] = add(gmax_range_fx[i], temp_fx);
        }
    }

    grp_bound_fx[0] = 0;
    move16();
    FOR(i=1; i<GRP_SB-1; i++)
    {
        grp_bound_fx[i] = gmax_range_fx[i-1];
        move16();
    }
    grp_bound_fx[i] = harmonic_band_fx;
    move16();
    grp_bound_fx[i+1] = N_fx;
    move16();


    FOR(i=0; i<GRP_SB; i++)
    {
        L_Ravg_sub[i] = 0x0L;
        move32();
        FOR ( j = grp_bound_fx[i]; j < grp_bound_fx[i+1]; j++ )
        {
            IF ( L_temp_band_energy[j] > 0x0L )
            {
                L_Ravg_sub[i] = L_add(L_Ravg_sub[i], L_temp_band_energy[j]);
                move32();
            }
        }
    }

    L_temp_band_energydiff[0] = L_temp_band_energy[0];
    move32();
    FOR ( j = 1; j < harmonic_band_fx; j++ )
    {
        L_temp_band_energydiff[j]= L_abs(L_sub(L_temp_band_energy[j], L_temp_band_energy[j-1]));
        move32();
    }

    G1_BE_DIFF_POS_fx = 0;
    move16();
    L_G1_BE_DIFF_VAL = 0x0L;
    move32();

    FOR(j=1; j< harmonic_band_fx; j++)
    {
        IF( L_sub(L_temp_band_energydiff[j], L_G1_BE_DIFF_VAL) > 0 )
        {
            G1_BE_DIFF_POS_fx = j;
            move16();
            L_G1_BE_DIFF_VAL = L_temp_band_energydiff[j];
            move32();
        }
    }

    test();
    test();
    IF( sub(G1_BE_DIFF_POS_fx, gmax_range_fx[0] ) < 0 && G1_BE_DIFF_POS_fx > 0 )
    {
        final_gr_fact_pos_fx = 0;
        move16();
    }
    ELSE IF ( sub(G1_BE_DIFF_POS_fx, gmax_range_fx[0]) >= 0 && sub(G1_BE_DIFF_POS_fx, gmax_range_fx[1] ) < 0 )
    {
        final_gr_fact_pos_fx = 1;
        move16();
    }
    ELSE
    {
        final_gr_fact_pos_fx = 2;
        move16();
    }

    test();
    IF( final_gr_fact_pos_fx == 0 || sub(final_gr_fact_pos_fx, 1) == 0 )
    {
        IF( L_sub(L_core_brate, HQ_16k40 ) == 0 )
        {
            bits_fact_fx  = BITS_FACT_1p10;
            move16(); /* 1.10f; */ /* G1 */
            bits_fact1_fx = BITS_FACT_0p92;
            move16(); /* 0.92f; */ /* G3 */
        }
        ELSE
        {
            bits_fact_fx  = BITS_FACT_1p05;
            move16(); /* 1.05f; */ /* G1 */
            bits_fact1_fx = BITS_FACT_0p97;
            move16(); /* 0.97f; */ /* G3 */
        }
    }
    ELSE
    {
        IF( L_sub(L_core_brate, HQ_16k40) == 0 )
        {
            bits_fact_fx  = BITS_FACT_0p97;
            move16(); /* 0.97f; */ /* G1 */
            bits_fact1_fx = BITS_FACT_1p00;
            move16(); /* 1.00f; */ /* G3 */
        }
        ELSE
        {
            bits_fact_fx  = BITS_FACT_0p92;
            move16(); /* 0.92f; */ /* G1 */
            bits_fact1_fx = BITS_FACT_1p00;
            move16(); /* 1.00f; */ /* G3 */
        }
    }

    FOR ( i = 0; i < sub(N_fx, harmonic_band_fx); i++ )
    {
        y_index_fx[i] = extract_h(L_shl(L_temp_band_energy[harmonic_band_fx+i], sub(16, SWB_BWE_LR_Qbe)));
        move16();
        index_fx[i] = add(harmonic_band_fx, i);
        move16();
    }

    reordvct(y_index_fx, sub(N_fx, harmonic_band_fx), index_fx);

    /* Log2 */
    L_temp = L_deposit_l(band_width_fx[index_fx[0]]);
    exp = norm_l(L_temp);
    frac = Log2_norm_lc(L_shl(L_temp, exp));
    exp = sub(30, exp);
    L_temp = L_Comp(exp, frac);
    /* ceil */
    if( L_and(0x0000ffff, L_temp) > 0 )
    {
        L_temp = L_add(L_temp, 0x00010000);
    }
    esthf_bits_fx = extract_h(L_temp);

    L_grp_thr[0] = L_THR1;
    move32();
    L_grp_thr[1] = L_THR2;
    move32();
    L_grp_thr[2] = L_THR3;
    move32();
    L_grp_thr[3] = L_shl(L_deposit_l(esthf_bits_fx), SWB_BWE_LR_QRk);
    move16();

    L_norm_sum = 1;
    move32();
    FOR(i=0; i<3; i++)
    {
        L_norm_sum = L_add( L_norm_sum, L_Ravg_sub[i]);
        move32();
    }

    /*reserve bits for HF coding */
    L_temp = L_add(L_norm_sum, L_Ravg_sub[GRP_SB-1]);
    exp_normn = norm_l(L_temp);
    exp_normn = sub(exp_normn, 1);
    exp_normd = norm_s(N_fx);

    div_fx = div_l(L_shl(L_temp, exp_normn), shl(N_fx, exp_normd)); /* (Qbe+exp_normn)-(0+exp_normd)-1) */
    L_norm_sum_avg = L_shr(L_deposit_h(div_fx), add(sub(exp_normn, exp_normd), 15)); /* -> Qbe */

    exp_norm = norm_l(L_norm_sum);
    norm_sum_fx = extract_h( L_shl(L_norm_sum, exp_norm) ); /* SWB_BWE_LR_Qbe+exp_norm-16 */
    Qns = sub(add(SWB_BWE_LR_Qbe, exp_norm), 16);

    Inv_norm_sum_fx = div_s( 0x4000 /* Q15 */ , norm_sum_fx );
    QIns = sub(31, exp_norm); /* 14 - (14+exp_norm-16) + 15 */

    grp_bit_avg_fx = div_s_ss(B_fx, GRP_SB); /* Q0 */

    exp_normd = norm_s(p2a_bands_fx);
    Inv_p2a_bands_fx = div_s(0x3fff, shl(p2a_bands_fx, exp_normd)); /* 14-exp_normd+15 */
    QIpb = sub(29, exp_normd);

    L_temp = L_shl(Mpy_32_16(L_Ravg_sub[GRP_SB-1], Inv_p2a_bands_fx), sub(SWB_BWE_LR_Qbe, sub(QIpb,1)));
    L_norm_diff = L_sub(L_temp, L_norm_sum_avg); /* Qbe */

    L_temp = Mpy_32_16(L_Ravg_sub[GRP_SB-1], sub(GRP_SB, 1)); /* Qbe+0+1 */
    L_temp = Mpy_32_16(L_temp, Inv_norm_sum_fx);             /* Qbe+1+QIpb+1 */
    lf_hf_ge_r_fx = round_fx(L_shl(L_temp, sub(15+16, sub(add(SWB_BWE_LR_Qbe, QIns),30))));

    exp_normn = norm_s(norm_sum_fx);
    exp_normn = sub(exp_normn, 1);
    exp_normd = norm_s(harmonic_band_fx);

    div_fx = div_s(shl(norm_sum_fx, exp_normn), shl(harmonic_band_fx, exp_normd));
    L_avg_enhf_en_diff = L_sub(L_temp_band_energy[index_fx[0]], L_shl(L_deposit_h(div_fx), sub(sub(SWB_BWE_LR_Qbe, (add(Qns,sub(exp_normn,exp_normd)))),31))); /* Qbe - (Qns+exp_normn-(exp_normd)+15) -16 */

    IF( sub(lf_hf_ge_r_fx , 26214) > 0x0 && L_sub(L_avg_enhf_en_diff, (Word32)(8<<SWB_BWE_LR_Qbe)) > 0x0L) /* 0.8=26214.4(Q15) 8.0f=131072(Qbe) */
    {
        bits_allocweigh_fx = 6554;
        move16(); /* 0.2 6553.6(Q15) */
        IF(L_norm_diff < 0x0L)
        {
            bits_allocweigh_fx = 13107;
            move16();  /* 0.4 13107.2(Q15) */
        }

        /*allocate bits*/
        /*Bits_grp[GRP_SB-1] = (short)min((grp_bit_avg/p2a_bands + bits_allocweigh*norm_diff),10);*/
        L_temp = L_mult(grp_bit_avg_fx, Inv_p2a_bands_fx);    /* Q0+QIpb+1 */
        L_temp2 = Mpy_32_16(L_norm_diff, bits_allocweigh_fx); /* Qbe+Q15-15 */

        L_temp = L_shr(L_temp, add(QIpb, 1));
        L_temp = L_add(L_shl(L_temp,SWB_BWE_LR_Qbe), L_temp2);

        Bits_grp_fx[GRP_SB-1] = extract_h(L_shl(L_temp, sub(16, SWB_BWE_LR_Qbe)));
        Bits_grp_fx[GRP_SB-1] = s_min(Bits_grp_fx[GRP_SB-1], 10);

        test();
        if( sub(Bits_grp_fx[GRP_SB-1], esthf_bits_fx) < 0 )
        {
            Bits_grp_fx[GRP_SB-1] = 0;
            move16();
        }
        B_fx = sub(B_fx, Bits_grp_fx[GRP_SB-1]);
    }

    exp_shift = sub(add(SWB_BWE_LR_Qbe, QIns), 47); /* (SWB_BWE_LR_Qbe+14+1+QIns-15-16) */
    exp_norm = norm_s(B_fx);
    B_norm_fx = shl(B_fx, exp_norm);
    exp_shift = add(exp_shift, exp_norm);

    IF( sub(final_gr_fact_pos_fx, 1) == 0 )
    {
        L_temp = Mpy_32_16(L_Ravg_sub[1], extract_h(L_mult(bits_fact_fx, B_norm_fx)));
        L_temp = Mpy_32_16(L_temp, Inv_norm_sum_fx);
        Bits_grp_fx[1] = extract_h(L_shr(L_temp, exp_shift));

        L_temp = Mpy_32_16(L_Ravg_sub[2], extract_h(L_mult(bits_fact1_fx, B_norm_fx)));
        L_temp = Mpy_32_16(L_temp, Inv_norm_sum_fx);
        Bits_grp_fx[2] = extract_h(L_shr(L_temp, exp_shift));

        Bits_grp_fx[0] = sub(sub(B_fx, Bits_grp_fx[1]), Bits_grp_fx[2]);
    }
    ELSE
    {
        L_temp = Mpy_32_16(L_Ravg_sub[0], extract_h(L_mult(bits_fact_fx, B_norm_fx)));
        L_temp = Mpy_32_16(L_temp, Inv_norm_sum_fx);
        Bits_grp_fx[0] = extract_h(L_shr(L_temp, exp_shift));

        L_temp = Mpy_32_16(L_Ravg_sub[2], extract_h(L_mult(bits_fact1_fx, B_norm_fx)));
        L_temp = Mpy_32_16(L_temp, Inv_norm_sum_fx);
        Bits_grp_fx[2] = extract_h(L_shr(L_temp, exp_shift));

        Bits_grp_fx[1] = sub(sub(B_fx, Bits_grp_fx[0]), Bits_grp_fx[2]);
    }

    IF( sub(Bits_grp_fx[2], THR2 ) < 0 )
    {
        Bits_grp_fx[1] = add(Bits_grp_fx[1], Bits_grp_fx[2]);
        move16();
        Bits_grp_fx[2] = 0;
        move16();
    }

    FOR(i=0; i<GRP_SB; i++)
    {
        IF(Bits_grp_fx[i] > 0)
        {
            Bits2indvsb_fx( L_temp_band_energy, grp_bound_fx[i], grp_bound_fx[i+1] , Bits_grp_fx[i], L_grp_thr[i], L_Rsubband, p2a_flags_fx);
        }
        ELSE
        {
            set_val_Word32(L_Rsubband+grp_bound_fx[i], 0x0L, sub(grp_bound_fx[i+1], grp_bound_fx[i]));
            IF( sub(i, GRP_SB-1) == 0 )
            {
                set_val_Word16(p2a_flags_fx+grp_bound_fx[i], 0, sub(grp_bound_fx[i+1], grp_bound_fx[i]));
            }
        }
    }
    return;
}

void hq2_bit_alloc (
    const float  band_energy[],     /* i  : band energy of each subband                 */
    const short  bands,             /* i  : total number of subbands in a frame         */
    Word32  L_Rk[],            /* i/o: Bit allocation/Adjusted bit alloc.          */
    short  *bit_budget_fx,    /* i/o: bit bugdet                                  */
    short  *p2a_flags,        /* i  : HF tonal indicator                          */
    const Word16 weight_fx,         /* i  : weight (Q13)                                */
    const short  band_width[],      /* i  : Sub band bandwidth                          */
    const short  num_bits,          /* i  : available bits                              */
    const short  hqswb_clas,        /* i  : HQ2 class information                       */
    const short  bwidth,            /* i  : input bandwidth                             */
    const short  is_transient       /* i  : indicator HQ_TRANSIENT or not               */
)
{
    Word16 j, k;
    Word16 tmp;
    Word16 bit_budget_norm_fx;

    Word32 L_Rcalc, L_Ravg, L_Rcalc1;

    Word16 exp_normn, exp_normd;

    Word16 Rcnt_fx;

    Word16 div_fx;
    Word16 Qdiv;

    Word32 L_tmp;
    Word16 tmp_fx;

    Word32 L_maxxy;
    Word16 maxdex_fx;
    Word32 L_dummy;

    Word16 bit_budget_temp_fx;

    Word16 negflag;

    Word32 L_THR1, L_THR2, L_THR3;

    Word32 L_band_energy[BANDS_MAX];

    for(k=0; k<bands; k++)
    {
        L_band_energy[k] = (Word32)(band_energy[k]*(float)pow(2.0f, SWB_BWE_LR_Qbe));
    }

    L_THR1 = L_shl(L_deposit_l(THR1), SWB_BWE_LR_QRk);
    L_THR2 = L_shl(L_deposit_l(THR2), SWB_BWE_LR_QRk);
    L_THR3 = L_shl(L_deposit_l(THR3), SWB_BWE_LR_QRk);

    /* Init Rk to non-zero values for bands to be allocated bits */
    IF( sub(num_bits, HQ_16k40_BIT) <= 0 )
    {
        set_val_Word32( L_Rk, (Word32)(C1_QRk), bands); /* 1<<SWB_BWE_LR_QRk */

        test();
        IF( is_transient && sub(bands, 32) == 0 )
        {
            L_Rk[6] = 0x0L;
            move32();
            L_Rk[7] = 0x0L;
            move32();
            L_Rk[14] = 0x0L;
            move32();
            L_Rk[15] = 0x0L;
            move32();
            L_Rk[22] = 0x0L;
            move32();
            L_Rk[23] = 0x0L;
            move32();
            L_Rk[30] = 0x0L;
            move32();
            L_Rk[31] = 0x0L;
            move32();
        }
    }
    ELSE
    {
        /*mvs2r( p2a_flags, Rk, bands ); */
        FOR(k=0; k<bands; k++)
        {
            L_Rk[k] = L_shl(L_deposit_l(p2a_flags[k]), SWB_BWE_LR_QRk);
        }
    }

    L_Rcalc = 0x0L;
    move32();
    L_Rcalc1 = 0x0L;
    move32();

    FOR (j = 0; j < bands; j++)
    {
        Rcnt_fx = 0;
        move16();
        L_Ravg = 0x0L;
        move32();

        FOR (k = 0; k < bands; k++)
        {
            IF ( L_Rk[k] > 0 )
            {
                L_Ravg = L_add(L_Ravg, L_shl(L_band_energy[k], sub(SWB_BWE_LR_QRk, SWB_BWE_LR_Qbe)));  /* SWB_BWE_LR_QRk-SWB_BWE_LR_Qbe */
                Rcnt_fx = add(Rcnt_fx, 1);
            }
        }
        /* Ravg Qband_energy */

        /*L_Ravg /= Rcnt; */
        exp_normd = norm_l(L_Ravg);
        exp_normd = sub(exp_normd, 1);
        exp_normn = norm_s(Rcnt_fx);

        tmp = shl(Rcnt_fx, exp_normn);
        tmp = s_max(tmp,1);
        IF ( L_Ravg > 0 )
        {
            div_fx = div_l(L_shl(L_Ravg, exp_normd), tmp); /* Qdiv = 14+exp_normd-(exp_normn)-1 */
        }
        ELSE
        {
            div_fx = div_l(L_shl(L_abs(L_Ravg), exp_normd), tmp); /* Qdiv = 14+exp_normd-(exp_normn)-1 */
            div_fx = negate(div_fx);
        }

        /*Qdiv = QRk+exp_normd-(exp_normn)-1; */
        Qdiv = sub(sub(add(SWB_BWE_LR_QRk, exp_normd), exp_normn), 1);

        L_Ravg = L_shr(L_deposit_l(div_fx), sub(Qdiv, SWB_BWE_LR_QRk));

        exp_normd = norm_s(*bit_budget_fx);
        exp_normd = sub(exp_normd, 1);
        bit_budget_norm_fx = shl(*bit_budget_fx, exp_normd);
        div_fx = 0;
        move16();

        test();
        IF( bit_budget_norm_fx > 0 && sub(bit_budget_norm_fx, tmp) < 0 )
        {
            div_fx = div_s(bit_budget_norm_fx, tmp);
        }
        Qdiv = add(sub(exp_normd, exp_normn), 15);

        FOR (k = 0; k < bands; k++)
        {
            IF ( L_Rk[k] > 0)
            {
                /*Rk[k] = ((float) *bit_budget / Rcnt + weight * (band_energy[k] - Ravg)); */

                L_tmp = Mpy_32_16(L_sub(L_shl(L_band_energy[k], sub(SWB_BWE_LR_QRk, SWB_BWE_LR_Qbe)), L_Ravg), weight_fx); /* SWB_BWE_LR_QRk + Q13 - 15 */
                L_tmp = L_shl(L_tmp, 2); /* -> SWB_BWE_LR_QRk */

                L_Rk[k] = L_add(L_shr(L_deposit_l(div_fx), sub(Qdiv, SWB_BWE_LR_QRk)) , L_tmp);
            }
        }

        negflag = 0;
        move16();
        L_Rcalc = 0;
        move32();
        FOR (k = 0; k < bands; k++)
        {
            IF ( L_sub(L_Rk[k], MIN_BITS_FIX) < 0 )
            {
                L_Rk[k] = 0x0L;
                move32();
                negflag = 1;
                move16();
            }
            L_Rcalc = L_add( L_Rcalc , L_Rk[k]); /*SWB_BWE_LR_QRk */
        }

        /* prune noiselike bands with low allocation */
        IF ( sub(num_bits, HQ_16k40_BIT) <= 0 && negflag == 0)
        {
            L_maxxy = 0;
            move32();
            maxdex_fx = -1;
            move16();
            L_Rcalc = 0;
            move32();

            /* find worst under-allocation */
            FOR (k = sub(bands, 1); k >= 0; k--)
            {
                /* dummy = ((float) min (band_width[k], max (12, band_width[k] / 4))) - Rk[k];                                                                                                                                                                                              */
                tmp_fx = s_min( band_width[k], s_max(12, shr( band_width[k], 2)));
                L_dummy = L_sub(L_shl(L_deposit_l(tmp_fx), SWB_BWE_LR_QRk), L_Rk[k]) ; /*SWB_BWE_LR_QRk */
                test();
                test();
                test();
                IF ( p2a_flags[k] == 0 && L_sub(L_dummy, L_maxxy) > 0 && L_Rk[k] > 0 )
                {
                    maxdex_fx = k;
                    move16();
                    L_maxxy = L_dummy;
                    move32();/*SWB_BWE_LR_QRk */
                }
            }

            /* prune worst allocation and recalculate total allocation */
            IF ( sub(maxdex_fx, -1) > 0)
            {
                L_Rk[maxdex_fx] = 0;
                move32();
            }
            FOR (k = 0; k < bands; k++)
            {
                L_Rcalc = L_add(L_Rcalc, L_Rk[k]); /*SWB_BWE_LR_QRk */
            }
        }
        test();
        IF ( L_sub(L_Rcalc, L_Rcalc1) == 0 && sub(bwidth, SWB) == 0 )
        {
            /* Reallocate bits to individual subbands for HQ_NORMAL mode */
            /* if bits allocated to subbands areless than predefined threshold */
            IF( sub(hqswb_clas, HQ_NORMAL) == 0 && sub(num_bits, HQ_16k40_BIT) < 0 )
            {
                L_dummy = 0x0L;
                move32();
                FOR( k = 0; k < bands; k++ )
                {
                    test();
                    test();
                    test();
                    test();
                    test();
                    IF( sub(k, 11) < 0 && L_sub(L_Rk[k], L_THR1) < 0 )
                    {
                        L_Rk[k] = 0x0L;
                        move32();
                    }
                    ELSE IF( sub(k, 11) >= 0 && sub(k, 16) < 0 && L_sub(L_Rk[k], L_THR2) < 0 )
                    {
                        L_Rk[k] = 0x0L;
                        move32();
                    }
                    ELSE IF( sub(k, 16) >= 0 && sub(k, bands ) < 0 && L_sub(L_Rk[k], L_THR3) < 0 )
                    {
                        L_Rk[k] = 0x0L;
                        move32();
                    }

                    L_dummy = L_add(L_dummy, L_Rk[k]);
                }

                IF( L_sub(L_dummy, L_Rcalc ) == 0 )
                {
                    test();
                    IF( sub(hqswb_clas, HQ_NORMAL) == 0 && sub(num_bits, HQ_16k40_BIT) < 0)
                    {
                        bit_budget_temp_fx = *bit_budget_fx;
                        move16();
                        FOR( k=0; k<NB_SWB_SUBBANDS; k++ )
                        {
                            IF( p2a_flags[bands-NB_SWB_SUBBANDS+k] == 1 && L_Rk[bands-NB_SWB_SUBBANDS+k] == 0.0f )
                            {
                                p2a_flags[bands-NB_SWB_SUBBANDS+k] = 0;
                                move16();
                                bit_budget_temp_fx = sub(bit_budget_temp_fx, bits_lagIndices_modeNormal[k]);
                            }
                        }

                        IF(  sub(bit_budget_temp_fx, *bit_budget_fx ) < 0)
                        {
                            *bit_budget_fx = bit_budget_temp_fx;
                            move16();
                            /* a negative *bit_budget_fx may occur here due to Bit Errors              */
                            /* handled outside this function to properly set flag: st_fx->BER_detect */
                        }
                        ELSE IF( sub(bit_budget_temp_fx, *bit_budget_fx ) == 0 )
                        {
                            BREAK;
                        }
                    }
                    ELSE
                    {
                        BREAK;
                    }
                }
            }
            ELSE
            {
                BREAK;
            }
        }
        ELSE IF ( L_sub(L_Rcalc, L_Rcalc1 ) == 0 && sub(bwidth, SWB) != 0)
        {
            BREAK;
        }

        L_Rcalc1 = L_Rcalc;
        move32();

    }
    return;
}



} // end of namespace
