/*
 * Copyright (C) 2003 - 2016 Sony Corporation
 *
 * 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.
 */

#include "ldac.h"

/***************************************************************************************************
    Subfunction: Get Scale Factor Index
***************************************************************************************************/
__inline static int get_scale_factor_id_ldac(
INT32 val)
{
    int i;
    int id, step;

    if (ga_sf_ldac[0] > val) {
        return 0;
    }

    id = LDAC_NIDSF >> 1;
    step = LDAC_NIDSF >> 2;
    for (i = 0; i < LDAC_IDSFBITS-1; i++) {
        if (ga_sf_ldac[id] > val) {
            id -= step;
        }
        else {
            id += step;
        }
        step >>= 1;
    }

    if ((ga_sf_ldac[id] <= val) && (id < LDAC_NIDSF-1)) {
        id++;
    }

    return id;
}

/***************************************************************************************************
    Normalize Spectrum
***************************************************************************************************/
static INT32 sa_val_ldac[LDAC_MAXNSPS] = { /* Q31 */
    0xa0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
};

DECLFUNC void norm_spectrum_ldac(
AC *p_ac)
{
    int iqu, isp;
    int lsp, hsp;
    int nqus = p_ac->p_ab->nqus;
    int idsf;
    INT32 maxspec, tmp;
    INT32 *p_spec = p_ac->p_acsub->a_spec;

    for (iqu = 0; iqu < nqus; iqu++) {
        lsp = ga_isp_ldac[iqu];
        hsp = ga_isp_ldac[iqu+1];

        maxspec = abs(p_spec[lsp]);
        for (isp = lsp+1; isp < hsp; isp++) {
            tmp = abs(p_spec[isp]);
            if (maxspec < tmp) {
                maxspec = tmp;
            }
        }
        idsf = get_scale_factor_id_ldac(maxspec);

        if (idsf > 0) {
            for (isp = lsp; isp < hsp; isp++) {
                p_spec[isp] = sftrnd_ldac(p_spec[isp], idsf-LDAC_Q_NORM);
            }
        }
        else {
            for (isp = lsp; isp < hsp; isp++) {
                p_spec[isp] = sa_val_ldac[isp-lsp];
            }
        }

        p_ac->a_idsf[iqu] = idsf;
    }

    return;
}

/***************************************************************************************************
    Subfunction: Quantize Spectrum Core
***************************************************************************************************/
__inline static void quant_spectrum_core_ldac(
AC *p_ac,
int iqu)
{
    int i;
    int isp = ga_isp_ldac[iqu];
    int nsps = ga_nsps_ldac[iqu];
    int *p_qspec = p_ac->a_qspec+isp;
    INT32 qf = ga_qf_ldac[p_ac->a_idwl1[iqu]];
    INT32 *p_nspec = p_ac->p_acsub->a_spec+isp;

    for (i = 0; i < nsps; i++) {
        /* Q00 <- Q31 * Q16 */
        p_qspec[i] = mul_rsftrnd_ldac(p_nspec[i], qf, LDAC_Q_QUANT1);
    }

    return;
}

/***************************************************************************************************
    Quantize Spectrum
***************************************************************************************************/
DECLFUNC void quant_spectrum_ldac(
AC *p_ac)
{
    int iqu;
    int nqus = p_ac->p_ab->nqus;

    for (iqu = 0; iqu < nqus; iqu++) {
        quant_spectrum_core_ldac(p_ac, iqu);
    }

    return;
}

/***************************************************************************************************
    Subfunction: Quantize Residual Spectrum Core
***************************************************************************************************/
__inline static void quant_residual_core_ldac(
AC *p_ac,
int iqu)
{
    int i;
    int isp = ga_isp_ldac[iqu];
    int nsps = ga_nsps_ldac[iqu];
    int *p_qspec = p_ac->a_qspec+isp;
    int *p_rspec = p_ac->a_rspec+isp;
    INT32 ldqspec, rnspec;
    INT32 iqf = ga_iqf_ldac[LDAC_MAXIDWL1];
    INT32 rqf = ga_qf_ldac[p_ac->a_idwl2[iqu]];
    INT32 irsf = ga_irsf_ldac[LDAC_MAXIDWL1];
    INT32 *p_nspec = p_ac->p_acsub->a_spec+isp;

    for (i = 0; i < nsps; i++) {
        /* Q31 <- Q00 * Q31 */
        ldqspec = mul_lsftrnd_ldac(p_qspec[i], iqf, LDAC_Q_QUANT2);
        /* Q31 <- (Q31 - Q31) * Q15 */
        rnspec = mul_rsftrnd_ldac(p_nspec[i]-ldqspec, irsf, LDAC_Q_QUANT3);
        /* Q00 <- Q31 * Q16 */
        p_rspec[i] = mul_rsftrnd_ldac(rnspec, rqf, LDAC_Q_QUANT4);
    }

    return;
}

/***************************************************************************************************
    Quantize Residual Spectrum
***************************************************************************************************/
DECLFUNC void quant_residual_ldac(
AC *p_ac)
{
    int iqu;
    int nqus = p_ac->p_ab->nqus;
    int	*p_idwl2 = p_ac->a_idwl2;

    for (iqu = 0; iqu < nqus; iqu++) {
        if (p_idwl2[iqu] > 0) {
            quant_residual_core_ldac(p_ac, iqu);
        }
    }

    return;
}