
#include        "common.h"
#include        "decoder.h"

/*****************************************************************
 *
 * The following are the subband synthesis routines. They apply
 * to both layer I and layer II stereo or mono. The user has to
 * decide what parameters are to be passed to the routines.
 *
 ***************************************************************/

/*************************************************************
 *
 *   Pass the subband sample through the synthesis window
 *
 **************************************************************/

/* create in synthesis filter */

void create_syn_filter(REAL FAR filter[64][SBLIMIT])
{
    int i, k;
#ifdef NO_MODFF
    double temp;
#endif

    for (i = 0; i < 64; i++)
	for (k = 0; k < 32; k++) {
#ifdef FSINGLE
	    filter[i][k] = 1e9 * cos((PI64*i+PI4)*(2.0*k+1.0));
	    if (filter[i][k] >= 0) {
		/*modff(filter[i][k]+0.5, &filter[i][k]);*/
		filter[i][k] = floor(filter[i][k] + 0.5);
	    } else {
		/*modff(filter[i][k]-0.5, &filter[i][k]);*/
		filter[i][k] = floor(filter[i][k] - 0.5);
	    }
#else /* FSINGLE */
	    filter[i][k] = 1e9*cos((PI64*i+PI4)*(2*k+1));
	    if (filter[i][k] >= 0)
		/*modf(filter[i][k]+0.5, &filter[i][k]);*/
		filter[i][k] = floor(filter[i][k] + 0.5);
	    else
		/*modf(filter[i][k]-0.5, &filter[i][k]);*/
		filter[i][k] = floor(filter[i][k] - 0.5);
#endif
	    filter[i][k] *= 1e-9;
	}
	/*
	 * filter[][] is now filled with values between -1 and 1.
	 */
}


#ifndef BUILTIN_TABLES

/***************************************************************
 *
 *   Window the restored sample
 *
 ***************************************************************/

/* read in synthesis window */

void read_syn_window(REAL FAR window[HAN_SIZE])
{
    int	  i, j[4];
    FILE *fp;
    REAL  f[4];
    char  t[150];

    if (!(fp = OpenTableFile("dewindow") )) {
        fprintf(stderr, "Please check synthesis window table 'dewindow'\n");
        exit(1);
    }
    for (i=0; i<512; i+=4) {
        fgets(t, 150, fp);
#ifdef FSINGLE
	sscanf(t,"D[%d] = %f D[%d] = %f D[%d] = %f D[%d] = %f\n",
		j, f, j+1, f+1, j+2, f+2, j+3, f+3);
#else
        sscanf(t,"D[%d] = %lf D[%d] = %lf D[%d] = %lf D[%d] = %lf\n",
		j, f, j+1, f+1, j+2, f+2, j+3, f+3);
#endif
        if (i == j[0]) {
            window[i] = f[0];
            window[i+1] = f[1];
            window[i+2] = f[2];
            window[i+3] = f[3];
        }
        else {
            fprintf(stderr, "Check index in synthesis window table\n");
            exit(1);
        }
        fgets(t, 150, fp);
    }
    fclose(fp);
}

#endif /* BUILTIN_TABLES */


#ifndef INT_MATH

/* Set to 1 for the optimization level from version 0.9.3 and earlier */
#define OPTIMIZE_093	0
/* Set to 1 for the "fuzzy zero detection" optimization in version 0.9.5 */
#define OPTIMIZE_095	0

