#include <stdio.h>
#include <string.h>
#include "../../crc.h"
#include "ac3_header.h"
#include "ac3_parser.h"
#include "ac3_bitalloc.h"
#include "ac3_dither.h"
#include "ac3_tables.h"







#define EXP_REUSE 0
#define EXP_D15   1
#define EXP_D25   2
#define EXP_D45   3

#define DELTA_BIT_REUSE    0
#define DELTA_BIT_NEW      1
#define DELTA_BIT_NONE     2
#define DELTA_BIT_RESERVED 3








class Quantizer
{
protected:
  int q3_cnt, q5_cnt, q11_cnt;
  sample_t q3[2];
  sample_t q5[2];
  sample_t q11;

public:
  Quantizer(): q3_cnt(0), q5_cnt(0), q11_cnt(0) {};

  void get_coeff(ReadBS &bs, sample_t *s, int8_t *bap, int8_t *exp, int n, bool dither);
};





AC3Parser::AC3Parser()
{
  frames = 0;
  errors = 0;

  do_crc = true;
  do_dither = true;
  do_imdct = true;

  
  samples.allocate(AC3_NCHANNELS, AC3_FRAME_SAMPLES);
  delay.allocate(AC3_NCHANNELS, AC3_BLOCK_SAMPLES);

  reset();
}

AC3Parser::~AC3Parser()
{}




const HeaderParser *
AC3Parser::header_parser() const
{
  return &ac3_header;
}

void 
AC3Parser::reset()
{
  memset((AC3Info*)this, 0, sizeof(AC3Info));
  memset((AC3FrameState*)this, 0, sizeof(AC3FrameState));

  spk = spk_unknown;
  frame = 0;
  frame_size = 0;
  bs_type = 0;

  block = 0;
  samples.zero();
  delay.zero();
}

bool
AC3Parser::parse_frame(uint8_t *frame, size_t size)
{
  if (!start_parse(frame, size))
  {
    errors++;
    return false;
  }

  if (!parse_header())
  {
    errors++;
    return false;
  }

  while (block < AC3_NBLOCKS)
    if (!decode_block())
    {
      errors++;
      return false;
    }

  frames++;

  return true;
}

size_t
AC3Parser::stream_info(char *buf, size_t size) const 
{
  char info[1024];
  int max_freq = (cplinu? MAX(endmant[0], cplendmant): endmant[0]) * spk.sample_rate / 512000;
  int cpl_freq = cplinu? cplstrtmant * spk.sample_rate / 512000: max_freq;

  size_t len = sprintf(info,
    "AC3\n"
    "speakers: %s\n"
    "sample rate: %iHz\n"
    "bitrate: %ikbps\n"
    "stream: %s\n"
    "frame size: %i bytes\n"
    "nsamples: %i\n"
    "bsid: %i\n"
    "clev: %.1fdB (%.4f)\n"
    "slev: %.1fdB (%.4f)\n"
    "dialnorm: -%idB\n"
    "bandwidth: %ikHz/%ikHz\n\0",
    spk.mode_text(),
    spk.sample_rate,
    bitrate,
    (bs_type == BITSTREAM_8? "8 bit": "16bit low endian"), 
    frame_size,
    AC3_FRAME_SAMPLES,
    bsid, 
    value2db(clev), clev,
    value2db(slev), slev,
    dialnorm,
    cpl_freq, max_freq);

  if (len + 1 > size) len = size - 1;
  memcpy(buf, info, len + 1);
  buf[len] = 0;
  return len;
}

size_t
AC3Parser::frame_info(char *buf, size_t size) const 
{
  if (buf && size) buf[0] = 0;
  return 0;
}




