/*====================================================================================
    EVS Codec 3GPP TS26.443 Jun 30, 2015. Version CR 26.443-0006
  ====================================================================================*/

#include "options.h"
#include "cnst.h"
#include "prot.h"
#include "rom_com.h"
#include <assert.h>


/*--------------------------------------------------------------------------*
*  mvr2r_inv()
*
*
*--------------------------------------------------------------------------*/

static void mvr2r_inv(
    const float *in,
    float *out,
    short L,
    short decimate
)
{
    short i;

    in=in+(short) ((decimate-1)/2);
    out=out+L-1;

    for (i=0; i<L; i++)
    {
        *out=*in;
        in+=decimate;
        out--;
    }

    return;
}

/*--------------------------------------------------------------------------*
*  mvr2r_dec()
*
*
*--------------------------------------------------------------------------*/

static void mvr2r_dec(
    const float *in,
    float *out,
    short L,
    short decimate
)
{
    short i;
    in=in+(short) ((decimate-1)/2);
    for (i=0; i<L; i++)
    {
        *out=*in;
        in+=decimate;
        out++;
    }

    return;
}

/*--------------------------------------------------------------------------*
*  copy_win()
*
*
*--------------------------------------------------------------------------*/

static void copy_win(
    float *out_win,
    short nb_zero,
    const float *in_win,
    short win_lenght,
    short nb_one,
    short decimate
)
{
    if (decimate<0)
    {
        set_f(out_win,1,nb_one);
        mvr2r_inv(in_win,out_win+nb_one,win_lenght,-decimate);
        set_f(out_win+win_lenght+nb_one,0,nb_zero);
    }
    else
    {
        set_f(out_win,0,nb_zero);
        mvr2r_dec(in_win,out_win+nb_zero,win_lenght,decimate);
        set_f(out_win+nb_zero+win_lenght,1,nb_one);
    }

    return;
}

/*--------------------------------------------------------------------------*
*  tcx_get_windows_mode1()
*
*
*--------------------------------------------------------------------------*/

void tcx_get_windows_mode1(
    const short left_mode,          /* i: overlap mode of left window half          */
    const short right_mode,         /* i: overlap mode of right window half         */
    float  *left_win,               /* o: left overlap window                       */
    float  *right_win,              /* o: right overlap window                      */
    float  *left_win_int,           /* o: left overlap window                       */
    float  *right_win_int,          /* o: right overlap window                      */
    short const L
)
{
    /* Left part */
    if (left_mode == MIN_OVERLAP || left_mode == TRANSITION_OVERLAP)
    {
        if (L==256 || L == 512)
        {
            copy_win(left_win,R1_25-4*R2_25/7,small_overlap_25,R2_25/7,3*R2_25/7,1);
        }
        else
        {
            copy_win(left_win,R1_48-4*R2_48/7,small_overlap_48,R2_48/7,3*R2_48/7,1);
            copy_win(left_win_int,R1_16-4*R2_16/7,small_overlap_int,R2_16/7,3*R2_16/7,1);
        }
    }
    else if (left_mode == HALF_OVERLAP)
    {
        if (L==256 || L == 512)
        {
            copy_win(left_win,R1_25-5*R2_25/7,half_overlap_25,3*R2_25/7,2*R2_25/7,1);
        }
        else
        {
            copy_win(left_win,R1_48-5*R2_48/7,half_overlap_48,3*R2_48/7,2*R2_48/7,1);
            copy_win(left_win_int,R1_16-5*R2_16/7,half_overlap_int,3*R2_16/7,2*R2_16/7,1);
        }
    }
    else if (left_mode == ALDO_WINDOW)
    {
        /* ALDO */
        if (L==256 || L == 512)
        {
            mvr2r(window_256kHz,left_win,R1_25);
        }
        else
        {
            mvr2r(window_48kHz,left_win,R1_48);
            mvr2r(window_8_16_32kHz,left_win_int,R1_16);
        }
    }
    else
    {
        assert(!"Window not supported");
    }

    /* Right part */
    if (right_mode == MIN_OVERLAP || right_mode == TRANSITION_OVERLAP)
    {

        if (L==256 || L == 512)
        {
            copy_win(right_win,3*R2_25/7,small_overlap_25,R2_25/7,3*R2_25/7,-1);
        }
        else
        {
            copy_win(right_win,3*R2_48/7,small_overlap_48,R2_48/7,3*R2_48/7,-1);
            copy_win(right_win_int,3*R2_16/7,small_overlap_int,R2_16/7,3*R2_16/7,-1);
        }
    }
    else if (right_mode == HALF_OVERLAP)
    {

        if (L==256 || L == 512)
        {
            copy_win(right_win,2*R2_25/7,half_overlap_25,3*R2_25/7,2*R2_25/7,-1);
        }
        else
        {
            copy_win(right_win,2*R2_48/7,half_overlap_48,3*R2_48/7,2*R2_48/7,-1);
            copy_win(right_win_int,2*R2_16/7,half_overlap_int,3*R2_16/7,2*R2_16/7,-1);
        }
    }
    else if (right_mode == ALDO_WINDOW)
    {
        if (L==256 || L == 512)
        {
            mvr2r(window_256kHz+R1_25,right_win,R2_25);
        }
        else
        {
            mvr2r(window_48kHz+R1_48,right_win,R2_48);
            mvr2r(window_8_16_32kHz+R1_16,right_win_int,R2_16);
        }
    }
    else
    {
        assert(!"Window not supported");
    }

    return;
}