int SubBandSynthesis(
    REAL	*bandPtr,
    short	*samples)
{
    int			 i, j;
    REAL		*bufOffsetPtr, sum;
    static int		 init = 1;
    typedef REAL	 NN[64][32];
    static NN FAR	*filter;
    typedef REAL	 BB[2*HAN_SIZE];
    static BB FAR	*buf;
    static int		 bufOffset = 64;
    static REAL FAR	*window;
    int			 clip = 0;   /* count & return # samples clipped */
    int			 offset;
    long		 foo;
    int			 k;
#ifdef OPTIMIZE
    REAL		*filterp;
    REAL		*bandp;
# if OPTIMIZE_095
    int			 nzbcount, nzbands[32];	/* non-zero band detection */
# endif
#endif

    if (init == 1) {
        buf = (BB FAR *) mem_alloc(sizeof(BB),"BB");
        filter = (NN FAR *) mem_alloc(sizeof(NN), "NN");
        create_syn_filter(*filter);
        window = (REAL FAR *) mem_alloc(sizeof(REAL) * HAN_SIZE, "WIN");
        read_syn_window(window);
	init = 0;
    }

    bufOffset = (bufOffset - 64) & 0x3ff;
    bufOffsetPtr = &((*buf)[bufOffset]);

#ifdef OPTIMIZE

# if OPTIMIZE_093

    filterp = (REAL *)((*filter)[0]);
    bandp = bandPtr;

    i = 64;
    while (i--) {

	*bufOffsetPtr++ =
	    bandp[0] * filterp[0] +
	    bandp[1] * filterp[1] +
	    bandp[2] * filterp[2] +
	    bandp[3] * filterp[3] +
	    bandp[4] * filterp[4] +
	    bandp[5] * filterp[5] +
	    bandp[6] * filterp[6] +
	    bandp[7] * filterp[7] +
	    bandp[8] * filterp[8] +
	    bandp[9] * filterp[9] +
	    bandp[10] * filterp[10] +
	    bandp[11] * filterp[11] +
	    bandp[12] * filterp[12] +
	    bandp[13] * filterp[13] +
	    bandp[14] * filterp[14] +
	    bandp[15] * filterp[15] +
	    bandp[16] * filterp[16] +
	    bandp[17] * filterp[17] +
	    bandp[18] * filterp[18] +
	    bandp[19] * filterp[19] +
	    bandp[20] * filterp[20] +
	    bandp[21] * filterp[21] +
	    bandp[22] * filterp[22] +
	    bandp[23] * filterp[23] +
	    bandp[24] * filterp[24] +
	    bandp[25] * filterp[25] +
	    bandp[26] * filterp[26] +
	    bandp[27] * filterp[27] +
	    bandp[28] * filterp[28] +
	    bandp[29] * filterp[29] +
	    bandp[30] * filterp[30] +
	    bandp[31] * filterp[31];

	filterp += 32;
    }

# elif OPTIMIZE_095

    filterp = (REAL *)((*filter)[0]);
    bandp = bandPtr;

    /* Analyze input */
    for (i = 0, nzbcount = 0; i < 32; i++)
	/* Fuzzy zero detection */
	if (bandp[i] < -0.00035 || bandp[i] > 0.00035)
	    nzbands[nzbcount++] = i;

    for (i = 0; i < 64; i++, filterp += 32) {

	/* Only add non-zero bands */
	for (j = 0, sum = 0.0; j < nzbcount; j++)	    
	    sum += bandp[nzbands[j]] * filterp[nzbands[j]];

	*bufOffsetPtr++ = sum;
    }

# else /*optimize using a fast cosine transform */

#define cos1_64  0.500602998235196
#define cos3_64  0.505470959897544
#define cos5_64  0.515447309922625
#define cos7_64  0.531042591089784
#define cos9_64  0.553103896034445
#define cos11_64 0.582934968206134
#define cos13_64 0.622504123035665
#define cos15_64 0.674808341455006
#define cos17_64 0.744536271002299
#define cos19_64 0.839349645415527
#define cos21_64 0.972568237861961
#define cos23_64 1.169439933432885
#define cos25_64 1.484164616314166
#define cos27_64 2.057781009953411
#define cos29_64 3.407608418468719
#define cos31_64 10.190008123548033
#define cos1_32  0.502419286188156
#define cos3_32  0.522498614939689
#define cos5_32  0.566944034816358
#define cos7_32  0.646821783359990
#define cos9_32  0.788154623451250
#define cos11_32 1.060677685990347
#define cos13_32 1.722447098238334
#define cos15_32 5.101148618689155
#define cos1_16  0.509795579104159
#define cos3_16  0.601344886935045
#define cos5_16  0.899976223136416
#define cos7_16  2.562915447741505
#define cos1_8   0.541196100146197
#define cos3_8   1.306562964876376
#define cos1_4   0.707106781186547

  {
    int i;
    register REAL tmp;
    REAL p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15;
    REAL pp0,pp1,pp2,pp3,pp4,pp5,pp6,pp7,pp8,pp9,pp10,pp11,pp12,pp13,pp14,pp15;

    /* Compute new values via a fast cosine transform */
    p0  = bandPtr[0] + bandPtr[31];
    p1  = bandPtr[1] + bandPtr[30];
    p2  = bandPtr[2] + bandPtr[29];
    p3  = bandPtr[3] + bandPtr[28];
    p4  = bandPtr[4] + bandPtr[27];
    p5  = bandPtr[5] + bandPtr[26];
    p6  = bandPtr[6] + bandPtr[25];
    p7  = bandPtr[7] + bandPtr[24];
    p8  = bandPtr[8] + bandPtr[23];
    p9  = bandPtr[9] + bandPtr[22];
    p10 = bandPtr[10]+ bandPtr[21];
    p11 = bandPtr[11]+ bandPtr[20];
    p12 = bandPtr[12]+ bandPtr[19];
    p13 = bandPtr[13]+ bandPtr[18];
    p14 = bandPtr[15]+ bandPtr[17];
    p15 = bandPtr[16]+ bandPtr[16];

    pp0 = p0 + p15;
    pp1 = p1 + p14;
    pp2 = p2 + p13;
    pp3 = p3 + p12;
    pp4 = p4 + p11;
    pp5 = p5 + p10;
    pp6 = p6 + p9;
    pp7 = p7 + p8;
    pp8 = cos1_32  * (p0 - p15);
    pp9 = cos3_32  * (p1 - p14);
    pp10= cos5_32  * (p2 - p13);
    pp11= cos7_32  * (p3 - p12);
    pp12= cos9_32  * (p4 - p11);
    pp13= cos11_32 * (p5 - p10);
    pp14= cos13_32 * (p6 - p9);
    pp15= cos15_32 * (p7 - p8);

    p0 = pp0 + pp7;
    p1 = pp1 + pp6;
    p2 = pp2 + pp5;
    p3 = pp3 + pp4;
    p4 = cos1_16 * (pp0 - pp7);
    p5 = cos3_16 * (pp1 - pp6);
    p6 = cos5_16 * (pp2 - pp5);
    p7 = cos7_16 * (pp3 - pp4);
    p8 = pp8 + pp15;
    p9 = pp9 + pp14;
    p10= pp10 + pp13;
    p11= pp11 + pp12;
    p12= cos1_16 * (pp8  - pp15);
    p13= cos3_16 * (pp9  - pp14);
    p14= cos5_16 * (pp10 - pp13);
    p15= cos7_16 * (pp11 - pp12);

    pp0 = p0 + p3;
    pp1 = p1 + p2;
    pp2 = cos1_8 * (p0 - p3);
    pp3 = cos3_8 * (p1 - p2);
    pp4 = p4 + p7;
    pp5 = p5 + p6;
    pp6 = cos1_8 * (p4 - p7);
    pp7 = cos3_8 * (p5 - p6);
    pp8 = p8 + p11;
    pp9 = p9 + p10;
    pp10= cos1_8 * (p8 - p11);
    pp11= cos3_8 * (p9 - p10);
    pp12= p12 + p15;
    pp13 = p13 + p14;
    pp14= cos1_8 * (p12 - p15);
    pp15= cos3_8 * (p13 - p14);

    p0 = pp0 + pp1;
    p1 = cos1_4 * (pp0 - pp1);
    p2 = pp2 + pp3;
    p3 = cos1_4 * (pp2 - pp3);
    p4 = pp4 + pp5;
    p5 = cos1_4 * (pp4 - pp5);
    p6 = pp6 + pp7;
    p7 = cos1_4 * (pp6 - pp7);
    p8 = pp8 + pp9;
    p9 = cos1_4 * (pp8 - pp9);
    p10= pp10 + pp11;
    p11= cos1_4 * (pp10 - pp11);
    p12= pp12 + pp13;
    p13= cos1_4 * (pp12 - pp13);
    p14= pp14 + pp15;
    p15= cos1_4 * (pp14 - pp15);

    tmp              = p6 + p7;
    bufOffsetPtr[36] = -(p5 + tmp);
    bufOffsetPtr[44] = -(p4 + tmp);
    tmp              = p11 + p15;
    bufOffsetPtr[10] = tmp;
    bufOffsetPtr[6]  = p13 + tmp;
    tmp              = p14 + p15;
    bufOffsetPtr[46] = -(p8  + p12 + tmp);
    bufOffsetPtr[34] = -(p9  + p13 + tmp);
    tmp             += p10 + p11;
    bufOffsetPtr[38] = -(p13 + tmp);
    bufOffsetPtr[42] = -(p12 + tmp);
    bufOffsetPtr[2]  = p9 + p13 + p15;
    bufOffsetPtr[4]  = p5 + p7;
    bufOffsetPtr[48] = -p0;
    bufOffsetPtr[0]  = p1;
    bufOffsetPtr[8]  = p3;
    bufOffsetPtr[12] = p7;
    bufOffsetPtr[14] = p15;
    bufOffsetPtr[40] = -(p2  + p3);

    p0  = cos1_64  * (bandPtr[0] - bandPtr[31]);
    p1  = cos3_64  * (bandPtr[1] - bandPtr[30]);
    p2  = cos5_64  * (bandPtr[2] - bandPtr[29]);
    p3  = cos7_64  * (bandPtr[3] - bandPtr[28]);
    p4  = cos9_64  * (bandPtr[4] - bandPtr[27]);
    p5  = cos11_64 * (bandPtr[5] - bandPtr[26]);
    p6  = cos13_64 * (bandPtr[6] - bandPtr[25]);
    p7  = cos15_64 * (bandPtr[7] - bandPtr[24]);
    p8  = cos17_64 * (bandPtr[8] - bandPtr[23]);
    p9  = cos19_64 * (bandPtr[9] - bandPtr[22]);
    p10 = cos21_64 * (bandPtr[10]- bandPtr[21]);
    p11 = cos23_64 * (bandPtr[11]- bandPtr[20]);
    p12 = cos25_64 * (bandPtr[12]- bandPtr[19]);
    p13 = cos27_64 * (bandPtr[13]- bandPtr[18]);
    p14 = cos29_64 * (bandPtr[14]- bandPtr[17]);
    p15 = cos31_64 * (bandPtr[15]- bandPtr[16]);

    pp0 = p0 + p15;
    pp1 = p1 + p14;
    pp2 = p2 + p13;
    pp3 = p3 + p12;
    pp4 = p4 + p11;
    pp5 = p5 + p10;
    pp6 = p6 + p9;
    pp7 = p7 + p8;
    pp8 = cos1_32  * (p0 - p15);
    pp9 = cos3_32  * (p1 - p14);
    pp10= cos5_32  * (p2 - p13);
    pp11= cos7_32  * (p3 - p12);
    pp12= cos9_32  * (p4 - p11);
    pp13= cos11_32 * (p5 - p10);
    pp14= cos13_32 * (p6 - p9);
    pp15= cos15_32 * (p7 - p8);

    p0 = pp0 + pp7;
    p1 = pp1 + pp6;
    p2 = pp2 + pp5;
    p3 = pp3 + pp4;
    p4 = cos1_16 * (pp0 - pp7);
    p5 = cos3_16 * (pp1 - pp6);
    p6 = cos5_16 * (pp2 - pp5);
    p7 = cos7_16 * (pp3 - pp4);
    p8 = pp8  + pp15;
    p9 = pp9  + pp14;
    p10= pp10 + pp13;
    p11= pp11 + pp12;
    p12= cos1_16 * (pp8  - pp15);
    p13= cos3_16 * (pp9  - pp14);
    p14= cos5_16 * (pp10 - pp13);
    p15= cos7_16 * (pp11 - pp12);

    pp0 = p0 + p3;
    pp1 = p1 + p2;
    pp2 = cos1_8 * (p0 - p3);
    pp3 = cos3_8 * (p1 - p2);
    pp4 = p4 + p7;
    pp5 = p5 + p6;
    pp6 = cos1_8 * (p4 - p7);
    pp7 = cos3_8 * (p5 - p6);
    pp8 = p8 + p11;
    pp9 = p9 + p10;
    pp10= cos1_8 * (p8 - p11);
    pp11= cos3_8 * (p9 - p10);
    pp12= p12 + p15;
    pp13= p13 + p14;
    pp14= cos1_8 * (p12 - p15);
    pp15= cos3_8 * (p13 - p14);

    p0 = pp0 + pp1;
    p1 = cos1_4 * (pp0 - pp1);
    p2 = pp2 + pp3;
    p3 = cos1_4 * (pp2 - pp3);
    p4 = pp4 + pp5;
    p5 = cos1_4 * (pp4 - pp5);
    p6 = pp6 + pp7;
    p7 = cos1_4 * (pp6 - pp7);
    p8 = pp8 + pp9;
    p9 = cos1_4 * (pp8 - pp9);
    p10= pp10 + pp11;
    p11= cos1_4 * (pp10 - pp11);
    p12= pp12 + pp13;
    p13= cos1_4 * (pp12 - pp13);
    p14= pp14 + pp15;
    p15= cos1_4 * (pp14 - pp15);

    tmp              = p13 + p15;
    bufOffsetPtr[1]  = p1 + p9 + tmp;
    bufOffsetPtr[5]  = p5 + p7 + p11 + tmp;
    tmp             += p9;
    bufOffsetPtr[33] = -(p1 + p14 + tmp);
    tmp             += p5 + p7;
    bufOffsetPtr[3]  = tmp;
    bufOffsetPtr[35] = -(p6 + p14 + tmp);
    tmp              = p10 + p11 + p12 + p13 + p14 + p15;
    bufOffsetPtr[39] = -(p2 + p3 + tmp - p12);
    bufOffsetPtr[43] = -(p4 + p6 + p7 + tmp - p13);
    bufOffsetPtr[37] = -(p5 + p6 + p7 + tmp - p12);
    bufOffsetPtr[41] = -(p2 + p3 + tmp - p13);
    tmp              = p8 + p12 + p14 + p15;
    bufOffsetPtr[47] = -(p0 + tmp);
    bufOffsetPtr[45] = -(p4 + p6 + p7 + tmp);
    tmp              = p11 + p15;
    bufOffsetPtr[11] = p7  + tmp;
    tmp             += p3;
    bufOffsetPtr[9]  = tmp;
    bufOffsetPtr[7]  = p13 + tmp;
    bufOffsetPtr[13] = p7 + p15;
    bufOffsetPtr[15] = p15;

    bufOffsetPtr[16] = 0.0;
    for (i = 0; i < 16; i++) {
	bufOffsetPtr[32-i] = -bufOffsetPtr[i];
	bufOffsetPtr[63-i] = bufOffsetPtr[33+i];
    }
  }

# endif /* OPTIMIZE_093 & OPTIMIZE_095 */

#else /* original code */

    for (i = 0; i < 64; i++) {
	sum = 0.0;
	for (k = 0; k < 32; k++)
	    sum += bandPtr[k] * (*filter)[i][k];
	bufOffsetPtr[i] = sum;
    }
#endif /* OPTIMIZE */


# if OPTIMIZE_095 /* code in version 0.9.5 and earlier */

#  ifdef DETECT_CLIP
    /* Detects and "smooths" clipping
     *
     *  S(i,j) = D(j+32i) * U(j+32i+((i+1)>>1)*64)
     *  samples(i,j) = MWindow(j+32i) * bufPtr(j+32i+((i+1)>>1)*64)
     */

    for (j = 0; j < 32; j++) {	/* for each subband... */
	offset = bufOffset + j;
	/*
	 * -1.144989014 <= window[x] <= 1.144989014  for all x
	 */
	sum = window[j] * (*buf)[offset] +
	    window[j + 32] * (*buf)[(96 + offset) & 0x3ff] +
	    window[j + 64] * (*buf)[(128 + offset) & 0x3ff] +
	    window[j + 96] * (*buf)[(224 + offset) & 0x3ff] +
	    window[j + 128] * (*buf)[(256 + offset) & 0x3ff] +
	    window[j + 160] * (*buf)[(352 + offset) & 0x3ff] +
	    window[j + 192] * (*buf)[(384 + offset) & 0x3ff] +
	    window[j + 224] * (*buf)[(480 + offset) & 0x3ff] +
	    window[j + 256] * (*buf)[(512 + offset) & 0x3ff] +
	    window[j + 288] * (*buf)[(608 + offset) & 0x3ff] +
	    window[j + 320] * (*buf)[(640 + offset) & 0x3ff] +
	    window[j + 352] * (*buf)[(736 + offset) & 0x3ff] +
	    window[j + 384] * (*buf)[(768 + offset) & 0x3ff] +
	    window[j + 416] * (*buf)[(864 + offset) & 0x3ff] +
	    window[j + 448] * (*buf)[(896 + offset) & 0x3ff] +
	    window[j + 480] * (*buf)[(992 + offset) & 0x3ff];

	/*
	 * At this point we hope we have -1 <= sum <= 1 otherwise, it'll
	 * have to be clipped anyway, so it's no big deal to clip it earlier
	 * or something.
	 */

	/*
	 * Casting truncates towards zero for both positive and negative
	 * numbers, the result is cross-over distortion,  1995-07-12 shn
	 */

	if (sum > 0) {
	    foo = (long)(sum * SCALE + 0.5);
	} else {
	    foo = (long)(sum * SCALE - 0.5);
	} 

	if (foo >= (long)SCALE) {
	    samples[j] = (short)(SCALE-1);
	    ++clip;
	} else if (foo < (long)-SCALE) {
	    samples[j] = (short)(-SCALE);
	    ++clip;
	} else
	    samples[j] = (short)foo;
    }

#  else /* !DETECT_CLIP */

    /* Faster, but does not detect clipping
     *
     *  S(i,j) = D(j+32i) * U(j+32i+((i+1)>>1)*64)
     *  samples(i,j) = MWindow(j+32i) * bufPtr(j+32i+((i+1)>>1)*64)
     */
    for (j = 0; j < 32; j++) {
	sum = 0.0;

	for (i = 0; i < 16; i++) {
	    k = j + (i << 5);
	    sum += window[k] * (*buf)[((k + (((i+1) >> 1) << 6)) + bufOffset) & 0x3ff];
	}
	samples[j] = sum * SCALE;
    }

#  endif /* DETECT_CLIP */

# else /* most optimized */

  {
    REAL* dt[16];
    for (i = 0; i < 16; i++) {
	k = (i << 5);
	dt[i]=(*buf) + ( ((k + (((i+1) >> 1) << 6)) +
				bufOffset) & 0x3ff);
    }

    for (j = 0; j < 32; j++) {
	/* Unroll loop
	 * Here we multiply every subband by the appropriate scale
	 * factor and add 'em all up, so we get one sample.
	 */
	sum =
	    window[j] * dt[0][j]+
	    window[j + 32] * dt[1][j]+
	    window[j + 64] * dt[2][j]+
	    window[j + 96] * dt[3][j]+
	    window[j + 128] * dt[4][j]+
	    window[j + 160] * dt[5][j]+
	    window[j + 192] * dt[6][j]+
	    window[j + 224] * dt[7][j]+
	    window[j + 256] * dt[8][j]+
	    window[j + 288] * dt[9][j]+
	    window[j + 320] * dt[10][j]+
	    window[j + 352] * dt[11][j]+
	    window[j + 384] * dt[12][j]+
	    window[j + 416] * dt[13][j]+
	    window[j + 448] * dt[14][j]+
	    window[j + 480] * dt[15][j];
	  
	/*foo = floor(sum * SCALE);*/
	if (sum > 0) {
	    foo = (long)(sum * SCALE + 0.5);
	} else {
	    foo = (long)(sum * SCALE - 0.5);
	} 
	
#  ifdef DETECT_CLIP
	if (foo >= (long)SCALE) {
	    samples[j] = (short)(SCALE-1);
	    ++clip;
	} else if (foo < (long)-SCALE) {
	    samples[j] = (short)(-SCALE);
	    ++clip;
	} else
#  endif
	  samples[j] = foo;
      }
    }

# endif /* OPTIMIZE_095 */

    return clip;
}

