/************************* MPEG-2 NBC Audio Decoder **************************
 *                                                                           *
"This software module was originally developed by 

AT&T, Dolby Laboratories, Fraunhofer Gesellschaft IIS and edited by

Yoshiaki Oikawa (Sony Corporation),
Mitsuyuki Hatanaka (Sony Corporation),
Ralph Sperschneider (Fraunhofer Gesellschaft IIS)

in the course of development of the MPEG-2 NBC/MPEG-4 Audio standard ISO/IEC 13818-7, 
14496-1,2 and 3. This software module is an implementation of a part of one or more 
MPEG-2 NBC/MPEG-4 Audio tools as specified by the MPEG-2 NBC/MPEG-4 
Audio standard. ISO/IEC  gives users of the MPEG-2 NBC/MPEG-4 Audio 
standards free license to this software module or modifications thereof for use in 
hardware or software products claiming conformance to the MPEG-2 NBC/MPEG-4
Audio  standards. Those intending to use this software module in hardware or 
software products are advised that this use may infringe existing patents. 
The original developer of this software module and his/her company, the subsequent 
editors and their companies, and ISO/IEC have no liability for use of this software 
module or modifications thereof in an implementation. Copyright is not released for 
non MPEG-2 NBC/MPEG-4 Audio conforming products.The original developer
retains full right to use the code for his/her  own purpose, assign or donate the 
code to a third party and to inhibit third party from using the code for non 
MPEG-2 NBC/MPEG-4 Audio conforming products. This copyright notice must
be included in all copies or derivative works." 
Copyright(c)1996.
 *                                                                           *
 ****************************************************************************/

#include "huffdec2.h"
#include "huffdec3.h"
#include "all.h"
#include "port.h"
#include "sony_local.h" /* 971117 YT */
#include "common.h"
#include "resilience.h"
#include "reorderspec.h"
#include "concealment.h"
#include "bitfct.h"
#include "buffers.h"

static void PrintSpectralValues ( int *quant )
{
  unsigned short i;
  for ( i = 0; i < LN2; i++ )
    fprintf ( stderr, "bno %13li line %4i value %13i\n", bno, i, quant[i] );
}

typedef int DINT_DATATYPE;
static void deinterleave ( DINT_DATATYPE     inptr1[], 
                           DINT_DATATYPE     outptr1[], 
                           short             ngroups,
                           short             nsubgroups[], 
                           int               ncells[], 
                           short             cellsize[],
                           int               islong,
                           HANDLE_RESILIENCE hResilience )
{
#ifdef VERSION2
  if ( GetReorderSpecFlag( hResilience ) )
    {
      unsigned short    unitInterleaveLevel;
      unsigned short    unitNrInSpectralDirection;
      unsigned short    unitsInSpectralDirection;   /* number of units in spectral direction */
      unsigned short    windowNr;
      unsigned short    windows;
      unsigned short    lineNrPerUnit;
      unsigned short    linesPerUnit = 4;
      unsigned short    linesPerWindow;
      unsigned short    inLine = 0;

      if ( islong ) /* long */
        {
          linesPerWindow = LN2;                          /* 1024 */
          unitsInSpectralDirection = LN2 / linesPerUnit; /*  256 */
          windows = 1;                                   /*    1 */
        }
      else /* short */
        {
          linesPerWindow = SN2;                          /*  256 */
          unitsInSpectralDirection = SN2 / linesPerUnit; /*   32 */
          windows = 8;                                   /*    8 */
        }
      for ( unitInterleaveLevel = 0; 
            unitInterleaveLevel < UNIT_INTERLEAVING; 
            unitInterleaveLevel++ )
        for ( unitNrInSpectralDirection = unitInterleaveLevel; 
              unitNrInSpectralDirection < unitsInSpectralDirection;
              unitNrInSpectralDirection += UNIT_INTERLEAVING )         /* for each unit of a window within the spectrum */
          for ( windowNr = 0; windowNr < windows; windowNr++ )         /* for each window within a spectrum part (4 lines) */
            for ( lineNrPerUnit = 0; lineNrPerUnit < linesPerUnit; lineNrPerUnit++ ) /* for each line within a unit */
              {
                outptr1 [unitNrInSpectralDirection * linesPerUnit + windowNr * linesPerUnit * unitsInSpectralDirection + lineNrPerUnit] 
                  = inptr1[inLine];
                inLine++;
              }
    }
  else
#endif /*VERSION2*/
    {
      int i, j, k, l;
      DINT_DATATYPE *start_inptr, *start_subgroup_ptr, *subgroup_ptr;
      short cell_inc, subgroup_inc;

      start_subgroup_ptr = outptr1;

      for (i = 0; i < ngroups; i++)
        {
          cell_inc = 0;
          start_inptr = inptr1;

          /* Compute the increment size for the subgroup pointer */

          subgroup_inc = 0;
          for (j = 0; j < ncells[i]; j++) {
            subgroup_inc += cellsize[j];
          }

          /* Perform the deinterleaving across all subgroups in a group */

          for (j = 0; j < ncells[i]; j++) {
            subgroup_ptr = start_subgroup_ptr;

            for (k = 0; k < nsubgroups[i]; k++) {
              outptr1 = subgroup_ptr + cell_inc;
              for (l = 0; l < cellsize[j]; l++) {
                *outptr1++ = *inptr1++;
              }
              subgroup_ptr += subgroup_inc;
            }
            cell_inc += cellsize[j];
          }
          start_subgroup_ptr += (inptr1 - start_inptr);
        }
    }
}

static void calc_gsfb_table ( Info *info, 
                              byte *group )
{
  int group_offset;
  int group_idx;
  int offset;
  short * group_offset_p;
  int sfb,len;
  /* first calc the group length*/
  if (info->islong){
    return;
  } else {
    group_offset = 0;
    group_idx =0;
    do  {
      info->group_len[group_idx]=group[group_idx]-group_offset;
      group_offset=group[group_idx];
      group_idx++;
    } while (group_offset<8);
    info->num_groups=group_idx;
    group_offset_p = info->bk_sfb_top;
    offset=0;
    for (group_idx=0;group_idx<info->num_groups;group_idx++){
      len = info->group_len[group_idx];
      for (sfb=0;sfb<info->sfb_per_sbk[group_idx];sfb++){
        offset += info->sfb_width_short[sfb] * len;
        *group_offset_p++ = offset;
#if 0
        PRINT(SE,"%d %d: %d\n",  group_idx, sfb, offset);
#endif    
      }
    }
  }
}

