
#include        "common.h"
#include        "decoder.h"
/*#include        "huffman.h"
#include        "sound.h"

/*------------------------------------------------------------------*
 *								    *
 *    Function: Calculation of the inverse MDCT 		    *
 *    In the case of short blocks the 3 output vectors are already  *
 *    overlapped and added in this module.			    *
 *								    *
 *    New layer3                                                    *
 *								    *
 *------------------------------------------------------------------*/
void inv_mdct(
    REAL		in[18],
    REAL		out[36],
    int			block_type)
{
    int			i, m, N, p;
    static REAL		win[4][36];
    static int		init = 1;
    REAL		sum;
#ifdef OPTIMIZE
    static REAL		const1[12][6];
    static REAL		const3[36][18];
#else
    REAL		tmp[12];
    static REAL		COS[4 * 36];
#endif

    if (init == 1) {

	/* Type 0 */
	for (i = 0; i < 36; i++)
	    win[0][i] = sin(PI36 * (i + 0.5));

	/* Type 1 */
	for (i = 0; i < 18; i++)
	    win[1][i] = sin(PI36 * (i + 0.5));
	for (i = 18; i < 24; i++)
	    win[1][i] = 1.0;
	for (i = 24; i < 30; i++)
	    win[1][i] = sin(PI12 * (i + 0.5 - 18));
	for (i = 30; i < 36; i++)
	    win[1][i] = 0.0;

	/* Type 3 */
	for (i = 0; i < 6; i++)
	    win[3][i] = 0.0;
	for (i = 6; i < 12; i++)
	    win[3][i] = sin(PI12 * (i + 0.5 - 6));
	for (i = 12; i < 18; i++)
	    win[3][i] = 1.0;
	for (i = 18; i < 36; i++)
	    win[3][i] = sin(PI36 * (i + 0.5));

	/* Type 2 */
	for (i = 0; i < 12; i++)
	    win[2][i] = sin(PI12 * (i + 0.5)) ;
	for (i = 12; i < 36; i++)
	    win[2][i] = 0.0 ;

#ifdef OPTIMIZE

	/* Pre-calculate cosine array */
	N = 12;
	for (p = 0; p < N; p++)
	    for (m = 0; m < N/2; m++)
		const1[p][m] = cos((PI/(2*N)) * (2*p+1+N/2) * (2*m+1));

	/*
	 *  Create an optimized cosine lookup table
	 *  for the block_type != 2 case
	 */
	for (p = 0; p < 36; p++) {
	    int pconst = (p * 2) + 19;

	    for (m = 0; m < 18; m++)
		/* Calculate cosine value for this position */
		const3[p][m] = cos(PI/(2*36) *
			      ((pconst * ((m << 1) + 1)) % 144));
	}
	init = 0;
    }

    if (block_type == 2) {

	/* Clear the out[] array */
	memset((void *)&out[0], 0, sizeof(REAL) * 36);

	/*
	 * Optimization I
	 *
	 * for (i = 0; i < 3; i++) {
	 *    for (p = 0; p < 12; p++) {
	 *	sum = in[i] * const1[p][0] +
	 *	    in[i + 3] * const1[p][1] +
	 *	    in[i + 6] * const1[p][2] +
	 *	    in[i + 9] * const1[p][3] +
	 *	    in[i + 12] * const1[p][4] +
	 *	    in[i + 15] * const1[p][5];
	 *	out[6 * i + p + 6] += sum * win[2][p];
	 *    }
	 * }
	 */

	/*
	 * Optimization II
	 */
	for (p = 0; p < 12; p++) {
	    sum = in[0] * const1[p][0] +
		in[3] * const1[p][1] +
		in[6] * const1[p][2] +
		in[9] * const1[p][3] +
		in[12] * const1[p][4] +
		in[15] * const1[p][5];
	    out[p + 6] += sum * win[2][p];
	} 
	for (p = 0; p < 12; p++) {
	    sum = in[1] * const1[p][0] +
		in[4] * const1[p][1] +
		in[7] * const1[p][2] +
		in[10] * const1[p][3] +
		in[13] * const1[p][4] +
		in[16] * const1[p][5];
	    out[p + 12] += sum * win[2][p];
	}
	for (p = 0; p < 12; p++) {
	    sum = in[2] * const1[p][0] +
		in[5] * const1[p][1] +
		in[8] * const1[p][2] +
		in[11] * const1[p][3] +
		in[14] * const1[p][4] +
		in[17] * const1[p][5];
	    out[p + 18] += sum * win[2][p];
	}

    } else { /* block_type != 2 */

	/*
	 * Optimization I
	 *
	 * for (p = 0; p < 36; p++) {
	 *    sum = 0.0;
	 *
	 *    for (m = 0; m < 18; m++)
	 *	 sum += in[m] * const3[p][m];
	 *    out[p] = sum * win[block_type][p];
	 * }
	 */

	/*
	 * Optimization II
	 */
	int nzcount, nzin[18];

	for (p = 0, nzcount = 0; p < 18; p++)
	    if (in[p] < -0.0004 || in[p] > 0.0004)	/* analyze input */
		nzin[nzcount++] = p;

	for (p = 0; p < 36; p++) {
	    sum = 0.0;

	    for (m = 0; m < nzcount; m++)
		sum += in[nzin[m]] * const3[p][nzin[m]];
	    out[p] = sum * win[block_type][p];
	}
    }

#else /* original code */

	for (i = 0; i < 4*36; i++)
	    COS[i] = cos(PI/(2*36) * i);

	init = 0;
    }

    for (i = 0; i < 36; i++)
	out[i]=0;

    if (block_type == 2){
	N = 12;
	for (i=0; i<3; i++){
	    for (p = 0; p<N; p++){
		sum = 0.0;
		for(m=0; m<N/2; m++)
		    sum += in[i+3*m] * cos( PI/(2*N)*(2*p+1+N/2)*(2*m+1) );
		tmp[p] = sum * win[block_type][p] ;
	    }
	    for (p=0; p<N; p++)
		out[6*i+p+6] += tmp[p];
       }
    } else {
	N = 36;
	for (p=0; p<N; p++){
	    sum = 0.0;
	    for (m=0; m < N/2; m++)
		sum += in[m] * COS[((2*p+1+N/2)*(2*m+1))%(4*36)];
	    out[p] = sum * win[block_type][p];
	}
    }
#endif /* OPTIMIZE */
}

void III_hybrid(
	int gr_info[3],
    REAL		 fsIn[SSLIMIT],   /* freq samples per subband in */
    REAL		 tsOut[SSLIMIT],  /* time samples per subband out */
    int			 sb
    )
{
    int		 ss;
#ifdef OPTIMIZE
    static REAL	 rawout[36];
#else
    REAL	 rawout[36];
#endif
    static REAL	 prevblck[SBLIMIT][SSLIMIT];
    static int	 init = 1;
    int		 bt;

    if (init == 1) {
	int j, k;
      
	    for (j = 0; j < SBLIMIT; j++)
		for (k = 0; k < SSLIMIT; k++)
		    prevblck[j][k] = 0.0;
	init = 0;
    }

    bt = (gr_info[0] && gr_info[2] &&
		(sb < 2)) ? 0 : gr_info[1]; 

    inv_mdct(fsIn, rawout, bt);

    /* Overlap addition */
    for (ss = 0; ss < SSLIMIT; ss++) {		/* 18 */
	tsOut[ss] = rawout[ss] + prevblck[sb][ss];
	prevblck[sb][ss] = rawout[ss+18];
    }
}