bool
AC3Parser::start_parse(uint8_t *_frame, size_t _size)
{
  HeaderInfo hinfo;

  if (!ac3_header.parse_header(_frame, &hinfo))
    return false;

  if (hinfo.frame_size > _size)
    return false;

  spk = hinfo.spk;
  spk.format = FORMAT_LINEAR;
  frame = _frame;
  frame_size = hinfo.frame_size;
  bs_type = hinfo.bs_type;

  if (do_crc)
    if (!crc_check())
      return false;

  bs.set_ptr(frame, bs_type);
  return true;
}

bool
AC3Parser::crc_check()
{
  

  uint32_t crc;

  
  
  
  
  
  

  size_t frame_size1 = ((frame_size >> 2) + (frame_size >> 4)) << 1;
  crc = crc16.calc(0, frame + 2, frame_size1 - 2, bs_type);
  if (crc) 
    return false;

  
  
  
  

  crc = crc16.calc(0, frame + frame_size1, frame_size - frame_size1, bs_type);
  if (crc) 
    return false;

  return true;
}

bool 
AC3Parser::parse_header()

{
  
  

  bs.get(32);

  
  

  fscod      = bs.get(2);            
  frmsizecod = bs.get(6);            
  bsid       = bs.get(5);            
  bsmod      = bs.get(3);            
  acmod      = bs.get(3);            

  halfrate = halfrate_tbl[bsid];
  bitrate = bitrate_tbl[frmsizecod >> 1];

  if ((acmod & 1) && (acmod != 1))
    clev = clev_tbl[bs.get(2)];      
  else
    clev = 1.0;

  if (acmod & 4)
    slev = slev_tbl[bs.get(2)];      
  else
    slev = 1.0;

  if (acmod == AC3_MODE_STEREO)
    dsurmod  = bs.get(2);            
  else
    dsurmod  = 0;

  lfeon      = bs.get_bool();        
  dialnorm   = bs.get(5);            

  compre     = bs.get_bool();        
  if (compre)
    compr    = bs.get(8);            
  else
    compr    = 0;

  langcode   = bs.get_bool();        
  if (langcode)
    langcod  = bs.get(8);            
  else
    langcod  = 0;
                                     
  audprodie  = bs.get_bool();        
  if (audprodie)
  {
    mixlevel = bs.get(5) + 80;       
    roomtyp  = bs.get(2);            
  }
  else
  {
    mixlevel = 0;
    roomtyp  = 0;
  }

  if (acmod == AC3_MODE_DUAL)            
  {                                  
    dialnorm2  = bs.get(5);          
                                     
    compr2e    = bs.get_bool();      
    if (compr2e)                     
      compr2   = bs.get(8);          
    else
      compr2   = 0;
                                     
    langcod2e  = bs.get_bool();      
    if (langcod2e)
      langcod  = bs.get(8);          
    else
      langcod  = 0;

    audprodi2e = bs.get_bool();      
    if (audprodi2e)
    {
      mixlevel2 = bs.get(5) + 80;    
      roomtyp2  = bs.get(2);         
    }
    else
    {
      mixlevel2 = 0;
      roomtyp2  = 0;
    }
  }
  else
  {
    dialnorm2  = 0;
    compr2e    = false;
    compr2     = 0;
    langcod2e  = false;
    langcod    = 0;
    audprodi2e = false;
    mixlevel2  = 0;
    roomtyp2   = 0;
  }

  copyrightb = bs.get_bool();        
  origbs     = bs.get_bool();        

  if (bs.get_bool())                 
  {
    timecode.hours = bs.get(5);
    timecode.mins  = bs.get(6);
    timecode.secs  = bs.get(3) << 4;
  }

  if (bs.get_bool())                 
  {
    timecode.secs  += bs.get(3);
    timecode.frames = bs.get(5);
    timecode.fracs  = bs.get(6);
  }
  
  if (bs.get_bool())                 
  {
    int addbsil = bs.get(6);         
    while (addbsil--)
      bs.get(8);                     
  }

  
  

  block    = 0;

  dynrng   = 1.0;
  dynrng2  = 1.0;

  cpldeltbae = DELTA_BIT_NONE;
  deltbae[0] = DELTA_BIT_NONE;
  deltbae[1] = DELTA_BIT_NONE;
  deltbae[2] = DELTA_BIT_NONE;
  deltbae[3] = DELTA_BIT_NONE;
  deltbae[4] = DELTA_BIT_NONE;

  return true;
}

