/**********************************************************************
Copyright (c) 1991 MPEG/audio software simulation group, All Rights Reserved
decode.c
**********************************************************************/
/**********************************************************************
 * MPEG/audio coding/decoding software, work in progress              *
 *   NOT for public distribution until verified and approved by the   *
 *   MPEG/audio committee.  For further information, please contact   *
 *   Chad Fogg email: <cfogg@xenon.com>                               *
 *                                                                    *
 * VERSION 4.1                                                        *
 *   changes made since last update:                                  *
 *   date   programmers         comment                               *
 * 2/25/91  Douglas Wong,       start of version 1.0 records          *
 *          Davis Pan                                                 *
 * 3/06/91  Douglas Wong        rename: setup.h to dedef.h            *
 *                                      dfilter to defilter           *
 *                                      dwindow to dewindow           *
 *                              integrated "quantizer", "scalefactor" *
 *                              combined window_samples routine into  *
 *                              filter samples                        *
 * 3/31/91  Bill Aspromonte     replaced read_filter by               *
 *                              create_syn_filter and introduced a    *
 *                              new Sub-Band Synthesis routine called *
 *                              SubBandSynthesis()                    *
 * 5/10/91  Vish (PRISM)        Ported to Macintosh and Unix.         *
 *                              Changed "out_fifo()" so that last     *
 *                              unfilled block is also written out.   *
 *                              "create_syn_filter()" was modified so *
 *                              that calculation precision is same as *
 *                              in specification tables.              *
 *                              Changed "decode_scale()" to reflect   *
 *                              specifications.                       *
 *                              Removed all routines used by          *
 *                              "synchronize_buffer()".  This is now  *
 *                              replaced by "seek_sync()".            *
 *                              Incorporated Jean-Georges Fritsch's   *
 *                              "bitstream.c" package.                *
 *                              Deleted "reconstruct_sample()".       *
 * 27jun91  dpwe (Aware)        Passed outFile and &sampFrames as     *
 *                              args to out_fifo() - were global.     *
 *                              Moved "alloc_*" reader to common.c.   *
 *                              alloc, sblimit, stereo passed via new *
 *                              'frame_params struct (were globals).  *
 *                              Added JOINT STEREO decoding, lyrs I&II*
 *                              Affects: decode_bitalloc,buffer_samps *
 *                              Plus a few other cleanups.            *
 * 6/10/91   Earle Jennings     conditional expansion added in        *
 *                              II_dequantize_sample to handle range  *
 *                              problems in MSDOS version             *
 * 8/8/91    Jens Spille        Change for MS-C6.00                   *
 *10/1/91    S.I. Sudharsanan,  Ported to IBM AIX platform.           *
 *           Don H. Lee,                                              *
 *           Peter W. Farrett                                         *
 *10/3/91    Don H. Lee         implemented CRC-16 error protection   *
 *                              newly introduced functions are        *
 *                              buffer_CRC and recover_CRC_error.     *
 * 2/11/92  W. Joseph Carter    Ported new code to Macintosh.  Most   *
 *                              important fixes involved changing     *
 *                              16-bit ints to long or unsigned in    *
 *                              bit alloc routines for quant of 65535 *
 *                              and passing proper function args.     *
 *                              Removed "Other Joint Stereo" option   *
 *                              and made bitrate be total channel     *
 *                              bitrate, irrespective of the mode.    *
 *                              Fixed many small bugs & reorganized.  *
 * 7/27/92  Juan Pineda         Bug fix in SubBandSynthesis()         *
 *--------------------------------------------------------------------*
 * 6/14/92  Juan Pineda         Layer III decoding routines added.    *
 *          Amit Gulati         Follows CD 3-11172 rev2.  Contains    *
 *                              hacks deal with evolving available    *
 *                              layerIII bitstreams.  Some (minor)    *
 *                              modification of prior LI&II code.     *
 * 10/25/92 Amit Gulati         Updated layerIII routines. Added code *
 *                              for subblock_gain, switched block     *
 *                              modes, stereo pre-processing.         *
 *                              Corrected sign bits for huffman       *
 *                              decoding of quadruples region and     *
 *                              adjusted gain factor in III_dequant.  *
 * 11/21/92 Amit Gulati         Several layerIII bugs fixed.          *
 * 12/15/92 Amit Gulati         Corrected reordering (indexing)       *
 *          Stan Searing        within IMDCT routine.                 *
 *  8/24/93 Masahiro Iwadare    Included IS modification in Layer III.*
 *                              Changed for 1 pass decoding.          *
 *  9/07/93 Toshiyuki Ishino    Integrated Layer III with Ver 3.9.    *
 *--------------------------------------------------------------------*
 * 11/20/93 Masahiro Iwadare    Integrated Layer III with Ver 4.0.    *
 *--------------------------------------------------------------------*
 *  7/14/94 Juergen Koller      Bug fixes in Layer III code           *
 *--------------------------------------------------------------------*
 *  1/15/02 Christopher Andrews Cleaned up for 545 project usage:     *
 *                              Removed all support for other layers  *
 *                              and other platforms                   *
 **********************************************************************/

#include        "common.h"
#include        "decoder.h"
#include        "huffman.h"
#include        "dewindow.h"
#include        "filter.h"
#include        "COS.h"
#include        "imdct_window.h"