void getgroup ( Info*             info, 
                byte*             group, 
                HANDLE_RESILIENCE hResilience,
                HANDLE_BUFFER     hVm,
                HANDLE_EP_INFO    hEPInfo )
{
  int i, j, first_short;

  if( debug['g'] ) PRINT(SE,"Grouping: 0");
  first_short=1;
  for (i = 0; i < info->nsbk; i++) {
    if (info->bins_per_sbk[i] > SN2) {
      /* non-short windows are always their own group */
      *group++ = i+1;
    }
    else {
      /* only short-window sequences are grouped! */
      if (first_short) {
        /* first short window is always a new group */
        first_short=0;
      }
      else {
        if((j = GetBits ( SCALE_FACTOR_GROUPING, 
                          1,
                          hResilience,
                          hVm, 
                          hEPInfo )) == 0) {
          *group++ = i;
        }
        if( debug['g'] ) PRINT(SE,"%1d", j);
      }
    }
  }
  *group = i;
  if( debug['g'] ) PRINT(SE,"\n");
}

/*
 * read a synthesis mask
 *  uses EXTENDED_MS_MASK
 *  and grouped mask 
 */
int getmask ( Info*             info, 
              byte*             group, 
              byte              max_sfb, 
              byte*             mask, 
              HANDLE_RESILIENCE hResilience,
              HANDLE_BUFFER     hVm, 
              HANDLE_EP_INFO    hEPInfo )
{
  int b, i, mp;

  mp = GetBits ( MS_MASK_PRESENT, 
                 LEN_MASK_PRES,
                 hResilience,
                 hVm, 
                 hEPInfo );
  if( debug['m'] )
    PRINT(SE,"\nExt. Mask Present: %d\n",mp);

  /* special EXTENDED_MS_MASK cases */
  if(mp == 0) { /* no ms at all */
    return 0;
  }
  if(mp == 2) {/* MS for whole spectrum on, mask bits set to 1 */
    for(b = 0; b < info->nsbk; b = *group++)
      for(i = 0; i < info->sfb_per_sbk[b]; i ++)
        *mask++ = 1;
    return 2;
  }

  /* otherwise get mask */
  for(b = 0; b < info->nsbk; b = *group++){
    if( debug['m'] ) PRINT(SE," gr%1i:",b);
    for(i = 0; i < max_sfb; i ++) {
      *mask = GetBits ( MS_USED, 
                        LEN_MASK,
                        hResilience,
                        hVm, 
                        hEPInfo );
      if( debug['m'] )PRINT(SE,"%1i",*mask);
      mask++;
    }
    for( ; i < info->sfb_per_sbk[b]; i++){
      *mask = 0;
      if( debug['m'] ) PRINT(SE,"%1i",*mask);
      mask++;
    }
  }
  if( debug['m'] ) PRINT(SE,"\n");
  return 1;
}

void clr_tns( Info *info, TNS_frame_info *tns_frame_info )
{
  int s;

  tns_frame_info->n_subblocks = info->nsbk;
  for (s=0; s<tns_frame_info->n_subblocks; s++)
    tns_frame_info->info[s].n_filt = 0;
}

static int get_tns ( Info*             info, 
                     TNS_frame_info*   tns_frame_info,
                     HANDLE_RESILIENCE hResilience,
                     HANDLE_BUFFER     hVm, 
                     HANDLE_EP_INFO    hEPInfo )
{
  int                       f, t, top, res, res2, compress;
  int                       short_flag, s;
  short                     *sp, tmp, s_mask, n_mask;
  TNSfilt                   *tns_filt;
  TNSinfo                   *tns_info;
  static short              sgn_mask[] = {     0x2, 0x4, 0x8     };
  static short              neg_mask[] = {     (short) 0xfffc, (short)0xfff8, (short)0xfff0     };


  short_flag = (!info->islong);
  tns_frame_info->n_subblocks = info->nsbk;

  for (s=0; s<tns_frame_info->n_subblocks; s++) {
    tns_info = &tns_frame_info->info[s];

    if (!(tns_info->n_filt = GetBits ( N_FILT, 
                                       short_flag ? 1 : 2,
                                       hResilience,
                                       hVm, 
                                       hEPInfo )))
      continue;
            
    tns_info -> coef_res = res = GetBits ( COEF_RES, 
                                           1,
                                           hResilience,
                                           hVm, 
                                           hEPInfo ) + 3;
    top = info->sfb_per_sbk[s];
    tns_filt = &tns_info->filt[ 0 ];
    for (f=tns_info->n_filt; f>0; f--)  {
      tns_filt->stop_band = top;
      top = tns_filt->start_band = top - GetBits ( TNS_LENGTH, 
                                                   short_flag ? 4 : 6,
                                                   hResilience,
                                                   hVm, 
                                                   hEPInfo );
      tns_filt->order = GetBits ( ORDER, 
                                  short_flag ? 3 : 5,
                                  hResilience,
                                  hVm, 
                                  hEPInfo );

      if (tns_filt->order)  {
        tns_filt->direction = GetBits ( DIRECTION, 
                                        1,
                                        hResilience,
                                        hVm, 
                                        hEPInfo );
        compress = GetBits ( COEF_COMPRESS, 
                             1,
                             hResilience,
                             hVm, 
                             hEPInfo );

        res2 = res - compress;
        s_mask = sgn_mask[ res2 - 2 ];
        n_mask = neg_mask[ res2 - 2 ];

        sp = tns_filt -> coef;
        for (t=tns_filt->order; t>0; t--)  {
          tmp = GetBits ( TNS_COEF, 
                          res2,
                          hResilience,
                          hVm, 
                          hEPInfo );
          *sp++ = (tmp & s_mask) ? (tmp | n_mask) : tmp;
        }
      }
      tns_filt++;
    }
  }   /* subblock loop */
  return 1;
}

/*
 * NEC noiseless coding
 */
struct Nec_Info
{
  int pulse_data_present;
  int number_pulse;
  int pulse_start_sfb;
  int pulse_position[NUM_NEC_LINES];
  int pulse_offset[NUM_NEC_LINES];
  int pulse_amp[NUM_NEC_LINES];
};
static struct Nec_Info nec_info;