bool 
AC3Parser::decode_block()
{
  samples_t d = delay;
  samples_t s = samples;
  s += (block * AC3_BLOCK_SAMPLES);

  if (block >= AC3_NBLOCKS || !parse_block())
  {
    block = AC3_NBLOCKS; 
    return false;
  }
  parse_coeff(s);

  if (do_imdct)
  {
    int nfchans = spk.lfe()? spk.nch() - 1: spk.nch();
    for (int ch = 0; ch < nfchans; ch++)
      if (blksw[ch])
        imdct.imdct_256(s[ch], delay[ch]);
      else
        imdct.imdct_512(s[ch], delay[ch]);

    if (spk.lfe())
      imdct.imdct_512(s[nfchans], d[nfchans]);
  }

  block++;
  return true;
}

bool
AC3Parser::parse_block()
{
  int nfchans = nfchans_tbl[acmod];
  int ch, bnd;

  
  
  
  
  
  int bitalloc = 0;

  for (ch = 0; ch < nfchans; ch++)
    blksw[ch] = bs.get_bool();                

  for (ch = 0; ch < nfchans; ch++)
    dithflag[ch] = bs.get_bool();             

  
  
  if (!do_dither)
    for (ch = 0; ch < nfchans; ch++)
      dithflag[ch] = 0;

  if (bs.get_bool())                          
  {
    int32_t dynrng_word = bs.get_signed(8);   
    dynrng = (((dynrng_word & 0x1f) | 0x20) << 13) * scale_factor[(3 - (dynrng_word >> 5)) & 7];
  }

  if (acmod == AC3_MODE_DUAL)
    if (bs.get_bool())                        
    {
      int32_t dynrng_word = bs.get_signed(8); 
      dynrng2 = (((dynrng_word & 0x1f) | 0x20) << 13) * scale_factor[(3 - (dynrng_word >> 5)) & 7];
    }

  
  
  

  if (bs.get_bool())                          
  {
    cplinu = bs.get_bool();                   
    if (cplinu)
    {
      if (acmod == AC3_MODE_MONO || acmod == AC3_MODE_DUAL)
        return false;                         
                                              
      for (ch = 0; ch < nfchans; ch++)
        chincpl[ch] = bs.get_bool();          

      if (acmod == AC3_MODE_STEREO)
        phsflginu = bs.get_bool();            

      int cplbegf = bs.get(4);                
      int cplendf = bs.get(4);                

      int ncplsubnd = cplendf - cplbegf + 3;
      if (ncplsubnd < 0)
        return false;                         

      cplstrtmant = cplbegf * 12 + 37;
      cplendmant  = cplendf * 12 + 73;

      ncplbnd = 0;
      cplbnd[0] = cplstrtmant + 12;
      for (bnd = 0; bnd < ncplsubnd - 1; bnd++)
        if (bs.get_bool())                    
          cplbnd[ncplbnd] += 12;
        else
        {
          ncplbnd++;
          cplbnd[ncplbnd] = cplbnd[ncplbnd - 1] + 12;
        }
      ncplbnd++; 
    }
    else
    {
      chincpl[0] = false;
      chincpl[1] = false;
      chincpl[2] = false;
      chincpl[3] = false;
      chincpl[4] = false;
    }
  }
  else 
    if (!block)                               
      return false;

  
  
  
  

  if (cplinu)
  {
    bool cplcoe = false;
    int  mstrcplco;
    int  cplcoexp;
    int  cplcomant;

    for (ch = 0; ch < nfchans; ch++)
      if (chincpl[ch])
        if (bs.get_bool())                    
        {
          cplcoe = true;

          mstrcplco = bs.get(2) * 3;          
          for (bnd = 0; bnd < ncplbnd; bnd++)
          {
            cplcoexp  = bs.get(4);            
            cplcomant = bs.get(4);            

            if (cplcoexp == 15)
              cplcomant <<= 14;
            else
              cplcomant = (cplcomant | 0x10) << 13;

            cplco[ch][bnd] = cplcomant * scale_factor[cplcoexp + mstrcplco];
          } 
        } 

    if (acmod == AC3_MODE_STEREO && phsflginu && cplcoe)
      for (bnd = 0; bnd < ncplbnd; bnd++)
        if (bs.get_bool())                    
          cplco[1][bnd] = -cplco[1][bnd];
  }

  
  
  

  if (acmod == AC3_MODE_STEREO)
    if (bs.get_bool())                        
    {
      bnd = 0;
      rematflg = 0;
      int endbin = cplinu? cplstrtmant: 253;
      do
        rematflg |= bs.get(1) << bnd;         
      while (rematrix_tbl[bnd++] < endbin);
    }

  
  
  

  int cplexpstr;
  int chexpstr[5];
  int lfeexpstr;

  if (cplinu)
  {
    cplexpstr = bs.get(2);                    
    if (cplexpstr == EXP_REUSE && block == 0) 
      return false;
  }

  for (ch = 0; ch < nfchans; ch++)
  {
    chexpstr[ch] = bs.get(2);                 
    if (chexpstr[ch] == EXP_REUSE && block == 0) 
      return false;
  }

  if (lfeon)
  {
    lfeexpstr = bs.get(1);                    
    if (lfeexpstr == EXP_REUSE && block == 0) 
      return false;
  }

  for (ch = 0; ch < nfchans; ch++)
    if (chexpstr[ch] != EXP_REUSE)
      if (chincpl[ch])
        endmant[ch] = cplstrtmant;
      else
      {
        int chbwcod = bs.get(6);              

        if (chbwcod > 60)
          return false;                       

        endmant[ch] = chbwcod * 3 + 73;
      }

  if (cplinu && cplexpstr != EXP_REUSE)
  {
    bitalloc |= 1 << 6; 
    int ncplgrps = (cplendmant - cplstrtmant) / (3 << (cplexpstr - 1));
    int8_t cplabsexp = bs.get(4) << 1;
    if (!parse_exponents(cplexps + cplstrtmant, cplabsexp, cplexpstr, ncplgrps))
      return false;
  }

  for (ch = 0; ch < nfchans; ch++)
    if (chexpstr[ch] != EXP_REUSE)
    {
      bitalloc |= 1 << ch; 
      int nexpgrps;
      switch (chexpstr[ch])
      {
        case EXP_D15: nexpgrps = (endmant[ch] - 1)     / 3;  break;
        case EXP_D25: nexpgrps = (endmant[ch] - 1 + 3) / 6;  break;
        case EXP_D45: nexpgrps = (endmant[ch] - 1 + 9) / 12; break;
      }

      exps[ch][0] = bs.get(4);
      if (!parse_exponents(exps[ch] + 1, exps[ch][0], chexpstr[ch], nexpgrps))
        return false;

      gainrng[ch] = bs.get(2);                
    }

  if (lfeon && lfeexpstr != EXP_REUSE)
  {
    bitalloc |= 1 << 5; 
    lfeexps[0] = bs.get(4);
    if (!parse_exponents(lfeexps + 1, lfeexps[0], lfeexpstr, 2))
      return false;
  }

  
  
  

  if (bs.get_bool())                          
  {
    bitalloc |= -1; 
    sdecay = sdecay_tbl[bs.get(2)];           
    fdecay = fdecay_tbl[bs.get(2)];           
    sgain  = sgain_tbl[bs.get(2)];            
    dbknee = dbknee_tbl[bs.get(2)];           
    floor  = floor_tbl[bs.get(3)];            
  }
  else 
    if (block == 0)                           
      return false;

  if (bs.get_bool())                          
  {
    bitalloc |= -1; 
    int csnroffst = bs.get(6);                
    if (cplinu)
    {
      int cplfsnroffst = bs.get(4);           
      cplsnroffset = (((csnroffst - 15) << 4) + cplfsnroffst) << 2;
      cplfgain = fgain_tbl[bs.get(3)];        
    }

    for (ch = 0; ch < nfchans; ch++)
    {      
      int fsnroffst = bs.get(4);              
      snroffset[ch] = (((csnroffst - 15) << 4) + fsnroffst) << 2;
      fgain[ch] = fgain_tbl[bs.get(3)];       
    }

    if (lfeon)
    {      
      int lfefsnroffst = bs.get(4);           
      lfesnroffset = (((csnroffst - 15) << 4) + lfefsnroffst) << 2;
      lfefgain = fgain_tbl[bs.get(3)];        
    }
  }
  else 
    if (block == 0)                           
      return false;

  if (cplinu)                                 
    if (bs.get_bool())                        
    {
      bitalloc |= 1 << 6; 
      cplfleak = (bs.get(3) << 8) + 768;      
      cplsleak = (bs.get(3) << 8) + 768;      
    }
    else 
      if (block == 0)                         
        return false;

  
  
  

  if (bs.get_bool())                          
  {
    bitalloc |= -1; 

    if (cplinu)
    {
      cpldeltbae = bs.get(2);                 
      if (cpldeltbae == DELTA_BIT_REUSE && block == 0)
        return false;                         
    }

    for (ch = 0; ch < nfchans; ch++)
    {
      deltbae[ch] = bs.get(2);                
      if (deltbae == DELTA_BIT_REUSE && block == 0)
        return false;                         
    }

    if (cplinu && cpldeltbae == DELTA_BIT_NEW)
      if (!parse_deltba(cpldeltba))
        return false;

    for (ch = 0; ch < nfchans; ch++)
      if (deltbae[ch] == DELTA_BIT_NEW)
        if (!parse_deltba(deltba[ch]))
          return false;
  }

  
  
  

  if (bs.get_bool())
  {
    int skipl = bs.get(9);
    while (skipl--)
      bs.get(8);
  }

  
  
  

  if (bitalloc)
  {
    bool got_cplchan = false;
    BAP_BitCount counter;

    for (ch = 0; ch < nfchans; ch++)
    {
      if (bitalloc & (1 << ch))
      {
        bit_alloc(
          bap[ch], exps[ch],
          deltbae[ch], deltba[ch],
          0, endmant[ch], 
          fscod, halfrate, 
          sdecay, fdecay, 
          sgain, fgain[ch], 
          dbknee, floor, 
          0, 0, 
          snroffset[ch]);

        counter.add_bap(bap[ch], 0, endmant[ch]);
      }

      if (cplinu && !got_cplchan && (bitalloc & (1 << 6)))
      {
        got_cplchan = true;
        bit_alloc(
          cplbap, cplexps, 
          cpldeltbae, cpldeltba,
          cplstrtmant, cplendmant, 
          fscod, halfrate, 
          sdecay, fdecay, 
          sgain, cplfgain, 
          dbknee, floor, 
          cplfleak, cplsleak, 
          cplsnroffset);

        counter.add_bap(cplbap, cplstrtmant, cplendmant);
      }
    }

    if (lfeon && bitalloc & (1 << 5))
    {
      bit_alloc(
        lfebap, lfeexps,
        DELTA_BIT_NONE, 0,
        0, 7, 
        fscod, halfrate, 
        sdecay, fdecay, 
        sgain, lfefgain, 
        dbknee, floor, 
        0, 0, 
        lfesnroffset);

      counter.add_bap(lfebap, 0, 7);
    }

    if (bs.get_pos() + counter.bits > frame_size * 8)
      return false;
  }

  return true;
}

