/*____________________________________________________________________________
	
	FreeAmp - The Free MP3 Player

        MP3 Decoder originally Copyright (C) 1995-1997 Xing Technology
        Corp.  http://www.xingtech.com

	Portions Copyright (C) 1998-1999 EMusic.com

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
	
	$Id: uph.c,v 1.1.1.1 2001/09/26 07:05:07 bardtx Exp $
____________________________________________________________________________*/

/****  uph.c  ***************************************************

Layer 3 audio
 huffman decode


******************************************************************/
#include <float.h>
#include <math.h>

#include "L3.h"
#include "mhead.h"

#ifdef _MSC_VER
#pragma warning(disable: 4505)
#endif

/*===============================================================*/

/* max bits required for any lookup - change if htable changes */
/* quad required 10 bit w/signs  must have (MAXBITS+2) >= 10   */
#define MAXBITS 9

static HUFF_ELEMENT huff_table_0[4] =
{{0}, {0}, {0}, {64}};			/* dummy must not use */

#include "htable.h"

/*-- 6 bit lookup (purgebits, value) --*/
static unsigned char quad_table_a[][2] =
{
  {6, 11}, {6, 15}, {6, 13}, {6, 14}, {6, 7}, {6, 5}, {5, 9},
  {5, 9}, {5, 6}, {5, 6}, {5, 3}, {5, 3}, {5, 10}, {5, 10},
  {5, 12}, {5, 12}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 1},
  {4, 1}, {4, 1}, {4, 1}, {4, 4}, {4, 4}, {4, 4}, {4, 4},
  {4, 8}, {4, 8}, {4, 8}, {4, 8}, {1, 0}, {1, 0}, {1, 0},
  {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0},
  {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0},
  {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0},
  {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0},
  {1, 0},
};


typedef struct
{
   HUFF_ELEMENT *table;
   int linbits;
   int ncase;
}
HUFF_SETUP;

#define no_bits       0
#define one_shot      1
#define no_linbits    2
#define have_linbits  3
#define quad_a        4
#define quad_b        5


static HUFF_SETUP table_look[] =
{
  {huff_table_0, 0, no_bits},
  {huff_table_1, 0, one_shot},
  {huff_table_2, 0, one_shot},
  {huff_table_3, 0, one_shot},
  {huff_table_0, 0, no_bits},
  {huff_table_5, 0, one_shot},
  {huff_table_6, 0, one_shot},
  {huff_table_7, 0, no_linbits},
  {huff_table_8, 0, no_linbits},
  {huff_table_9, 0, no_linbits},
  {huff_table_10, 0, no_linbits},
  {huff_table_11, 0, no_linbits},
  {huff_table_12, 0, no_linbits},
  {huff_table_13, 0, no_linbits},
  {huff_table_0, 0, no_bits},
  {huff_table_15, 0, no_linbits},
  {huff_table_16, 1, have_linbits},
  {huff_table_16, 2, have_linbits},
  {huff_table_16, 3, have_linbits},
  {huff_table_16, 4, have_linbits},
  {huff_table_16, 6, have_linbits},
  {huff_table_16, 8, have_linbits},
  {huff_table_16, 10, have_linbits},
  {huff_table_16, 13, have_linbits},
  {huff_table_24, 4, have_linbits},
  {huff_table_24, 5, have_linbits},
  {huff_table_24, 6, have_linbits},
  {huff_table_24, 7, have_linbits},
  {huff_table_24, 8, have_linbits},
  {huff_table_24, 9, have_linbits},
  {huff_table_24, 11, have_linbits},
  {huff_table_24, 13, have_linbits},
  {huff_table_0, 0, quad_a},
  {huff_table_0, 0, quad_b},
};

/*========================================================*/
/*------------- get n bits from bitstream -------------*/
/* unused
static unsigned int bitget(int n)
{
   unsigned int x;

   if (bitdat.bits < n)
   {			*/	/* refill bit buf if necessary */
/*      while (bitdat.bits <= 24)
      {
	 bitdat.bitbuf = (bitdat.bitbuf << 8) | *bitdat.bs_ptr++;
	 bitdat.bits += 8;
      }
   }
   bitdat.bits -= n;
   x = bitdat.bitbuf >> bitdat.bits;
   bitdat.bitbuf -= x << bitdat.bits;
   return x;
}
*/
/*----- get n bits  - checks for n+2 avail bits (linbits+sign) -----*/
static unsigned int bitget_lb(MPEG *m, int n)
{
   unsigned int x;

   if (m->cupl.bitdat.bits < (n + 2))
   {				/* refill bit buf if necessary */
      while (m->cupl.bitdat.bits <= 24)
      {
	 m->cupl.bitdat.bitbuf = (m->cupl.bitdat.bitbuf << 8) | 
		                 *m->cupl.bitdat.bs_ptr++;
	 m->cupl.bitdat.bits += 8;
      }
   }
   m->cupl.bitdat.bits -= n;
   x = m->cupl.bitdat.bitbuf >> m->cupl.bitdat.bits;
   m->cupl.bitdat.bitbuf -= x << m->cupl.bitdat.bits;
   return x;
}