static void get_nec_nc ( struct Nec_Info*  nec_info,
                         HANDLE_RESILIENCE hResilience,
                         HANDLE_BUFFER     hVm,
                         HANDLE_EP_INFO    hEPInfo )
{
  int i;
  nec_info->number_pulse = GetBits ( NUMBER_PULSE,
                                     LEN_NEC_NPULSE,
                                     hResilience,
                                     hVm, 
                                     hEPInfo );
  nec_info->pulse_start_sfb = GetBits ( PULSE_START_OFFSET, 
                                        LEN_NEC_ST_SFB,
                                        hResilience,
                                        hVm, 
                                        hEPInfo );
  for(i=0; i<nec_info->number_pulse; i++) {
    nec_info->pulse_offset[i] = GetBits ( PULSE_OFFSET, 
                                          LEN_NEC_POFF,
                                          hResilience,
                                          hVm, 
                                          hEPInfo );
    nec_info->pulse_amp[i] = GetBits ( PULSE_AMP, 
                                       LEN_NEC_PAMP,
                                       hResilience,
                                       hVm, 
                                       hEPInfo );
  }
}

static void nec_nc ( int *coef, 
                     struct Nec_Info *nec_info)
{
  int i, k;
    
  k = only_long_info.sbk_sfb_top[0][nec_info->pulse_start_sfb];
    
  for(i=0; i<=nec_info->number_pulse; i++) {
    k += nec_info->pulse_offset[i];
    if (coef[k]>0) coef[k] += nec_info->pulse_amp[i];
    else coef[k] -= nec_info->pulse_amp[i];
  }
}

#ifdef SRS

long get_gcBuf ( byte              window_sequence, 
                 BsBitStream*      gc_streamCh,
                 HANDLE_RESILIENCE hResilience ,                 
                 HANDLE_BUFFER     hVm,
                 HANDLE_EP_INFO    hEPInfo )
{
  unsigned int bd;
  int wd;
  unsigned int ad;
  unsigned long   max_band, natks, ltmp;
  int loc;

  loc = gc_streamCh->currentBit;
  max_band = GetBits ( MAX_BAND, 
                       NBANDSBITS,
                       hResilience,
                       hVm, 
                       hEPInfo );
  BsPutBit(gc_streamCh, max_band, NBANDSBITS);/*   0 < max_band <= 3 */

  switch (window_sequence) {
  case ONLY_LONG_SEQUENCE:
    for (bd = 1; bd <= max_band; bd++) {
      for (wd = 0; wd < 1; wd++) {
        natks = GetBits ( ADJUST_NUM, 
                          NATKSBITS,
                          hResilience,
                          hVm, 
                          hEPInfo );
        BsPutBit(gc_streamCh, natks, NATKSBITS);
        for (ad = 0; ad < natks; ad++) {
          ltmp = GetBits ( ALEVCODE, 
                           IDGAINBITS,
                           hResilience,
                           hVm, 
                           hEPInfo );
          BsPutBit(gc_streamCh, ltmp, IDGAINBITS);
          ltmp = GetBits ( ALOCCODE,
                           ATKLOCBITS,
                           hResilience,
                           hVm, 
                           hEPInfo );
          BsPutBit(gc_streamCh, ltmp, ATKLOCBITS);
        }
      }
    }
    break;
  case LONG_START_SEQUENCE:
    for (bd = 1; bd <= max_band; bd++) {
      for (wd = 0; wd < 2; wd++) {
        natks = GetBits ( ADJUST_NUM, 
                          NATKSBITS,
                          hResilience,
                          hVm, 
                          hEPInfo );
        BsPutBit(gc_streamCh, natks, NATKSBITS);
        for (ad = 0; ad < natks; ad++) {
          ltmp = GetBits ( ALEVCODE,
                           IDGAINBITS,
                           hResilience,
                           hVm, 
                           hEPInfo );
          BsPutBit(gc_streamCh, ltmp, IDGAINBITS);
          if (wd == 0) {
            ltmp = GetBits ( ALOCCODE, 
                             ATKLOCBITS_START_A,
                             hResilience,
                             hVm, 
                             hEPInfo );
            BsPutBit(gc_streamCh, ltmp, ATKLOCBITS_START_A);
          }
          else {
            ltmp = GetBits ( ALOCCODE, 
                             ATKLOCBITS_START_B,
                             hResilience,
                             hVm, 
                             hEPInfo );
            BsPutBit(gc_streamCh, ltmp, ATKLOCBITS_START_B);
          }
        }
      }
    }
    break;
  case EIGHT_SHORT_SEQUENCE:
    for (bd = 1; bd <= max_band; bd++) {
      for (wd = 0; wd < 8; wd++) {
        natks = GetBits (  ADJUST_NUM, 
                           NATKSBITS,
                           hResilience,
                           hVm, 
                           hEPInfo );
        BsPutBit(gc_streamCh, natks, NATKSBITS);
        for (ad = 0; ad < natks; ad++) {
          ltmp = GetBits ( ALEVCODE, 
                           IDGAINBITS,
                           hResilience,
                           hVm, 
                           hEPInfo );
          BsPutBit(gc_streamCh, ltmp, IDGAINBITS);
          ltmp = GetBits (  ALOCCODE, 
                            ATKLOCBITS_SHORT,
                            hResilience,
                            hVm, 
                            hEPInfo );
          BsPutBit(gc_streamCh, ltmp, ATKLOCBITS_SHORT);
        }
      }
    }
    break;
  case LONG_STOP_SEQUENCE:
    for (bd = 1; bd <= max_band; bd++) {
      for (wd = 0; wd < 2; wd++) {
        natks = GetBits (  ADJUST_NUM, 
                           NATKSBITS,
                           hResilience,
                           hVm, 
                           hEPInfo );
        BsPutBit(gc_streamCh, natks, NATKSBITS);
        for (ad = 0; ad < natks; ad++) {
          ltmp = GetBits ( ALEVCODE, 
                           IDGAINBITS,
                           hResilience,
                           hVm, 
                           hEPInfo );
          BsPutBit(gc_streamCh, ltmp, IDGAINBITS);
          if (wd == 0) {
            ltmp = GetBits ( ALOCCODE, 
                             ATKLOCBITS_STOP_A,
                             hResilience,
                             hVm, 
                             hEPInfo );
            BsPutBit(gc_streamCh, ltmp, ATKLOCBITS_STOP_A);
          }
          else {
            ltmp = GetBits ( ALOCCODE,
                             ATKLOCBITS_STOP_B,
                             hResilience,
                             hVm, 
                             hEPInfo );
            BsPutBit(gc_streamCh, ltmp, ATKLOCBITS_STOP_B);
          }
        }
      }
    }
    break;
  default:
    return  -1;
  }
  return gc_streamCh->currentBit - loc;
}