bool
AC3Parser::parse_exponents(int8_t *exps, int8_t absexp, int expstr, int nexpgrps)
{
  int expgrp;

  switch (expstr)
  {
  case EXP_D15:
    while (nexpgrps--)
    {
      expgrp = bs.get(7);

      absexp += exp1_tbl[expgrp];
      if (absexp > 24) return false;
      *(exps++) = absexp;

      absexp += exp2_tbl[expgrp];
      if (absexp > 24) return false;
      *(exps++) = absexp;

      absexp += exp3_tbl[expgrp];
      if (absexp > 24) return false;
      *(exps++) = absexp;
    }
    break;

  case EXP_D25:
    while (nexpgrps--)
    {
      expgrp = bs.get(7);

      absexp += exp1_tbl[expgrp];
      if (absexp > 24) return false;
      *(exps++) = absexp;
      *(exps++) = absexp;

      absexp += exp2_tbl[expgrp];
      if (absexp > 24) return false;
      *(exps++) = absexp;
      *(exps++) = absexp;

      absexp += exp3_tbl[expgrp];
      if (absexp > 24) return false;
      *(exps++) = absexp;
      *(exps++) = absexp;
    }
    break;

  case EXP_D45:
    while (nexpgrps--)
    {
      expgrp = bs.get(7);
      if (expgrp >= 125) 
        return false;

      absexp += exp1_tbl[expgrp];
      if (absexp > 24) return false;
      *(exps++) = absexp;
      *(exps++) = absexp;
      *(exps++) = absexp;
      *(exps++) = absexp;

      absexp += exp2_tbl[expgrp];
      if (absexp > 24) return false;
      *(exps++) = absexp;
      *(exps++) = absexp;
      *(exps++) = absexp;
      *(exps++) = absexp;

      absexp += exp3_tbl[expgrp];
      if (absexp > 24) return false;
      *(exps++) = absexp;
      *(exps++) = absexp;
      *(exps++) = absexp;
      *(exps++) = absexp;
    }
    break;
  }

  return true;
}