void decode_info(bs, fr_ps)
     Bit_stream_struc *bs;
     frame_params *fr_ps;
{
  short got;
  layer *hdr = fr_ps->header;
  
  got = get1bit(bs);
  hdr->version = got;
  got = getbits(bs,2l);
  hdr->lay = 4l-got;
  got = get1bit(bs);
  hdr->error_protection = !got; /* error protect. TRUE/FALSE */
  got = getbits(bs,4l);
  hdr->bitrate_index = got;
  hdr->sampling_frequency = getbits(bs,2);
  hdr->padding = get1bit(bs);
  hdr->extension = get1bit(bs);
  hdr->mode = getbits(bs,2);
  hdr->mode_ext = getbits(bs,2);
  hdr->copyright = get1bit(bs);
  hdr->original = get1bit(bs);
  hdr->emphasis = getbits(bs,2);
}



/************************* Layer III routines **********************/

void III_get_side_info(bs, si, fr_ps)
     Bit_stream_struc *bs;
     III_side_info_t *si;
     frame_params *fr_ps;
{
  int ch, gr, i;
  int stereo = fr_ps->stereo;
  struct gr_info_s *gi_temp;
   
  si->main_data_begin = getbits(bs, 9);

   
  if (stereo == 1)
    si->private_bits = getbits(bs,5);
  else si->private_bits = getbits(bs,3);



  for (ch=0; ch<stereo; ch++)
    for (i=0; i<4; i++)
      si->ch[ch].scfsi[i] = get1bit(bs);


  for (gr=0; gr<2; gr++) {
    for (ch=0; ch<stereo; ch++) {
      gi_temp = &(si->ch[ch].gr[gr]);
      gi_temp->part2_3_length = getbits(bs, 12);
      gi_temp->big_values = getbits(bs, 9);
      gi_temp->global_gain = getbits(bs, 8);
      gi_temp->scalefac_compress = getbits(bs, 4);
      gi_temp->window_switching_flag = get1bit(bs);

      if (gi_temp->window_switching_flag) {
	gi_temp->block_type = getbits(bs, 2);

	gi_temp->mixed_block_flag = get1bit(bs);

	for (i=0; i<2; i++)
	  gi_temp->table_select[i] = getbits(bs, 5);

	for (i=0; i<3; i++)
	  gi_temp->subblock_gain[i] = getbits(bs, 3);

               
	/* Set region_count parameters since they are implicit in this case. */
            
	if (gi_temp->block_type == 0) {
#ifdef PLATFORM_UNIX
	  printf("Side info bad: block_type == 0 in split block.\n");
#endif
	  exit(0);
	}
	else if (gi_temp->block_type == 2
		 && gi_temp->mixed_block_flag == 0)
	  gi_temp->region0_count = 8; /* MI 9; */
	else gi_temp->region0_count = 7; /* MI 8; */
	gi_temp->region1_count = 20 -
	  gi_temp->region0_count;
                                      
      }
      else {
	for (i=0; i<3; i++)
	  gi_temp->table_select[i] = getbits(bs, 5);
	gi_temp->region0_count = getbits(bs, 4);
	gi_temp->region1_count = getbits(bs, 3);
	gi_temp->block_type = 0;
      }      
      gi_temp->preflag = get1bit(bs);
      gi_temp->scalefac_scale = get1bit(bs);
      gi_temp->count1table_select = get1bit(bs);
    }
  }
}


struct {
  int l[5];
  int s[3];} sfbtable = {{0, 6, 11, 16, 21},
			 {0, 6, 12}};
                         
int slen[2][16] = {{0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4},
                   {0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3}};
typedef struct  {
  int l[23];
  int s[14];
} sfBandIndex_t;
sfBandIndex_t sfBandIndex[3] =   
  {{{0,4,8,12,16,20,24,30,36,44,52,62,74,90,110,134,162,196,238,288,342,418,576},
    {0,4,8,12,16,22,30,40,52,66,84,106,136,192}},
   {{0,4,8,12,16,20,24,30,36,42,50,60,72,88,106,128,156,190,230,276,330,384,576},
    {0,4,8,12,16,22,28,38,50,64,80,100,126,192}},
   {{0,4,8,12,16,20,24,30,36,44,54,66,82,102,126,156,194,240,296,364,448,550,576},
    {0,4,8,12,16,22,30,42,58,78,104,138,180,192}}};


void III_get_scale_factors(scalefac, si, gr, ch, fr_ps)
     III_scalefac_t *scalefac;
     III_side_info_t *si;
     int gr, ch;
     frame_params *fr_ps;
{
  int sfb, i, window;
  struct gr_info_s *gr_info = &(si->ch[ch].gr[gr]);

  if (gr_info->window_switching_flag && (gr_info->block_type == 2)) { 
    if (gr_info->mixed_block_flag) { /* MIXED */ /* NEW - ag 11/25 */
      for (sfb = 0; sfb < 8; sfb++)
	(*scalefac)[ch].l[sfb] = hgetbits( 
					  slen[0][gr_info->scalefac_compress]);
      for (sfb = 3; sfb < 6; sfb++)
	for (window=0; window<3; window++)
	  (*scalefac)[ch].s[window][sfb] = hgetbits(
						    slen[0][gr_info->scalefac_compress]);
      for (sfb = 6; sfb < 12; sfb++)
	for (window=0; window<3; window++)
	  (*scalefac)[ch].s[window][sfb] = hgetbits(
						    slen[1][gr_info->scalefac_compress]);
      for (sfb=12,window=0; window<3; window++)
	(*scalefac)[ch].s[window][sfb] = 0;
    }
    else {  /* SHORT*/
      for (i=0; i<2; i++) 
	for (sfb = sfbtable.s[i]; sfb < sfbtable.s[i+1]; sfb++)
	  for (window=0; window<3; window++)
	    (*scalefac)[ch].s[window][sfb] = hgetbits( 
						      slen[i][gr_info->scalefac_compress]);
      for (sfb=12,window=0; window<3; window++)
	(*scalefac)[ch].s[window][sfb] = 0;
    }
  }          
  else {   /* LONG types 0,1,3 */
    for (i=0; i<4; i++) {
      if ((si->ch[ch].scfsi[i] == 0) || (gr == 0))
	for (sfb = sfbtable.l[i]; sfb < sfbtable.l[i+1]; sfb++)
	  {
	    (*scalefac)[ch].l[sfb] = 
	      hgetbits( slen[(i<2)?0:1][gr_info->scalefac_compress]);
	  }
    }
    (*scalefac)[ch].l[22] = 0; 
  }
}