#endif

/*
 * read the codebook and boundaries
 */
static int huffcb ( byte*             sect, 
                    int*              sectbits, 
                    int               tot_sfb, 
                    int               sfb_per_sbk, 
                    byte              max_sfb,
                    HANDLE_RESILIENCE hResilience,
                    HANDLE_BUFFER     hVm,
                    HANDLE_EP_INFO    hEPInfo )
{
  int nsect, n, base, bits, len;

  if (debug['s']) {
    PRINT(SE,"total sfb %d\n", tot_sfb);
    PRINT(SE,"sect, top, cb\n");
  }
  bits = sectbits[0];
  len = (1 << bits) - 1;
  nsect = 0;
  for(base = 0; base < tot_sfb && nsect < tot_sfb; ){
    *sect++ = GetBits ( SECT_CB, 
                        LEN_CB,
                        hResilience,
                        hVm, 
                        hEPInfo );

    n = GetBits ( SECT_LEN_INCR, 
                  bits,
                  hResilience,
                  hVm, 
                  hEPInfo );
    if (n==0)
      CommonWarning("\n a section length of 0 ");
    while(n == len && base < tot_sfb){
      base += len;
      n = GetBits ( SECT_LEN_INCR, 
                    bits,
                    hResilience,
                    hVm, 
                    hEPInfo );
    }
    base += n;
    *sect++ = base;
    nsect++;
    if (debug['s'])
      PRINT(SE," %6d %6d %6d \n", nsect, sect[-1], sect[-2]);

    /* insert a zero section for regions above max_sfb for each group */
    if ((sect[-1] % sfb_per_sbk) == max_sfb) {
      base += (sfb_per_sbk - max_sfb);
      *sect++ = 0;
      *sect++ = base;
      nsect++;
      if (debug['s'])
        PRINT(SE,"(%6d %6d %6d)\n", nsect, sect[-1], sect[-2]);
    }
  }

  if(base != tot_sfb || nsect > tot_sfb)
    return 0;
  return nsect;
}
static int getescape ( int               q,
                       HANDLE_RESILIENCE hResilience,
                       HANDLE_BUFFER     hVm, 
                       HANDLE_EP_INFO    hEPInfo )
{
  int i, off, neg;

  if(q < 0){
    if(q != -16)
      return q;
    neg = 1;
  } 
  else{
    if(q != +16)
      return q;
    neg = 0;
  }

  for(i=4;; i++){
    if(GetBits ( ESCAPE_BITS, 
                 1,
                 hResilience,
                 hVm, 
                 hEPInfo ) == 0)
      break;
  }

  if(i > 16){
    off = GetBits ( ESCAPE_BITS,
                    i-16,
                    hResilience,
                    hVm, 
                    hEPInfo ) << 16;
    off |= GetBits ( ESCAPE_BITS, 
                     16,
                     hResilience,
                     hVm, 
                     hEPInfo );
  } 
  else
    off = GetBits ( ESCAPE_BITS, 
                    i,
                    hResilience,
                    hVm, 
                    hEPInfo );

  i = off + (1<<i);
  if(neg)
    i = -i;
  return i;
}

unsigned char  HuffSpecKernelPure ( int*               qp, 
                                    Hcb*               hcb, 
                                    Huffman*           hcw, 
                                    int                step,
                                    unsigned short     table,
                                    HANDLE_BUFFER      hSpecData,
                                    HANDLE_RESILIENCE  hResilience,
                                    HANDLE_EP_INFO     hEPInfo )
                   
{
  int           temp;
  unsigned long codewordBegin;

  codewordBegin = GetReadBitCnt ( hSpecData );
  temp = decode_huff_cw ( hcw,
                          hResilience,
                          hSpecData, 
                          1, 
                          hEPInfo );
  unpack_idx(qp, temp, hcb);
  
  if (!hcb->signed_cb)
    get_sign_bits ( qp, 
                    step,
                    hResilience,
                    hSpecData, 
                    hEPInfo );
  if(table == ESCBOOK){
    qp[0] = getescape ( qp[0],
                        hResilience,
                        hSpecData, 
                        hEPInfo  );
    qp[1] = getescape ( qp[1],
                        hResilience,
                        hSpecData, 
                        hEPInfo );
  }
  return ( GetReadBitCnt ( hSpecData ) - codewordBegin );
}

static void HuffSpecKernelNoReordering ( int*           qp, 
                                         byte*          qpStatus,
                                         Hcb*           hcb,
                                         Huffman*       hcw,
                                         int            step,
                                         unsigned short table,
                                         HANDLE_BUFFER  hSpecData,
                                         HANDLE_RESILIENCE  hResilience,HANDLE_EP_INFO hEPInfo)
{
  unsigned char codewordLength;
  codewordLength = HuffSpecKernelPure ( qp, 
                                        hcb, 
                                        hcw, 
                                        step, 
                                        table, 
                                        hSpecData,
                                        hResilience, hEPInfo );
}