#else /* INT_MATH */

int SubBandSynthesis(
    REAL	*bandPtr,
    short	*samples)
{
    int			 i, j, k;
    int			 sum;
    int			*bufOffsetPtr;
    static int		 init = 1;
    typedef REAL	 RNN[64][32];
    static RNN FAR	*Rfilter;
    typedef int		 NN[64][32];
    static NN FAR	*filter;
    typedef int		 BB[2*HAN_SIZE];
    static BB FAR	*buf;
    static int		 bufOffset = 64;
    static int		*window;
    static REAL FAR	*realWindow;
    int			 clip = 0;   /* count & return # samples clipped */
    long		 foo;
    int			 offset;
    int			*filterp;
    REAL		*bandp;

    if (init == 1) {
	buf = (BB FAR *) mem_alloc(sizeof(BB),"BB");

	filter = (NN FAR *) mem_alloc(sizeof(NN), "NN");
	Rfilter = (RNN FAR *) mem_alloc(sizeof(RNN), "RNN");
	create_syn_filter(*Rfilter);
	for (i = 0; i < 64; i++) {
	    for (j = 0; j < 32; j++) {
		(*filter)[i][j] = (*Rfilter)[i][j] * 32768;
	    }
	}

	window = (int *) mem_alloc(sizeof(int) * HAN_SIZE, "WIN");
	realWindow = (REAL FAR *) mem_alloc(sizeof(REAL FAR) * HAN_SIZE, "WIN");
	read_syn_window(realWindow);
	/*
	 * Let's now convert those nasty REALs to nice 'n fast ints.
	 * This should really be done in read_syn_window() but for now this
	 * at least keeps all the bugs in one place.
	 */
	for (i = 0; i < HAN_SIZE; i++) {
	    window[i] = realWindow[i] * 32768;
	}

	init = 0;
    }

    bufOffset = (bufOffset - 64) & 0x3ff;
    bufOffsetPtr = &((*buf)[bufOffset]);

    filterp = (int *)((*filter)[0]);
    bandp = bandPtr;

    i = 64;

    while (i--) {
	/*
	 * -1 <= filter <= 1
	 */
	*bufOffsetPtr++ =
	    bandp[0] * filterp[0] +
	    bandp[1] * filterp[1] +
	    bandp[2] * filterp[2] +
	    bandp[3] * filterp[3] +
	    bandp[4] * filterp[4] +
	    bandp[5] * filterp[5] +
	    bandp[6] * filterp[6] +
	    bandp[7] * filterp[7] +
	    bandp[8] * filterp[8] +
	    bandp[9] * filterp[9] +
	    bandp[10] * filterp[10] +
	    bandp[11] * filterp[11] +
	    bandp[12] * filterp[12] +
	    bandp[13] * filterp[13] +
	    bandp[14] * filterp[14] +
	    bandp[15] * filterp[15] +
	    bandp[16] * filterp[16] +
	    bandp[17] * filterp[17] +
	    bandp[18] * filterp[18] +
	    bandp[19] * filterp[19] +
	    bandp[20] * filterp[20] +
	    bandp[21] * filterp[21] +
	    bandp[22] * filterp[22] +
	    bandp[23] * filterp[23] +
	    bandp[24] * filterp[24] +
	    bandp[25] * filterp[25] +
	    bandp[26] * filterp[26] +
	    bandp[27] * filterp[27] +
	    bandp[28] * filterp[28] +
	    bandp[29] * filterp[29] +
	    bandp[30] * filterp[30] +
	    bandp[31] * filterp[31];
	filterp += 32;
    }

    /* Detects and "smooths" clipping
     *
     *  S(i,j) = D(j+32i) * U(j+32i+((i+1)>>1)*64)
     *  samples(i,j) = MWindow(j+32i) * bufPtr(j+32i+((i+1)>>1)*64)
     */

    for (j = 0; j < 32; j++) {	/* for each subband... */
	offset = bufOffset + j;
	sum =
	   (window[j] * (*buf)[offset] +
	    window[j + 32] * (*buf)[(96 + offset) & 0x3ff] +
	    window[j + 64] * (*buf)[(128 + offset) & 0x3ff] +
	    window[j + 96] * (*buf)[(224 + offset) & 0x3ff] +
	    window[j + 128] * (*buf)[(256 + offset) & 0x3ff] +
	    window[j + 160] * (*buf)[(352 + offset) & 0x3ff] +
	    window[j + 192] * (*buf)[(384 + offset) & 0x3ff] +
	    window[j + 224] * (*buf)[(480 + offset) & 0x3ff] +
	    window[j + 256] * (*buf)[(512 + offset) & 0x3ff] +
	    window[j + 288] * (*buf)[(608 + offset) & 0x3ff] +
	    window[j + 320] * (*buf)[(640 + offset) & 0x3ff] +
	    window[j + 352] * (*buf)[(736 + offset) & 0x3ff] +
	    window[j + 384] * (*buf)[(768 + offset) & 0x3ff] +
	    window[j + 416] * (*buf)[(864 + offset) & 0x3ff] +
	    window[j + 448] * (*buf)[(896 + offset) & 0x3ff] +
	    window[j + 480] * (*buf)[(992 + offset) & 0x3ff]) / 32768;

	/*
	 * Casting truncates towards zero for both positive and negative
	 * numbers, the result is cross-over distortion,  1995-07-12 shn
	 */

	if (sum >= (long)SCALE) {
	    samples[j] = (short)(SCALE-1);
	    ++clip;
	} else if (sum < (long)-SCALE) {
	    samples[j] = (short)(-SCALE);
	    ++clip;
	} else
	    samples[j] = (short)sum;
    }

    return clip;
}

#endif /* INT_MATH */