void III_hufman_decode(is, si, ch, gr, part2_start, fr_ps)
     short is[SBLIMIT][SSLIMIT];
     III_side_info_t *si;
     int gr, ch, part2_start;
     frame_params *fr_ps;
{
  int i, x, y;
  int v, w;
  struct huffcodetab *h;
  int region1Start;
  int region2Start;

  /* Find region boundary for short block case. */
   
  if ( ((*si).ch[ch].gr[gr].window_switching_flag) && 
       ((*si).ch[ch].gr[gr].block_type == 2) ) { 
   
    /* Region2. */

    region1Start = 36;  /* sfb[9/3]*3=36 */
    region2Start = 576; /* No Region2 for short block case. */
  }


  else {          /* Find region boundary for long block case. */

    region1Start = sfBandIndex[fr_ps->header->sampling_frequency]
      .l[(*si).ch[ch].gr[gr].region0_count + 1]; /* MI */
    region2Start = sfBandIndex[fr_ps->header->sampling_frequency]
      .l[(*si).ch[ch].gr[gr].region0_count +
	(*si).ch[ch].gr[gr].region1_count + 2]; /* MI */
  }


  /* Read bigvalues area. */
  for (i=0; i<(*si).ch[ch].gr[gr].big_values*2; i+=2) {
    if      (i<region1Start) h = &ht[(*si).ch[ch].gr[gr].table_select[0]];
    else if (i<region2Start) h = &ht[(*si).ch[ch].gr[gr].table_select[1]];
    else                h = &ht[(*si).ch[ch].gr[gr].table_select[2]];
    huffman_decoder(h, &x, &y, &v, &w);
    is[i/SSLIMIT][i%SSLIMIT] = x;
    is[(i+1)/SSLIMIT][(i+1)%SSLIMIT] = y;
  }

  /* Read count1 area. */
  h = &ht[(*si).ch[ch].gr[gr].count1table_select+32];
  while ((hsstell() < part2_start + (*si).ch[ch].gr[gr].part2_3_length ) &&
	 ( i < SSLIMIT*SBLIMIT )) {
    huffman_decoder(h, &x, &y, &v, &w);
    is[i/SSLIMIT][i%SSLIMIT] = v;
    is[(i+1)/SSLIMIT][(i+1)%SSLIMIT] = w;
    is[(i+2)/SSLIMIT][(i+2)%SSLIMIT] = x;
    is[(i+3)/SSLIMIT][(i+3)%SSLIMIT] = y;
    i += 4;
  }

  if (hsstell() > part2_start + (*si).ch[ch].gr[gr].part2_3_length)
    {  i -=4;
    rewindNbits(hsstell()-part2_start - (*si).ch[ch].gr[gr].part2_3_length);
    }

  /* Dismiss stuffing Bits */
  if ( hsstell() < part2_start + (*si).ch[ch].gr[gr].part2_3_length )
    hgetbits( part2_start + (*si).ch[ch].gr[gr].part2_3_length - hsstell());

  /* Zero out rest. */
  for (; i<SSLIMIT*SBLIMIT; i++)
    is[i/SSLIMIT][i%SSLIMIT] = 0;
}


short POW43(long int in)
{   
  if (in < 2)
    return in * 1;
  if (in < 6)
    return in * 1;
  if (in < 18)
    return in * 2;
  if (in < 46)
    return in * 3;
  if (in < 95)
    return in * 4;
  if (in < 171)
    return in * 5;
  if (in < 280)
    return in * 6;
  if (in < 428)
    return in * 7;
  if (in < 621)
    return in * 8;
  if (in < 865)
    return in * 9;
  if (in < 1166)
    return in * 10;
  if (in < 1530)
    return in * 11;
  if (in < 1963)
    return in * 12;
  if (in < 2471)
    return in * 13;
  if (in < 3060)
    return in * 14;
  if (in < 3736)
    return in * 15;
  if (in < 4505)
    return in * 16;
  if (in < 5373)
    return in * 17;
  if (in < 6346)
    return in * 18;
  if (in < 7430)
    return in * 19;
  if (in <= 8000)
    return in * 20;
}

int pretab[22] = {0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,3,3,3,2,0};

short EXTRAS[4] = {(short)(1.0000 * EXTRA_SCALE), (short)(1.1892 * EXTRA_SCALE), 
		   (short)(1.4142 * EXTRA_SCALE), (short)(1.6818 * EXTRA_SCALE)};