/*--------------------------------------------------------------------------*
*  wtda()
*
*  Windowing and time-domain aliasing
*--------------------------------------------------------------------------*/

void wtda(
    const float *new_audio,         /* i  : input audio                         */
    float *wtda_audio,        /* o  : windowed audio                      */
    float *old_wtda,          /* i/o: windowed audio from previous frame  */
    const short left_mode,
    const short right_mode,         /* window overlap of current frame (0: full, 2: none, or 3: half) */
    const short L                   /* i  : length                              */
)
{
    short i, decimate, decay;
    short n, windecay48, windecay16;
    const float *allsig_l, *allsig_r;
    float win_right[R2_48];
    float win_int_left[R1_16];
    float win_left[R1_48];
    float win_int_right[R2_16];

    tcx_get_windows_mode1(   left_mode,  right_mode, win_left, win_right, win_int_left,win_int_right, L);


    decimate = 1; /* L_FRAME 48k */
    decay = 0;
    windecay48 = (short)(2*((float)L_FRAME48k*N_ZERO_MDCT_NS/FRAME_SIZE_NS))+R1_48;


    if (L== L_FRAME32k || L== L_FRAME16k )
    {
        decimate = 3;
        decay = 1;

    }
    else if (L== L_FRAME8k)
    {
        decimate = 6;
        decay = 2;

    }


    n = (short)((float)L*N_ZERO_MDCT_NS/FRAME_SIZE_NS);

    windecay16 = (short)(2*((float)L_FRAME16k*N_ZERO_MDCT_NS/FRAME_SIZE_NS))+R1_16;

    /* algorithmic delay reduction */
    i = 0;

    if (old_wtda == NULL)
    {
        allsig_r = new_audio+n;
        allsig_l = new_audio+n-L;
    }
    else
    {
        allsig_r = new_audio+n;
        allsig_l = old_wtda+n;
    }


    if  ( L == L_FRAME32k )
    {
        {
            for (i=0; i<L/2-n; i+=2)
            {
                wtda_audio[i]=-allsig_r[L/2-i-1]*win_int_right[3*L_FRAME16k/2-i/2-1-windecay16]-allsig_r[L/2+i]*win_int_right[3*L_FRAME16k/2+i/2-windecay16];
                wtda_audio[i+1]=-allsig_r[L/2-(i+1)-1]*win_right[(3*L_FRAME16k/2-i/2-1)*decimate+decay-windecay48]-allsig_r[L/2+i+1]*win_right[(3*L_FRAME16k/2+1+i/2)*decimate-decay-1-windecay48];
            }

            for (i=L/2-n; i<L/2; i+=2)
            {
                wtda_audio[i]=-allsig_r[L/2-i-1];
                wtda_audio[i+1]=-allsig_r[L/2-(i+1)-1];
            }
            for (i=0; i<n; i+=2)
            {
                wtda_audio[i+L/2]=allsig_l[i]*win_left[(i/2)*decimate+decay]-new_audio[n-i-1];
                wtda_audio[i+L/2+1]=allsig_l[i+1]*win_int_left[i/2]-new_audio[n-(i+1)-1];
            }

            for (i=n; i<L/2; i+=2)
            {
                wtda_audio[i+L/2]=allsig_l[i]*win_left[(i/2)*decimate+decay]-allsig_l[L-i-1]*win_left[(L/2-i/2)*decimate-1-decay];
                wtda_audio[i+L/2+1]=allsig_l[i+1]*win_int_left[i/2]-allsig_l[L-(i+1)-1]*win_int_left[L/2-i/2-1];
            }

        }
    }
    else
    {
        {

            for (i=0; i<L/2-n; i++)
            {
                wtda_audio[i]=-allsig_r[L/2-i-1]*win_right[3*L/2*decimate-(i+1)*decimate+decay-windecay48]-allsig_r[L/2+i]*win_right[3*L/2*decimate-1+(i+1)*decimate-decay-windecay48];
            }

            for (i=L/2-n; i<L/2; i++)
            {
                wtda_audio[i]=-allsig_r[L/2-i-1];
            }

            for (i=0; i<n; i++)
            {
                wtda_audio[i+L/2]=allsig_l[i]*win_left[i*decimate+decay]-new_audio[n-i-1];
            }

            for (i=n; i<L/2; i++)
            {
                wtda_audio[i+L/2]=allsig_l[i]*win_left[i*decimate+decay]-allsig_l[L-i-1]*win_left[L*decimate-i*decimate-1-decay];
            }

        }

    }

    if (old_wtda != NULL)
    {
        mvr2r( new_audio, old_wtda, L );
    }

    return;
}