#ifdef VERSION2
static void HuffSpecKernelInclReordering ( int*               qp, 
                                           byte*              qpStatus, 
                                           Hcb*               hcb, 
                                           Huffman*           hcw, 
                                           int                step, 
                                           unsigned short     table,
                                           HANDLE_BUFFER      hSpecData,
                                           HANDLE_RESILIENCE  hResilience,
                                           HANDLE_HCR         hHcrInfo,
                                           HANDLE_EP_INFO     hEPInfo )
{
  unsigned char codewordLength;
  
  StoreBufferPointer ( hSpecData );
  if ( ! GetReorderStatusFlag ( hHcrInfo ) )
    ReorderSpecDecPCWFinishedCheck ( hcb->maxCWLen,
                                     hSpecData,
                                     hResilience,
                                     hHcrInfo,
                                     hEPInfo );
  if ( ! GetReorderStatusFlag ( hHcrInfo ) )
    {
      codewordLength = HuffSpecKernelPure ( qp, 
                                            hcb, 
                                            hcw, 
                                            step, 
                                            table,
                                            hSpecData, 
                                            hResilience, 
                                            hEPInfo );
      ReorderSpec ( codewordLength, 
                    qp, 
                    qpStatus, 
                    table,
                    hcb->maxCWLen, 
                    step, 
                    hResilience,
                    hSpecData,
                    hHcrInfo, 
                    hEPInfo );
    }
  else
    {
      codewordLength = HuffSpecKernelPure ( qp, 
                                            hcb, 
                                            hcw, 
                                            step, 
                                            table,
                                            GetNonPcwBufPtrHdl ( hHcrInfo ), hResilience, hEPInfo );
      ConcealmentDetectError1(step,
                              codewordLength,
                              qpStatus,
                              hcb,
                              hHcrInfo);
    }
}
#endif /*VERSION2*/

static void HuffSpecDecDefault ( Info*         info, 
                                 byte*         sect, 
                                 int           nsect, 
                                 int           quant[],
                                 byte          quantStatus[],
                                 HANDLE_BUFFER hSpecData,
                                 HANDLE_RESILIENCE hResilience,
                                 HANDLE_EP_INFO hEPInfo )
{
  byte*          qpStatus;
  short*         bandp;
  short*         bands;
  unsigned short bottom;
  unsigned short lineCnt; 
  unsigned short lineStart;
  unsigned short sectionCnt;
  unsigned short sfbCnt;
  unsigned short step;
  unsigned short stop;
  unsigned short table;
  unsigned short top;
  int*           qp;      /* probably could be short */
  Hcb*           hcb;
  Huffman*       hcw;

  bands = info->bk_sfb_top;
  bottom = 0;
  lineCnt = 0;
  bandp = bands;
  for( sectionCnt = nsect; sectionCnt; sectionCnt-- ) {
    table = sect[0];
    top = sect[1];
    sect += 2;
    if( (table == 0) ||
        (table == NOISE_HCB) ||
        (table == INTENSITY_HCB) ||
        (table == INTENSITY_HCB2) ) {
      bandp = bands+top;
      lineCnt = bandp[-1];
      bottom = top;
      continue;
    }
    if(table < BY4BOOKS+1)
      step = 4;
    else 
      step = 2;
    hcb       = &book[table];
    hcw       = hcb->hcw;
    qp        = quant       + lineCnt;
    qpStatus  = quantStatus + lineCnt;
    lineStart = lineCnt;
    for ( sfbCnt = bottom; sfbCnt < top; sfbCnt++ ) {
      stop = *bandp++;
      while ( lineCnt < stop ) {
        HuffSpecKernelNoReordering ( qp, 
                                     qpStatus, 
                                     hcb, 
                                     hcw, 
                                     step, 
                                     table,
                                     hSpecData,
                                     hResilience, hEPInfo );
        qp       += step;
        qpStatus += step;
        lineCnt  += step;
      }
      if(debug['q']){
        unsigned short idx;
        PRINT(SE,"\nsect %d %d\n", table, lineStart);
        for (idx = lineStart; idx < lineCnt; idx += 2 )
          PRINT(SE,"%d %d  ",quant[idx],quant[idx+1]);
        PRINT(SE,"\n");
      }
    }
    bottom = top;
  }
}