void III_dequantize_sample(is,xr,scalefac,gr_info, ch,fr_ps)
     short is[SBLIMIT][SSLIMIT];
     short xr[SBLIMIT][SSLIMIT];
     struct gr_info_s *gr_info;
     III_scalefac_t *scalefac;
     frame_params *fr_ps;
     int ch;
{
  int ss,sb,cb=0,sfreq=fr_ps->header->sampling_frequency;
  //  int stereo = fr_ps->stereo;
  int next_cb_boundary, cb_begin, cb_width, sign;

  int *bi_s = sfBandIndex[sfreq].s;
  int *bi_l = sfBandIndex[sfreq].l;

  //ADDED VARIABLES FOR HACKING POW
  short main, x, extra;


  /* choose correct scalefactor band per block type, initalize boundary */

  if (gr_info->window_switching_flag && (gr_info->block_type == 2) )
    if (gr_info->mixed_block_flag) 
      next_cb_boundary=bi_l[1];  /* LONG blocks: 0,1,3 */
    else {
      next_cb_boundary=bi_s[1]*3; /* pure SHORT block */
      cb_width = bi_s[1];
      cb_begin = 0;
    }  
  else 
    next_cb_boundary=bi_l[1];  /* LONG blocks: 0,1,3 */

  /* apply formula per block type */

  for (sb=0 ; sb < SBLIMIT ; sb++)
    for (ss=0 ; ss < SSLIMIT ; ss++) {

      if ( (sb*18)+ss == next_cb_boundary)  { /* Adjust critical band boundary */
	if (gr_info->window_switching_flag && (gr_info->block_type == 2)) {
	  if (gr_info->mixed_block_flag)  {
	    if (((sb*18)+ss) == bi_l[8])  {
	      next_cb_boundary=bi_s[4]*3; 
	      cb = 3;
	      cb_width = bi_s[cb+1] - bi_s[cb];
	      cb_begin = bi_s[cb]*3;      
	    }
	    else if (((sb*18)+ss) < bi_l[8]) 
	      next_cb_boundary = bi_l[(++cb)+1];
	    else {
	      next_cb_boundary = bi_s[(++cb)+1]*3;
	      cb_width = bi_s[cb+1] - bi_s[cb];
	      cb_begin = bi_s[cb]*3;      
	    }   
	  }
	  else  {
	    next_cb_boundary = bi_s[(++cb)+1]*3;
	    cb_width = bi_s[cb+1] - bi_s[cb];
	    cb_begin = bi_s[cb]*3;      
	  } 
	}
	else /* long blocks */
	  {
	    next_cb_boundary = bi_l[(++cb)+1];
	  }
	
      }

      /* Compute overall (global) scaling. */

      //things will eventually come out to the form: 2 ^ ( - (x >>2)) * 2 ^ (-0.25 * (x & 0x3))
      //we will call the (x >> 2) term the "main" term...and the (x & 0x3) term the "extra" term

      //xr[sb][ss] = DEQ_SCALE *  pow( 2.0 , (0.25 * (gr_info->global_gain - 210.0)));
      //NOTE: x is a TEMP variable! It doesn't matter if it's dumped after each of the phases...=d
      //NOTE: NEED TO MAKE SURE THAT ANY CONSTANT FP OPS ARE GONE!!! >:O
      
      x =  210 - gr_info->global_gain;
      
      if(x > 0)
	{
	  extra = x & 0x3;
	  main = x >> 2;
	}
      else
	{
	  x = -x;
	  extra = x & 0x3;
	  main = x >> 2;	  
	}
      
      if(main < 12)
	{
	  x = 1l << (long)(12 - main);
	  x = (x << 10l)/EXTRAS[extra];
	  xr[sb][ss] = x;
	}
      else 
	xr[sb][ss] = 0;
      
      /* Do long/short dependent scaling operations. */
      
      if (gr_info->window_switching_flag && (
					     ((gr_info->block_type == 2) && (gr_info->mixed_block_flag == 0)) ||
					     ((gr_info->block_type == 2) && gr_info->mixed_block_flag && (sb >= 2)) )) {
	
	//xr[sb][ss] *=  pow(2.0, 0.25 * -8.0 * 
	//		   gr_info->subblock_gain[(((sb*18)+ss) - cb_begin)/cb_width]);
	// NOTE: 0.25 * 8 = 2, which means that you do a left shift instead of doing the actual mult...=o

	x = gr_info->subblock_gain[(((sb*18)+ss) - cb_begin)/cb_width];

	if(x > 0)
	  {
	    extra = x & 0x3;
	    main = x >> 1;
	  }
	else
	  {
	    x = -x;
	    extra = x & 0x3;
	    main = x >> 1;	  
	  }

	if(main < 8)
	  {
	    x = 1 << (8 - main);
	    x = (x << 10l)/EXTRAS[extra];
	    xr[sb][ss] *= x;
	  }
	else 
	  xr[sb][ss] = 0;

	xr[sb][ss] /= 256;

	//xr[sb][ss] *=  pow(2.0, 0.25 * -2.0 * (1.0+gr_info->scalefac_scale)
	//		   * (*scalefac)[ch].s[(((sb*18)+ss) - cb_begin)/cb_width][cb]);
	//NOTE: 0.25 * 2 = 1/2, which means that you right shift instead of doing the divide...=o
	
	x = (1 + gr_info->scalefac_scale) * (*scalefac)[ch].s[(((sb*18)+ss) - cb_begin)/cb_width][cb];

	if(x > 0)
	  {
	    extra = x & 0x3;
	    main = x >> 1;
	  }
	else
	  {
	    x = -x;
	    extra = x & 0x3;
	    main = x >> 1;	  
	  }

	if(main < 8)
	  {
	    x = 1 << (long)(8l - main);
	    x = (x << 10l)/EXTRAS[extra];
	    xr[sb][ss] *= x;
	  }
	else 
	  xr[sb][ss] = 0;

	xr[sb][ss] /= 256;

      }
      else {   /* LONG block types 0,1,3 & 1st 2 subbands of switched blocks */
	//xr[sb][ss] *=  pow(2.0, -0.5 * (1.0+gr_info->scalefac_scale)
	//		  * ((*scalefac)[ch].l[cb]
	//		     + gr_info->preflag * pretab[cb]));
	//NOTE: 1/2 is, once again, a right shift 

	x = (1 + gr_info->scalefac_scale) * ((*scalefac)[ch].l[cb] + gr_info->preflag * pretab[cb]);
	if(x > 0)
	  {
	    extra = x & 0x3;
	    main = x >> 1;
	  }
	else
	  {
	    x = -x;
	    extra = x & 0x3;
	    main = x >> 1;	  
	  }

	if(main < 8)
	  {
	    x = 1 << (long)(8l - main);
	    x = (x << 10l)/EXTRAS[extra];
	    xr[sb][ss] *= x;
	  }
	else 
	  xr[sb][ss] = 0;

	xr[sb][ss] /= 256;
      }
      /////////////////////////////////////////

      /* Scale quantized value. */
        
      sign = (is[sb][ss]<0) ? 1 : 0; 

      xr[sb][ss] *= POW43(abs(is[sb][ss]));

      if (sign) xr[sb][ss] = -xr[sb][ss];
    }
}