/*------------- get n bits but DO NOT remove from bitstream --*/
static unsigned int bitget2(MPEG *m, int n)
{
   unsigned int x;

   if (m->cupl.bitdat.bits < (MAXBITS + 2))
   {				/* refill bit buf if necessary */
      while (m->cupl.bitdat.bits <= 24)
      {
	 m->cupl.bitdat.bitbuf = (m->cupl.bitdat.bitbuf << 8) | 
		                 *m->cupl.bitdat.bs_ptr++;
	 m->cupl.bitdat.bits += 8;
      }
   }
   x = m->cupl.bitdat.bitbuf >> (m->cupl.bitdat.bits - n);
   return x;
}
/*========================================================*/
/*========================================================*/
#define mac_bitget_check(n) if( m->cupl.bitdat.bits < (n) ) {  \
    while( m->cupl.bitdat.bits <= 24 ) {            \
        m->cupl.bitdat.bitbuf = (m->cupl.bitdat.bitbuf << 8) | \
		                *m->cupl.bitdat.bs_ptr++; \
        m->cupl.bitdat.bits += 8;                   \
    }                                       \
}
/*---------------------------------------------------------*/
#define mac_bitget2(n)  (m->cupl.bitdat.bitbuf >> (m->cupl.bitdat.bits-n));
/*---------------------------------------------------------*/
#define mac_bitget(n) ( m->cupl.bitdat.bits -= n,           \
         code  = m->cupl.bitdat.bitbuf >> m->cupl.bitdat.bits,     \
         m->cupl.bitdat.bitbuf -= code << m->cupl.bitdat.bits,     \
         code )
/*---------------------------------------------------------*/
#define mac_bitget_purge(n) m->cupl.bitdat.bits -= n,                    \
    m->cupl.bitdat.bitbuf -= (m->cupl.bitdat.bitbuf >> m->cupl.bitdat.bits) \
                              << m->cupl.bitdat.bits;
/*---------------------------------------------------------*/
#define mac_bitget_1bit() ( m->cupl.bitdat.bits--,               \
         code  = m->cupl.bitdat.bitbuf >> m->cupl.bitdat.bits,    \
         m->cupl.bitdat.bitbuf -= code << m->cupl.bitdat.bits,  \
         code )