#ifdef VERSION2
static void HuffSpecDecInterleaved ( Info*         info, 
                                     byte*         sect, 
                                     int           nsect, 
                                     int           quant[], 
                                     byte          quantStatus[],
                                     HANDLE_BUFFER hSpecData,
                                     HANDLE_RESILIENCE hResilience,
                                     HANDLE_HCR    hHcrInfo,
                                     HANDLE_EP_INFO hEPInfo )
{
  Hcb                   *hcb;
  Huffman               *hcw;
  int                   *qp;
  byte                  *qpStatus;
  int                   step;
  int                   i;
  int                   j;
  unsigned short        codeNr               = 0; /* code counter */
  unsigned short        unitsInSpectralDirection; /* number of units in spectral direction */
  unsigned short        unitNrInSpectralDirection;/* unit counter in spectral direction */
  unsigned short        sfb         [NSHORT];     /* number of current sfb           for each group */
  unsigned short        spectralLine[NSHORT];     /* number of current spectral line for each group */
  unsigned short        tableArray  [NSHORT];     /* number of current table         for each group */
  unsigned short        section     [NSHORT];     /* number of current section       for each group */
  unsigned short        groupNr;                  /* number of current group */
  unsigned short        groupNrPast;              /* number of past groups */
  unsigned short        unitInterleaveLevel;
  if ( ! nsect )
    return;
#if 0
  {
    unsigned short i;
    PRINT(SE,"info->num_groups = %hi\n",info->num_groups);
    for ( i = 0; i < info->num_groups; i++ )
      PRINT(SE,"info->group_len[%i] = %hi\n", i, info->group_len[i]);
    for ( i = 0; i < 200; i++)
      PRINT(SE,"info->bk_sfb_top[%3i] = %4hi\n", i, info->bk_sfb_top[i]);
    for ( i = 0; i < MAXBANDS; i += 2 )
      PRINT(SE,"table : %2i, till band : %2i\n", sect[i], sect[i+1]);
    for ( groupNr = 0; groupNr < info->num_groups ; groupNr++ )
      PRINT(SE,"%hu   ", sfb[groupNr]);
    PRINT(SE,"\n");
  }
#endif
  if (debug['i'])
    if ( info->islong )
      fprintf(stderr,"long block interleaving:\n\n");
    else
      fprintf(stderr,"short block interleaving:\n\n");
  qp       = quant;
  qpStatus = quantStatus;
  if ( info->islong )
    unitsInSpectralDirection = LN2 / 4;
  else
    unitsInSpectralDirection = SN2 / 4;
  for ( unitInterleaveLevel = 0; unitInterleaveLevel < UNIT_INTERLEAVING; unitInterleaveLevel++ )
    {
      /* initialization */
      shortclr ( (short*) spectralLine, NSHORT );
      shortclr ( (short*) tableArray,   NSHORT );
      shortclr ( (short*) section,      NSHORT );
      for ( groupNr = 0; groupNr < info->num_groups ; groupNr++ )
        {               
          sfb[groupNr] = groupNr * info->sfb_per_sbk[0];                 /* initialisazion of sfb[]
                                                                            with number of first sfb within each group */
          for ( groupNrPast = 0; groupNrPast < groupNr; groupNrPast++ )  /* initialisazion of spectralLine[] */
            spectralLine[groupNr] += SN2 * info->group_len[groupNrPast]; /* with number of first spectral line within each group */
          spectralLine[groupNr] += 4 * info->group_len[groupNr] * unitInterleaveLevel; /* 4 lines per unitInterleaveLevel has been already decoded */
        }                                                               
      /* loops */
      for ( unitNrInSpectralDirection = unitInterleaveLevel; 
            unitNrInSpectralDirection < unitsInSpectralDirection; 
            unitNrInSpectralDirection += UNIT_INTERLEAVING )
        {    
          for ( groupNr = 0; groupNr < info->num_groups; groupNr++ )          /* for each group in temporal direction */
            {
              while ( info->bk_sfb_top[sfb[groupNr]] <= spectralLine[groupNr] )  /* trace sfb of current group */
                sfb[groupNr]++;
              while ( sect[2 * section[groupNr] + 1] <= sfb[groupNr] )        /* trace section/table of current group */
                section[groupNr]++;
              tableArray[groupNr] = sect[2 * section[groupNr]];
              if( ! ( ( tableArray[groupNr] == 0) ||
                      ( tableArray[groupNr] == INTENSITY_HCB ) ||
                      ( tableArray[groupNr] == INTENSITY_HCB2 ) ) ) 
                {
                  hcb = &book[tableArray[groupNr]];      /* init hcb (pointer) with huffman codebook according table */
                  hcw = hcb->hcw;                        /* init hcw (pointer) with array of codewords of current table */
                  if ( tableArray[groupNr] < BY4BOOKS + 1 )                       /* decide between 2 and 4 dimensional codewords */
                    step = 4;
                  else 
                    step = 2;
                }
              else
                step = 4;
              for ( j = 0; j < info->group_len[groupNr]; j++ )                /* for each unit of the current group in temporal direction */
                {
                  for ( i = 0; i < 4; i += step )                             /* for each codeword of the current unit (4 spectral lines) */
                    {
                      if( ! ( ( tableArray[groupNr] == 0) ||
                              ( tableArray[groupNr] == INTENSITY_HCB ) ||
                              ( tableArray[groupNr] == INTENSITY_HCB2 ) ) ) 
                        {
                          if (debug['i'])
                            {
                              PRINT(SE,"code %3hu, group %1hu, section %2hu, sfb %2hu (%2hu), table %2i", 
                                    codeNr,                                     /* comparison with wrapper */
                                    groupNr,                                    /* comparison with wrapper */
                                    section     [groupNr],                      /* comparison with wrapper */
                                    sfb         [groupNr],                      /* comparison with wrapper */
                                    sfb         [groupNr]%info->sfb_per_sbk[0], /* comparison with wrapper */
                                    tableArray  [groupNr]                       /* comparison with wrapper */
                                    );
#if 1
                              PRINT(SE,", first spectralLine %4hu", spectralLine[groupNr]);
#endif
                              PRINT(SE,"\n");
                            }
                          HuffSpecKernelInclReordering ( qp, 
                                                         qpStatus, 
                                                         hcb, 
                                                         hcw, 
                                                         step, 
                                                         tableArray[groupNr],
                                                         hSpecData,
                                                         hResilience,
                                                         hHcrInfo, hEPInfo );
                          codeNr++;
                        }
                      qp       += step;
                      qpStatus += step;
                      spectralLine[groupNr] += step;
                    }
                  spectralLine[groupNr] += ( UNIT_INTERLEAVING - 1 ) * 4;
                }
            }
        }
    }
  return;
}
#endif /*VERSION2*/

static Float esc_iquant(int q)
{
  if (q > 0) {
    if (q < MAX_IQ_TBL) {
      return((Float)iq_exp_tbl[q]);
    }
    else {
      return(pow(q, 4./3.));
    }
  }
  else {
    q = -q;
    if (q < MAX_IQ_TBL) {
      return((Float)(-iq_exp_tbl[q]));
    }
    else {
      return(-pow(q, 4./3.));
    }
  }
}
 
static int HuffSpecFrame ( Info*             info, 
                           int               nsect, 
                           byte*             sect, 
                           short*            factors, 
                           Float*            coef,
                           HANDLE_RESILIENCE hResilience,
                           HANDLE_BUFFER     hVm,
                           HANDLE_BUFFER     hHcrSpecData,
                           HANDLE_HCR        hHcrInfo,
                           HANDLE_EP_INFO    hEPInfo )
{
  int            quant[LN2]; 
  byte           quantStatus[LN2];
  int            beginSpectralDataBitCnt;
  
  intclr  ( quant, LN2);
  byteclr ( quantStatus, LN2 );
  
  beginSpectralDataBitCnt = GetReadBitCnt(hVm);
#ifdef VERSION2
  if ( GetReorderSpecFlag ( hResilience ) )
    {
      ResetWriteBitCnt ( hHcrSpecData );
      PrepareWriting ( hHcrSpecData );
      TransferBits ( hVm,
                     hHcrSpecData,
                     GetLenOfSpecData ( hHcrInfo ), 
                     hResilience,
                     hEPInfo );
      InitHcr ( hHcrSpecData, hHcrInfo );
      HuffSpecDecInterleaved ( info, 
                               sect, 
                               nsect, 
                               quant, 
                               quantStatus,
                               hHcrSpecData,
                               hResilience,
                               hHcrInfo, hEPInfo );
    CheckDecodingProgress( hHcrSpecData,hResilience, hHcrInfo, hEPInfo );
    }
  else
#endif /*VERSION2*/
    HuffSpecDecDefault ( info, 
                         sect, 
                         nsect, 
                         quant, 
                         quantStatus,
                         hVm,
                         hResilience, hEPInfo );

#ifdef VERSION2
  if ( GetReorderSpecFlag ( hResilience ) )
    ConcealmentCheckLengthOfSpectralData( beginSpectralDataBitCnt, 
                                          GetReadBitCnt(hVm) , 
                                          hHcrInfo );
  
#endif /*VERSION2*/

  /* NEC noisless coding reconstruction */
  if ( (info->islong) && (nec_info.pulse_data_present) )
    nec_nc(quant, &nec_info);

  if (!info->islong) {
    int tmp_spec[LN2];
    deinterleave ( quant,
                   tmp_spec,
                   info->num_groups,   
                   info->group_len,
                   info->sfb_per_sbk,
                   info->sfb_width_short,
                   info->islong,
                   hResilience );
    memcpy(quant,tmp_spec,sizeof(tmp_spec));
  }
  ConcealmentSetCoeffStatus (quantStatus, info, hResilience /*, hConcealment */);

  if ( debug['Q'] )
    PrintSpectralValues ( quant );

  /* inverse quantization */
  {
    unsigned short i;
    for (i=0; i<info->bins_per_bk; i++) {
      coef[i] = esc_iquant(quant[i]);
    }
  }
  /* rescaling */
  {
    unsigned short i;
    unsigned short k;
    int sbk, nsbk, sfb, nsfb, fac, top;
    Float *fp, scale;

    i = 0;
    fp = coef;
    nsbk = info->nsbk;
    for (sbk=0; sbk<nsbk; sbk++) {
      nsfb = info->sfb_per_sbk[sbk];
      k=0;
      for (sfb=0; sfb<nsfb; sfb++) {
        top = info->sbk_sfb_top[sbk][sfb];
        fac = factors[i++]-SF_OFFSET;

        if (fac >= 0 && fac < TEXP) {
          scale = exptable[fac];
        }
        else {
          if (fac == -SF_OFFSET) {
            scale = 0;
          }
          else {
            scale = pow( 2.0,  0.25*fac );
          }
        }
        for ( ; k<top; k++) {
          *fp++ *= scale;
        }
      }
    }
  }
  return 1;
}