void III_reorder (xr, ro, gr_info, fr_ps) 
     short xr[SBLIMIT][SSLIMIT]; 
     short ro[SBLIMIT][SSLIMIT]; 
     struct gr_info_s *gr_info;
     frame_params *fr_ps;
{
  int sfreq=fr_ps->header->sampling_frequency;
  int sfb, sfb_start, sfb_lines;
  int sb, ss, window, freq, src_line, des_line;

  for(sb=0;sb<SBLIMIT;sb++)
    for(ss=0;ss<SSLIMIT;ss++) 
      ro[sb][ss] = 0;

  if (gr_info->window_switching_flag && (gr_info->block_type == 2)) {
    if (gr_info->mixed_block_flag) {
      /* NO REORDER FOR LOW 2 SUBBANDS */
      for (sb=0 ; sb < 2 ; sb++)
	for (ss=0 ; ss < SSLIMIT ; ss++) {
	  ro[sb][ss] = xr[sb][ss];
	}
      /* REORDERING FOR REST SWITCHED SHORT */
      for(sfb=3,sfb_start=sfBandIndex[sfreq].s[3],
            sfb_lines=sfBandIndex[sfreq].s[4] - sfb_start; 
	  sfb < 13; sfb++,sfb_start=sfBandIndex[sfreq].s[sfb],
            (sfb_lines=sfBandIndex[sfreq].s[sfb+1] - sfb_start))
	for(window=0; window<3; window++)
	  for(freq=0;freq<sfb_lines;freq++) {
	    src_line = sfb_start*3 + window*sfb_lines + freq; 
	    des_line = (sfb_start*3) + window + (freq*3);
	    ro[des_line/SSLIMIT][des_line%SSLIMIT] = 
	      xr[src_line/SSLIMIT][src_line%SSLIMIT];
	  }
    } 
    else {  /* pure short */
      for(sfb=0,sfb_start=0,sfb_lines=sfBandIndex[sfreq].s[1]; 
	  sfb < 13; sfb++,sfb_start=sfBandIndex[sfreq].s[sfb],
            (sfb_lines=sfBandIndex[sfreq].s[sfb+1] - sfb_start))
	for(window=0; window<3; window++)
	  for(freq=0;freq<sfb_lines;freq++) {
	    src_line = sfb_start*3 + window*sfb_lines + freq; 
	    des_line = (sfb_start*3) + window + (freq*3);
	    ro[des_line/SSLIMIT][des_line%SSLIMIT] = 
	      xr[src_line/SSLIMIT][src_line%SSLIMIT];
	  }
    }
  }
  else {   /*long blocks */
    for (sb=0 ; sb < SBLIMIT ; sb++)
      for (ss=0 ; ss < SSLIMIT ; ss++) 
	ro[sb][ss] = xr[sb][ss];
  }
}