bool
AC3Parser::parse_deltba(int8_t *deltba)
{
  int deltnseg, deltlen, delta, band;

  memset(deltba, 0, 50);

  deltnseg = bs.get(3) + 1;                   
  band = 0;
  while (deltnseg--)
  {
    band += bs.get(5);                        
    deltlen = bs.get(4);                      
    delta = bs.get(3);                        

    if (delta >= 4)
      delta = (delta - 3) << 7;
    else
      delta = (delta - 4) << 7;

    if (band + deltlen >= 50)
      return false;

    while (deltlen--)
      deltba[band++] = delta;
  }

  return true;
}

void 
AC3Parser::parse_coeff(samples_t samples)
{
  int ch, bnd, s;
  Quantizer q;

  int nfchans = nfchans_tbl[acmod];
  bool got_cplchan = false;

  
  

  for (ch = 0; ch < nfchans; ch++)
  {
    
    q.get_coeff(bs, samples[ch], bap[ch], exps[ch], endmant[ch], dithflag[ch]);

    if (chincpl[ch] && !got_cplchan)
    {
      
      got_cplchan = true;
      q.get_coeff(bs, samples[ch] + cplstrtmant, cplbap + cplstrtmant, cplexps + cplstrtmant, cplendmant - cplstrtmant, false);

      
      for (int ch2 = ch + 1; ch2 < nfchans; ch2++)
        if (chincpl[ch2])
          memcpy(samples[ch2] + cplstrtmant, samples[ch] + cplstrtmant, (cplendmant - cplstrtmant) * sizeof(sample_t));
    }
  }

  if (lfeon)
  {
    q.get_coeff(bs, samples[nfchans], lfebap, lfeexps, 7, false);
    memset(samples[nfchans] + 7, 0, 249 * sizeof(sample_t));
  }

  
  for (ch = 0; ch < nfchans; ch++)
    if (chincpl[ch] && dithflag[ch])
      for (s = cplstrtmant; s < cplendmant; s++)
        if (!cplbap[s])
          samples[ch][s] = dither_gen() * scale_factor[cplexps[s]];

  
  for (ch = 0; ch < nfchans; ch++)
    if (chincpl[ch])
    {
      s = cplstrtmant;
      for (bnd = 0; bnd < ncplbnd; bnd++)
        while (s < cplbnd[bnd])
          samples[ch][s++] *= cplco[ch][bnd];
    }

  
  for (ch = 0; ch < nfchans; ch++)
    if (chincpl[ch])
      memset(samples[ch] + cplendmant, 0, (256 - cplendmant) * sizeof(sample_t));
    else
      memset(samples[ch] + endmant[ch], 0, (256 - endmant[ch]) * sizeof(sample_t));

  
  

  if (acmod == AC3_MODE_STEREO) 
  {
    int bin = 13;
    int bnd = 0;
    int band_end = 0;
    int last_bin = MIN(endmant[0], endmant[1]);
    int remat = rematflg;
    do
    {
      if (!(remat & 1))
      {
        remat >>= 1;
        bin = rematrix_tbl[bnd++];
        continue;
      }
      remat >>= 1;
      band_end = rematrix_tbl[bnd++];

      if (band_end > last_bin)
        band_end = last_bin;

      do 
      {
        sample_t tmp0 = samples[0][bin];
        sample_t tmp1 = samples[1][bin];
        samples[0][bin] = tmp0 + tmp1;
        samples[1][bin] = tmp0 - tmp1;
      } while (++bin < band_end);
    } while (bin < last_bin);
  }
}