/*========================================================*/
/*========================================================*/
void unpack_huff(MPEG *m, int xy[][2], int n, int ntable)
{
   int i;
   HUFF_ELEMENT *t;
   HUFF_ELEMENT *t0;
   int linbits;
   int bits;
   int code;
   int x, y;

   if (n <= 0)
      return;
   n = n >> 1;			/* huff in pairs */
/*-------------*/
   t0 = table_look[ntable].table;
   linbits = table_look[ntable].linbits;
   switch (table_look[ntable].ncase)
   {
      default:
/*------------------------------------------*/
      case no_bits:
/*- table 0, no data, x=y=0--*/
	 for (i = 0; i < n; i++)
	 {
	    xy[i][0] = 0;
	    xy[i][1] = 0;
	 }
	 return;
/*------------------------------------------*/
      case one_shot:
/*- single lookup, no escapes -*/
	 for (i = 0; i < n; i++)
	 {
	    mac_bitget_check((MAXBITS + 2));
	    bits = t0[0].b.signbits;
	    code = mac_bitget2(bits);
	    mac_bitget_purge(t0[1 + code].b.purgebits);
	    x = t0[1 + code].b.x;
	    y = t0[1 + code].b.y;
	    if (x)
	       if (mac_bitget_1bit())
		  x = -x;
	    if (y)
	       if (mac_bitget_1bit())
		  y = -y;
	    xy[i][0] = x;
	    xy[i][1] = y;
	    if (m->cupl.bitdat.bs_ptr > m->cupl.bitdat.bs_ptr_end)
	       break;		// bad data protect

	 }
	 return;
/*------------------------------------------*/
      case no_linbits:
	 for (i = 0; i < n; i++)
	 {
	    t = t0;
	    for (;;)
	    {
	       mac_bitget_check((MAXBITS + 2));
	       bits = t[0].b.signbits;
	       code = mac_bitget2(bits);
	       if (t[1 + code].b.purgebits)
		  break;
	       t += t[1 + code].ptr;	/* ptr include 1+code */
	       mac_bitget_purge(bits);
	    }
	    mac_bitget_purge(t[1 + code].b.purgebits);
	    x = t[1 + code].b.x;
	    y = t[1 + code].b.y;
	    if (x)
	       if (mac_bitget_1bit())
		  x = -x;
	    if (y)
	       if (mac_bitget_1bit())
		  y = -y;
	    xy[i][0] = x;
	    xy[i][1] = y;
	    if (m->cupl.bitdat.bs_ptr > m->cupl.bitdat.bs_ptr_end)
	       break;		// bad data protect

	 }
	 return;
/*------------------------------------------*/
      case have_linbits:
	 for (i = 0; i < n; i++)
	 {
	    t = t0;
	    for (;;)
	    {
	       bits = t[0].b.signbits;
	       code = bitget2(m, bits);
	       if (t[1 + code].b.purgebits)
		  break;
	       t += t[1 + code].ptr;	/* ptr includes 1+code */
	       mac_bitget_purge(bits);
	    }
	    mac_bitget_purge(t[1 + code].b.purgebits);
	    x = t[1 + code].b.x;
	    y = t[1 + code].b.y;
	    if (x == 15)
	       x += bitget_lb(m, linbits);
	    if (x)
	       if (mac_bitget_1bit())
		  x = -x;
	    if (y == 15)
	       y += bitget_lb(m, linbits);
	    if (y)
	       if (mac_bitget_1bit())
		  y = -y;
	    xy[i][0] = x;
	    xy[i][1] = y;
	    if (m->cupl.bitdat.bs_ptr > m->cupl.bitdat.bs_ptr_end)
	       break;		// bad data protect

	 }
	 return;
   }
/*--- end switch ---*/

}
/*==========================================================*/
int unpack_huff_quad(MPEG *m, int vwxy[][4], int n, int nbits, int ntable)
{
   int i;
   int code;
   int x, y, v, w;
   int tmp;
   int i_non_zero, tmp_nz;

   tmp_nz = 15;
   i_non_zero = -1;

   n = n >> 2;			/* huff in quads */

   if (ntable)
      goto case_quad_b;

/* case_quad_a: */
   for (i = 0; i < n; i++)
   {
      if (nbits <= 0)
	 break;
      mac_bitget_check(10);
      code = mac_bitget2(6);
      nbits -= quad_table_a[code][0];
      mac_bitget_purge(quad_table_a[code][0]);
      tmp = quad_table_a[code][1];
      if (tmp)
      {
	 i_non_zero = i;
	 tmp_nz = tmp;
      }
      v = (tmp >> 3) & 1;
      w = (tmp >> 2) & 1;
      x = (tmp >> 1) & 1;
      y = tmp & 1;
      if (v)
      {
	 if (mac_bitget_1bit())
	    v = -v;
	 nbits--;
      }
      if (w)
      {
	 if (mac_bitget_1bit())
	    w = -w;
	 nbits--;
      }
      if (x)
      {
	 if (mac_bitget_1bit())
	    x = -x;
	 nbits--;
      }
      if (y)
      {
	 if (mac_bitget_1bit())
	    y = -y;
	 nbits--;
      }
      vwxy[i][0] = v;
      vwxy[i][1] = w;
      vwxy[i][2] = x;
      vwxy[i][3] = y;
      if (m->cupl.bitdat.bs_ptr > m->cupl.bitdat.bs_ptr_end)
	 break;			// bad data protect

   }
   if (nbits < 0)
   {
      i--;
      vwxy[i][0] = 0;
      vwxy[i][1] = 0;
      vwxy[i][2] = 0;
      vwxy[i][3] = 0;
   }

   i_non_zero = (i_non_zero + 1) << 2;

   if ((tmp_nz & 3) == 0)
      i_non_zero -= 2;

   return i_non_zero;

/*--------------------*/
 case_quad_b:
   for (i = 0; i < n; i++)
   {
      if (nbits < 4)
	 break;
      nbits -= 4;
      mac_bitget_check(8);
      tmp = mac_bitget(4) ^ 15;	/* one's complement of bitstream */
      if (tmp)
      {
	 i_non_zero = i;
	 tmp_nz = tmp;
      }
      v = (tmp >> 3) & 1;
      w = (tmp >> 2) & 1;
      x = (tmp >> 1) & 1;
      y = tmp & 1;
      if (v)
      {
	 if (mac_bitget_1bit())
	    v = -v;
	 nbits--;
      }
      if (w)
      {
	 if (mac_bitget_1bit())
	    w = -w;
	 nbits--;
      }
      if (x)
      {
	 if (mac_bitget_1bit())
	    x = -x;
	 nbits--;
      }
      if (y)
      {
	 if (mac_bitget_1bit())
	    y = -y;
	 nbits--;
      }
      vwxy[i][0] = v;
      vwxy[i][1] = w;
      vwxy[i][2] = x;
      vwxy[i][3] = y;
      if (m->cupl.bitdat.bs_ptr > m->cupl.bitdat.bs_ptr_end)
	 break;			// bad data protect

   }
   if (nbits < 0)
   {
      i--;
      vwxy[i][0] = 0;
      vwxy[i][1] = 0;
      vwxy[i][2] = 0;
      vwxy[i][3] = 0;
   }

   i_non_zero = (i_non_zero + 1) << 2;

   if ((tmp_nz & 3) == 0)
      i_non_zero -= 2;

   return i_non_zero;		/* return non-zero sample (to nearest pair) */

}
/*-----------------------------------------------------*/