void III_stereo(xr, lr, scalefac, gr_info, fr_ps)
     short xr[2][SBLIMIT][SSLIMIT];
     short lr[2][SBLIMIT][SSLIMIT];
     III_scalefac_t *scalefac;
     struct gr_info_s *gr_info;
     frame_params *fr_ps;
{
  // double xr[2][SBLIMIT][SSLIMIT];
  //int sfreq = fr_ps->header->sampling_frequency;
  int stereo = fr_ps->stereo;
  int ms_stereo = (fr_ps->header->mode == MPG_MD_JOINT_STEREO) &&
    (fr_ps->header->mode_ext & 0x2); 
  //  int i_stereo = (fr_ps->header->mode == MPG_MD_JOINT_STEREO) &&
  //  (fr_ps->header->mode_ext & 0x1);
  //int js_bound;  frequency line that marks the beggining of the zero part 
  //  int sfb, next_sfb_boundary;
  int sb,ss,ch; //i,j
  short xr0, xr1;

#ifdef STEREO_ENABLED
  int is_pos[576]; 
  double is_ratio[576];

  //  int I, J, K;

  // for(I=0;J<2;J++)
  //  for(J=0;J<SBLIMIT;J++)
  //    for(J=0;J<SSLIMIT;J++)
  //xr[I][J][K] = xrr[I][J][K] / DEQ_SCALE;

  /* intialization */
  for ( i=0; i<576; i++ )
    is_pos[i] = 7;

  if ((stereo == 2) && i_stereo )
    {
      if (gr_info->window_switching_flag && (gr_info->block_type == 2))
      {  if( gr_info->mixed_block_flag )
	{  int max_sfb = 0;

	for ( j=0; j<3; j++ )
	  {  int sfbcnt;
	  sfbcnt = 2;
	  for( sfb=12; sfb >=3; sfb-- )
	    {  int lines;
	    lines = sfBandIndex[sfreq].s[sfb+1]-sfBandIndex[sfreq].s[sfb];
	    i = 3*sfBandIndex[sfreq].s[sfb] + (j+1) * lines - 1;
	    while ( lines > 0 )
	      {  if ( xr[1][i/SSLIMIT][i%SSLIMIT] != 0.0 )
		{  sfbcnt = sfb;
		sfb = -10;
		lines = -10;
		}
	      lines--;
	      i--;
	      }
	    }
	  sfb = sfbcnt + 1;

	  if ( sfb > max_sfb )
	    max_sfb = sfb;
	  while( sfb<12 )
	    {  sb = sfBandIndex[sfreq].s[sfb+1]-sfBandIndex[sfreq].s[sfb];
	    i = 3*sfBandIndex[sfreq].s[sfb] + j * sb;
	    for ( ; sb > 0; sb--)
	      {
		is_pos[i] = (*scalefac)[1].s[j][sfb];
		if ( is_pos[i] != 7 )
		  is_ratio[i] = tan( is_pos[i] * (PI / 12));
		i++;
	      }
	    sfb++;
	    }
	  sb = sfBandIndex[sfreq].s[11]-sfBandIndex[sfreq].s[10];
	  sfb = 3*sfBandIndex[sfreq].s[10] + j * sb;
	  sb = sfBandIndex[sfreq].s[12]-sfBandIndex[sfreq].s[11];
	  i = 3*sfBandIndex[sfreq].s[11] + j * sb;
	  for ( ; sb > 0; sb-- )
	    {  is_pos[i] = is_pos[sfb];
	    is_ratio[i] = is_ratio[sfb];
	    i++;
	    }
	  }
	if ( max_sfb <= 3 )
	  {  i = 2;
	  ss = 17;
	  sb = -1;
	  while ( i >= 0 )
	    {  if ( xr[1][i][ss] != 0.0 )
	      {  sb = i*18+ss;
	      i = -1;
	      } else
		{  ss--;
		if ( ss < 0 )
		  {  i--;
		  ss = 17;
		  }
		}
	    }
	  i = 0;
	  while ( sfBandIndex[sfreq].l[i] <= sb )
	    i++;
	  sfb = i;
	  i = sfBandIndex[sfreq].l[i];
	  for ( ; sfb<8; sfb++ )
	    {  sb = sfBandIndex[sfreq].l[sfb+1]-sfBandIndex[sfreq].l[sfb];
	    for ( ; sb > 0; sb--)
	      {  is_pos[i] = (*scalefac)[1].l[sfb];
	      if ( is_pos[i] != 7 )
		is_ratio[i] = tan( is_pos[i] * (PI / 12));
	      i++;
	      }
	    }
	  }
	} else
	  {  for ( j=0; j<3; j++ )
            {  int sfbcnt;
	    sfbcnt = -1;
	    for( sfb=12; sfb >=0; sfb-- )
	      {  int lines;
	      lines = sfBandIndex[sfreq].s[sfb+1]-sfBandIndex[sfreq].s[sfb];
	      i = 3*sfBandIndex[sfreq].s[sfb] + (j+1) * lines - 1;
	      while ( lines > 0 )
		{  if ( xr[1][i/SSLIMIT][i%SSLIMIT] != 0.0 )
		  {  sfbcnt = sfb;
		  sfb = -10;
		  lines = -10;
		  }
		lines--;
		i--;
		}
	      }
	    sfb = sfbcnt + 1;
	    while( sfb<12 )
	      {  sb = sfBandIndex[sfreq].s[sfb+1]-sfBandIndex[sfreq].s[sfb];
	      i = 3*sfBandIndex[sfreq].s[sfb] + j * sb;
	      for ( ; sb > 0; sb--)
		{  is_pos[i] = (*scalefac)[1].s[j][sfb];
		if ( is_pos[i] != 7 )
		  is_ratio[i] = tan( is_pos[i] * (PI / 12));
		i++;
		}
	      sfb++;
	      }

	    sb = sfBandIndex[sfreq].s[11]-sfBandIndex[sfreq].s[10];
	    sfb = 3*sfBandIndex[sfreq].s[10] + j * sb;
	    sb = sfBandIndex[sfreq].s[12]-sfBandIndex[sfreq].s[11];
	    i = 3*sfBandIndex[sfreq].s[11] + j * sb;
	    for ( ; sb > 0; sb-- )
	      {  is_pos[i] = is_pos[sfb];
	      is_ratio[i] = is_ratio[sfb];
	      i++;
	      }
            }
	  }
      } else
	{  i = 31;
	ss = 17;
	sb = 0;
	while ( i >= 0 )
	  {  if ( xr[1][i][ss] != 0.0 )
            {  sb = i*18+ss;
	    i = -1;
            } else
	      {  ss--;
	      if ( ss < 0 )
		{  i--;
		ss = 17;
		}
	      }
	  }
	i = 0;
	while ( sfBandIndex[sfreq].l[i] <= sb )
	  i++;
	sfb = i;
	i = sfBandIndex[sfreq].l[i];
	for ( ; sfb<21; sfb++ )
	  {  sb = sfBandIndex[sfreq].l[sfb+1] - sfBandIndex[sfreq].l[sfb];
	  for ( ; sb > 0; sb--)
            {  is_pos[i] = (*scalefac)[1].l[sfb];
	    if ( is_pos[i] != 7 )
	      is_ratio[i] = tan( is_pos[i] * (PI / 12));
	    i++;
            }
	  }
	sfb = sfBandIndex[sfreq].l[20];
	for ( sb = 576 - sfBandIndex[sfreq].l[21]; sb > 0; sb-- )
	  {  is_pos[i] = is_pos[sfb];
	  is_ratio[i] = is_ratio[sfb];
	  i++;
	  }
	}
    }
#endif /* ifdef STEREO_ENABLED */

#if 0
  for(ch=0;ch<2;ch++)
    for(sb=0;sb<SBLIMIT;sb++)
      for(ss=0;ss<SSLIMIT;ss++) 
	lr[ch][sb][ss] = 0;
#endif

  if (stereo==2) 
    for(sb=0;sb<SBLIMIT;sb++)
      for(ss=0;ss<SSLIMIT;ss++) {
	xr0 = xr[0][sb][ss];
	xr1 = xr[1][sb][ss];

#ifdef STEREO_ENABLED
	i = (sb*18)+ss;
	if ( is_pos[i] == 7 ) {
#endif
	  if ( ms_stereo ) {
	    
	    lr[0][sb][ss] = (xr0+xr1)*2/3; 
	    lr[1][sb][ss] = (xr0-xr1)*2/3; 
	    
	  }
	  else {
	    lr[0][sb][ss] = xr0;
	    lr[1][sb][ss] = xr1;
	  }
#ifdef STEREO_ENABLED
	}
	else if (i_stereo ) {
	  lr[0][sb][ss] = xr[0][sb][ss] * (is_ratio[i]/(1+is_ratio[i]));
	  lr[1][sb][ss] = xr[0][sb][ss] * (1/(1+is_ratio[i])); 
	}
	else {
#ifdef PLATFORM_UNIX
	  printf("Error in streo processing\n");
#endif /* ifdef PLATFORM_UNIX */
	}
#endif /* ifdef STEREO_ENABLED */
      }
  else  /* mono , bypass xr[0][][] to lr[0][][]*/
    for(sb=0;sb<SBLIMIT;sb++)
      for(ss=0;ss<SSLIMIT;ss++)
	lr[0][sb][ss] = STEREO_SCALE * xr[0][sb][ss];

}