int getics ( Info*                    info, 
             int                      common_window, 
             WINDOW_TYPE*             win, 
             Window_shape*            wshape, 
             byte*                    group, 
             byte*                    max_sfb, 
             PRED_TYPE                pred_type, 
             int*                     lpflag, 
             int*                     prstflag, 
             byte*                    cb_map, 
             Float*                   coef, 
             short*                   global_gain, 
             short*                   factors,
             NOK_LT_PRED_STATUS*      nok_ltp, 
             TNS_frame_info*          tns,
             BsBitStream*             gc_streamCh, 
             enum AAC_BIT_STREAM_TYPE bitStreamType,
             HANDLE_RESILIENCE        hResilience,
             HANDLE_BUFFER            hVm,
             HANDLE_BUFFER            hHcrSpecData,
             HANDLE_HCR               hHcrInfo,
             HANDLE_EP_INFO           hEPInfo )
{
  int            nsect;
  int            i;
  int            cb;
  int            top;
  int            bot;
  int            tot_sfb;
  byte           sect[ 2*(MAXBANDS+1) ];
  unsigned long  tmp;
  /*
   * global gain
   */
  *global_gain = 0;
  tmp = GetBits ( GLOBAL_GAIN_MSB_1_5,
                  5,
                  hResilience,
                  hVm, 
                  hEPInfo );
  *global_gain |= (tmp<<3);
  tmp = GetBits ( GLOBAL_GAIN_MSB_6_7,
                  2, 
                  hResilience,
                  hVm, 
                  hEPInfo);
  *global_gain |= (tmp<<1);
  tmp = GetBits ( GLOBAL_GAIN_MSB_8, 
                  1, 
                  hResilience,
                  hVm, 
                  hEPInfo);
  *global_gain |= tmp;
  if (debug['f'])
    PRINT(SE,"global gain: %3d\n", *global_gain);
  if ( bitStreamType != SCALEABLE ){
    memcpy(info, winmap[*win], sizeof(Info));
  }
  if (( !common_window ) && ( bitStreamType != SCALEABLE )) {
    get_ics_info ( win, 
                   wshape, 
                   group, 
                   max_sfb, 
                   pred_type, 
                   lpflag, 
                   prstflag, 
                   bitStreamType,
                   hResilience,
                   hVm,
                   hEPInfo);
    memcpy(info, winmap[*win], sizeof(Info));
  } else {
    if( info->nsbk == 1 ) {
      group[0] = 1;
    } else {
      int sum = 0;
      for( i=0; i<info->num_groups; i++ ) {
        sum  += info->group_len[i];
        group[i]  = sum;
      }
    }
  }

  /* calculate total number of sfb for this grouping */
  if (*max_sfb == 0) {
    tot_sfb = 0;
  }
  else {
    i=0;
    tot_sfb = info->sfb_per_sbk[0];
    if (debug['f'])PRINT(SE,"tot sfb %d %d\n", i, tot_sfb);
    while (group[i++] < info->nsbk) {
      tot_sfb += info->sfb_per_sbk[0];
      if (debug['f'])PRINT(SE,"tot sfb %d %d\n", i, tot_sfb);
    }
  }

  /* 
   * section data
   */
  nsect = huffcb ( sect, 
                   info->sectbits, 
                   tot_sfb, 
                   info->sfb_per_sbk[0], 
                   *max_sfb,
                   hResilience,
                   hVm, 
                   hEPInfo );
  if(nsect==0 && *max_sfb>0)
    return 0;

  /* generate "linear" description from section info
   * stored as codebook for each scalefactor band and group
   */
  if (nsect) {
    bot = 0;
    for (i=0; i<nsect; i++) {
      cb = sect[2*i];
      top = sect[2*i + 1];
      for (; bot<top; bot++)
        *cb_map++ = cb;
      bot = top;
    }
  }  else {
    for (i=0; i<MAXBANDS; i++)
      cb_map[i] = 0;
  }

  /* calculate band offsets
   * (because of grouping and interleaving this cannot be
   * a constant: store it in info.bk_sfb_top)
   */
  calc_gsfb_table(info, group);

  /*
   * scale factor data
   */
  if(!hufffac ( info, 
                group, 
                nsect, 
                sect, 
                *global_gain, 
                factors,
                hVm,hResilience, hEPInfo ) )
    return 0;

  /*
   * NEC noiseless coding
   */
  if ((nec_info.pulse_data_present = GetBits ( PULSE_DATA_PRESENT, 
                                               LEN_PULSE_PRES,
                                               hResilience,
                                               hVm, 
                                               hEPInfo ))) {
    if (info->islong) {
      get_nec_nc ( &nec_info,
                   hResilience,
                   hVm, 
                   hEPInfo );
    }
    else {
      CommonExit(1, "Pulse data not allowed for short blocks\n");    
    }
  }
  if (bitStreamType  !=  SCALEABLE){  
    /*
     * Nokia long term prediction
     */
    if (pred_type == NOK_LTP)
      nok_lt_decode( (WINDOW_TYPE)win, 
                     *max_sfb, 
                     nok_ltp->sbk_prediction_used,
                     nok_ltp->sfb_prediction_used, 
                     &nok_ltp->weight,
                     nok_ltp->delay,
                     hResilience,
                     hVm, 
                     hEPInfo );
    /*
     * tns data
     */
    if (GetBits ( TNS_DATA_PRESENT, 
                  LEN_TNS_PRES,
                  hResilience,
                  hVm, 
                  hEPInfo )) {
      get_tns ( info, 
                tns, 
                hResilience,
                hVm, 
                hEPInfo );
    }
    else {
      clr_tns ( info, tns );
    }
    
    /*
     * Sony gain control
     */
    if (GetBits ( GAIN_CONTROL_DATA_PRESENT, 
                  LEN_GAIN_PRES,
                  hResilience,
                  hVm, 
                  hEPInfo )) {
#ifdef  SRS
      get_gcBuf( *win,
                 gc_streamCh,
                 hResilience,
                 hVm, 
                 hEPInfo);
#else
      CommonExit(1, "Gain control not implemented\n");
#endif
    }
  }
#ifdef VERSION2
  if ( GetLenOfLongestCwFlag ( hResilience ) )
    ReadLenOfLongestCw ( hHcrInfo, 
                         hResilience, 
                         hVm, 
                         hEPInfo );
  if ( GetReorderSpecFlag ( hResilience ) )
    ReadLenOfSpecData ( hHcrInfo, 
                        hResilience,
                        hVm, 
                        hEPInfo );
#endif /*VERSION2*/
  return HuffSpecFrame ( info, 
                         nsect, 
                         sect, 
                         factors,
                         coef,
                         hResilience,
                         hVm,
                         hHcrSpecData,
                         hHcrInfo, hEPInfo );
}