void 
Quantizer::get_coeff(ReadBS &bs, sample_t *s, int8_t *bap, int8_t *exp, int n, bool dither)
{
  int ibap;
  while (n--)
  {
    ibap = *bap++;
    switch (ibap)
    {
      case 0:
        if (dither)
          *s++ = dither_gen() * scale_factor[*exp++];
        else
        {
          *s++ = 0;
          exp++;
        }
        break;

      case 1: 
        
        if (q3_cnt--)
          *s++ = q3[q3_cnt] * scale_factor[*exp++];
        else
        {
          int code = bs.get(5);
          q3[0] = q3_3_tbl[code];
          q3[1] = q3_2_tbl[code];
          q3_cnt = 2;
          *s++ = q3_1_tbl[code] * scale_factor[*exp++];
        }
        break;

      case 2:  
        
        if (q5_cnt--)
          *s++ = q5[q5_cnt] * scale_factor[*exp++];
        else
        {
          int code = bs.get(7);
          q5[0] = q5_3_tbl[code];
          q5[1] = q5_2_tbl[code];
          q5_cnt = 2;
          *s++ = q5_1_tbl[code] * scale_factor[*exp++];
        }
        break;

      case 3:
        *s++ = q7_tbl[bs.get(3)] * scale_factor[*exp++];
        break;

      case 4:
        
        if (q11_cnt--)
          *s++ = q11 * scale_factor[*exp++];
        else
        {
          int code = bs.get(7);
          q11 = q11_2_tbl[code];
          q11_cnt = 1;
          *s++ = q11_1_tbl[code] * scale_factor[*exp++];
        }
        break;

      case 5:
        *s++ = q15_tbl[bs.get(4)] * scale_factor[*exp++];
        break;

      case 14:       
        *s++ = (bs.get_signed(14) << 2) * scale_factor[*exp++];
        break;

      case 15: 
        *s++ = bs.get_signed(16) * scale_factor[*exp++];
        break;

      default: 
        *s++ = (bs.get_signed(ibap - 1) << (16 - (ibap - 1))) * scale_factor[*exp++];
        break;
    }
  }
}