//double Ci[8]={-0.6,-0.535,-0.33,-0.185,-0.095,-0.041,-0.0142,-0.0037};

//THIS USED TO BE A DOUBLE
short ca[8] = {
  -0.514496 * ALIAS_SCALE, -0.471732 * ALIAS_SCALE, -0.313377 * ALIAS_SCALE, -0.181913 * ALIAS_SCALE,
  -0.094574 * ALIAS_SCALE, -0.040966 * ALIAS_SCALE, -0.014199 * ALIAS_SCALE, -0.003700 * ALIAS_SCALE};

//THIS USED TO BE A DOUBLE
short cs[8] = {
  0.857493 * ALIAS_SCALE, 0.881742 * ALIAS_SCALE, 0.949629 * ALIAS_SCALE, 0.983315 * ALIAS_SCALE,
  0.995518 * ALIAS_SCALE, 0.999161 * ALIAS_SCALE, 0.999899 * ALIAS_SCALE, 0.999993 * ALIAS_SCALE};

void III_antialias(xr, hybridIn, gr_info, fr_ps)
     short xr[SBLIMIT][SSLIMIT];
     short hybridIn[SBLIMIT][SSLIMIT];
     struct gr_info_s *gr_info;             
     frame_params *fr_ps;            
{
  short        bu,bd;  /* upper and lower butterfly inputs */
  int           ss,sb,sblim;


  if  (gr_info->window_switching_flag && (gr_info->block_type == 2) &&
       !gr_info->mixed_block_flag ) return;

  if ( gr_info->window_switching_flag && gr_info->mixed_block_flag &&
       (gr_info->block_type == 2))
    sblim = 1;
  else
    sblim = SBLIMIT-1;

  /* 31 alias-reduction operations between each pair of sub-bands */
  /* with 8 butterflies between each pair                         */

  for(sb=0;sb<sblim;sb++)   
    for(ss=0;ss<8;ss++) {      
      bu = xr[sb][17-ss];
      bd = xr[sb+1][ss];
      hybridIn[sb][17-ss] = (bu * cs[ss] / ALIAS_SCALE) - (bd * ca[ss] / ALIAS_SCALE);
      hybridIn[sb+1][ss] = (bd * cs[ss] / ALIAS_SCALE) + (bu * ca[ss] / ALIAS_SCALE);
    }  
}

void inv_mdct(in, out, block_type)
     short in[18];
     short out[36];
     int block_type;
{
  /*------------------------------------------------------------------*/
  /*                                                                  */
  /*    Function: Calculation of the inverse MDCT                     */
  /*    In the case of short blocks the 3 output vectors are already  */
  /*    overlapped and added in this modul.                           */
  /*                                                                  */
  /*    New layer3                                                    */
  /*                                                                  */
  /*------------------------------------------------------------------*/

  int    i,m,N,p;
  short  tmp[12], sum;



  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] / IMDCT_SCALE_DIFFERENTIAL * COS[((2*p+1+N/2)*(2*m+1))%(4*36)] / IMDCT_SCALE;
	tmp[p] = sum * imdct_window[block_type][p] / IMDCT_SCALE;
      }
      for(p=0;p<N;p++)
	out[6*i+p+6] += tmp[p];  //moved here
    }
  }
  else{
    N=36;
    for(p= 0;p<N;p++){
      sum = 0.0;
      for(m=0;m<N/2;m++)
	sum += 128 *in[m] / IMDCT_SCALE_DIFFERENTIAL * COS[((2*p+1+N/2)*(2*m+1))%(4*36)] / IMDCT_SCALE;
      out[p] = sum / IMDCT_SCALE * imdct_window[block_type][p] / 128; 
    }
  }
}