/* 
 * get scale factors
 */
int hufffac ( Info*         info, 
              byte*         group, 
              int           nsect, 
              byte*         sect,
              short         global_gain, 
              short*        factors,
              HANDLE_BUFFER hVm,
              HANDLE_RESILIENCE hResilience,
              HANDLE_EP_INFO    hEPInfo )
 
{
  Hcb *hcb;
  Huffman *hcw;
  int i, b, bb, t, n, sfb, top, fac, is_pos;
  int factor_transmitted[MAXBANDS], *fac_trans;
  int noise_pcm_flag = 1;
  int noise_nrg;

  /* clear array for the case of max_sfb == 0 */
  intclr(factor_transmitted, MAXBANDS);
  shortclr(factors, MAXBANDS);

  sfb = 0;
  fac_trans = factor_transmitted;
  for(i = 0; i < nsect; i++){
    top = sect[1];              /* top of section in sfb */
    t = sect[0];                /* codebook for this section */
    sect += 2;
    for(; sfb < top; sfb++) {
      fac_trans[sfb] = t;
    }
  }

  /* scale factors are dpcm relative to global gain
   * intensity positions are dpcm relative to zero
   */
  fac = global_gain;
  is_pos = 0;
  noise_nrg = global_gain - NOISE_OFFSET;

  /* get scale factors */
  hcb = &book[BOOKSCL];
  hcw = hcb->hcw;
  bb = 0;
  if (debug['f'])
    PRINT(SE,"scale factors\n");
  for(b = 0; b < info->nsbk; ){
    n = info->sfb_per_sbk[b];
    b = *group++;
    for(i = 0; i < n; i++){
      switch (fac_trans[i]) {
      case ZERO_HCB:        /* zero book */
        break;
      default:              /* spectral books */
        /* decode scale factor */
        t = decode_huff_cw ( hcw,
                             hResilience,
                             hVm, 
                             0, 
                             hEPInfo );
        fac += t - MIDFAC;    /* 1.5 dB */

        if (debug['f'])
          PRINT(SE,"%3d:%3d", i, fac);
        if(fac >= 2*maxfac || fac < 0)
          return 0;
        factors[i] = fac;
        break;
      case BOOKSCL:         /* invalid books */
        return 0;
      case INTENSITY_HCB:           /* intensity books */
      case INTENSITY_HCB2:
        /* decode intensity position */
        t = decode_huff_cw ( hcw,
                             hResilience,
                             hVm, 
                             0, 
                             hEPInfo );
        is_pos += t - MIDFAC;
        factors[i] = is_pos;
        break;
      case NOISE_HCB:       /* noise books */
        /* decode noise energy */
        if (noise_pcm_flag) {
          noise_pcm_flag = 0;
          t = GetBits ( PCM_BITS, 
                        NOISE_PCM_BITS,
                        hResilience,
                        hVm, 
                        hEPInfo ) - NOISE_PCM_OFFSET;
        }
        else
          t = decode_huff_cw ( hcw,
                               hResilience,
                               hVm, 
                               0, 
                               hEPInfo ) - MIDFAC;
        noise_nrg += t;
        if (debug['f'])
          PRINT(SE,"\n%3d %3d (noise, code %d)", i, noise_nrg, t);
        factors[i] = noise_nrg;
        break;
      }
      if (debug['f'])
        PRINT(SE,"%3d: %3d %3d\n", i, fac_trans[i], factors[i]);
    }
    if (debug['f'])
      PRINT(SE,"\n");

    /* expand short block grouping */
    if (!(info->islong)) {
      for(bb++; bb < b; bb++) {
        for (i=0; i<n; i++) {
          factors[i+n] = factors[i];
        }
        factors += n;
      }
    }
    fac_trans += n;
    factors += n;
  }
  return 1;
}

/* rm2 inverse quantization
 * escape books need ftn call
 * other books done via macro
 */
#define iquant( q ) ( q >= 0 ) ? \
(Float)iq_exp_tbl[ q ] : (Float)(-iq_exp_tbl[ - q ])