int main_data_slots(fr_ps)
     frame_params fr_ps;
{
  int nSlots;
  long br = bitrate[2][fr_ps.header->bitrate_index];
  long sf; 
  int offset = fr_ps.header->sampling_frequency;

  sf = s_freq[offset]; 
  nSlots = 144000 * br / sf;
  if (fr_ps.header->padding) nSlots++;
  nSlots -= 4;
  if (fr_ps.header->error_protection) nSlots -= 2;
  if (fr_ps.stereo == 1) nSlots -= 17; else nSlots -=32;
  return(nSlots);
}


/*
 * hardware functions below **********************************
 *
 */

typedef short NN[64][32];
typedef short BB[2][2*HAN_SIZE];

BB stc_buf;


/* sblimit = 32, sslimit = 18 */
int hardware( short hybridIn[SBLIMIT][SSLIMIT],
	      frame_params * fr_ps,
	      PCM pcm_sample,
	      int ch, int gr,
	      III_side_info_t * III_side_info )
	      
{
  int clip = 0;
  int sb, ss, i, j, k;
  short rawout[36];
  short *bufOffsetPtr, sum;

  static int bufOffset[2] = {64,64};
  long foo;

  static short prevblck[2][SBLIMIT][SSLIMIT];
  static int init = 0;
  int bt;
  struct gr_info_s *gr_info = &(III_side_info->ch[ch].gr[gr]);

  /* flat access: */
  short *prevblck_flat   = (short *)prevblck;
  short *hybridIn_flat   = (short *)hybridIn;
  short *stc_buf_flat    = (short *)stc_buf;
  short *stc_filter_flat = (short *)stc_filter;
  short  *pcm_sample_flat = (short*)pcm_sample;
  #define IDX_PB(a,b,c) ( ((a)*SBLIMIT + (b))*SSLIMIT + (c) )
  #define IDX_HI(a,b)   ( (a)*SSLIMIT + (b) )
  #define IDX_SB(a,b)   ( (a)*2*HAN_SIZE + (b) )
  #define IDX_SF(a,b)   ( (a)*32 + (b) )
  #define IDX_PS(a,b,c) ( ((a)*SSLIMIT + (b))*SBLIMIT + (c) )
  int idx_pb,idx_hi,idx_sf,idx_ps;


  if (!init) {
    for(i=0; i<2*SBLIMIT*SSLIMIT; ++i) {
      prevblck_flat[i] = 0x0;
    }

    init = 1;
  }


  /* Hybrid synthesis. */
  idx_hi = 0;
  idx_pb = ch * SBLIMIT * SSLIMIT;
  for (sb=0; sb<SBLIMIT; sb++) {
    bt = (gr_info->window_switching_flag && 
	  gr_info->mixed_block_flag &&
	  (sb < 2)) ? 0 : gr_info->block_type; 
    
    inv_mdct( hybridIn[sb], rawout, bt);
    
    /* overlap addition */
    for(ss=0; ss<SSLIMIT; ss++) {
      hybridIn_flat[idx_hi] = rawout[ss] + prevblck_flat[idx_pb];
      prevblck_flat[idx_pb] = rawout[ss+18];

      /* frequency inversion */
      if( (ss&1) && (sb&1) ) {
	hybridIn_flat[idx_hi] = -hybridIn_flat[idx_hi];
      }

      ++idx_hi;
      ++idx_pb;
    }
  }


  /* Polyphase synthesis */
  for (ss=0;ss<SSLIMIT;ss++) {    
    /* SubBandSynthesis */
    bufOffset[ch] = (bufOffset[ch] - 64) & 0x3ff;
    bufOffsetPtr = &stc_buf_flat[IDX_SB(ch,bufOffset[ch])];
    
    for (i=0; i<64; i++) {
      sum = 0;
      idx_hi = ss;
      idx_sf = i * 32;
      for (k=0; k<32; k++) {
	sum += hybridIn_flat[idx_hi] / 4 * stc_filter_flat[idx_sf];
	idx_hi += SSLIMIT;
	++idx_sf;
      }
      bufOffsetPtr[i] = sum;
    }
    
    for (j=0; j<32; j++) {
      sum = 0;
      for (i=0; i<16; i++) {
	k = j + (long)(i<<5l);

	sum += stc_window[k] * 
	  stc_buf_flat[IDX_SB(ch,( (k + ( ((i+1l)<<5l) & 0xffc0) ) +
			 bufOffset[ch]) & 0x3ff)];
      }
      
      
      idx_ps = IDX_PS(ch,ss,j);
      foo = sum * SCALE / (FILTER_SCALE*WINDOW_SCALE*64);
      if (foo >= (long) SCALE) {
	pcm_sample_flat[idx_ps] = SCALE-1; 
	++clip;
      }
      else if (foo < (long) -SCALE) {
	pcm_sample_flat[idx_ps] = -SCALE;  
	++clip;
      }
      else
	pcm_sample_flat[idx_ps] = foo;
    }

    /* end SubBandSynthesis */
  }

  return clip;
  
}


