
/*
 * xa_acodec.c
 *
 * Copyright (C) 1994,1995,1996 by Mark Podlipec.
 * All rights reserved.
 *
 * This software may be freely copied, modified and redistributed without
 * fee for non-commerical purposes provided that this copyright notice is
 * preserved intact on all copies and modified copies.
 *
 * There is no warranty or other guarantee of fitness of this software.
 * It is provided solely "as is". The author(s) disclaim(s) all
 * responsibility and liability with respect to this software's usage
 * or its effect upon hardware or computer systems.
 *
 */


/* This file contains Audio Codecs and the routines to add audio
 * into the XAnim structures.  The Hardware specific audio routines
 * for the various platforms is somewhere else.
 */

#include "xa_audio.h"

/* external */
XA_SND *XA_Audio_Next_Snd();
extern xaULONG xa_kludge2_dvi;

/* externals to make internal */
extern xaUBYTE xa_sign_2_ulaw[];
extern xaULONG xa_ulaw_2_sign[];
extern xaULONG xa_arm_2_signed[];
extern void Gen_Ulaw_2_Signed();
extern void Gen_Arm_2_Signed();

/* extern xaULONG  xa_kludge900_aud; */

/* Internal */
xaULONG XA_ADecode_1M_1M();
xaULONG XA_ADecode_PCMXM_PCM1M();
xaULONG XA_ADecode_PCM1M_PCM2M();
xaULONG XA_ADecode_PCM1S_PCMxM();
xaULONG XA_ADecode_PCM2X_PCM2M();
xaULONG XA_ADecode_NOP_PCMXM();
xaULONG XA_ADecode_ULAWx_PCM2M();
xaULONG XA_ADecode_ARMLAWx_PCM2M();
xaULONG XA_ADecode_ADPCMS_PCM2M();
xaULONG XA_ADecode_ADPCMM_PCM2M();
xaULONG XA_ADecode_DVIM_PCMxM();
xaULONG XA_ADecode_DVIS_PCMxM();
xaULONG XA_ADecode_IMA4M_PCMxM();
xaULONG XA_ADecode_IMA4S_PCMxM();
xaULONG XA_ADecode_GSMM_PCMxM();

xaULONG XA_IPC_Sound();
xaULONG XA_Add_Sound();
extern xaULONG xa_vaudio_hard_buff;
extern xaULONG xa_audio_hard_type;


/***************************************************************************
 * Below is an Empty Audio Decode Routine. It's mainly for my benefit
 * to cut and paste for new ones.
 */ 

#ifdef XA_NEVER_DEFINED_32
xaULONG XA_ADecode_XXX_XXX(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL;	/* Init Local Variables */
  /* Optionally Init Codec Specific Structure Here */ 
  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    {	
	/*** Decode Sample and increment byte_cnt ***/
      byte_cnt++;

      samp_cnt--;
      inc_cnt += inc;
    }
    while(inc_cnt >= (1<<24))
    { 
	/*** Output Sample ***/
      ocnt++;
      inc_cnt -= (1<<24);	
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;     /* save local variables */
  /* Optionally Save Codec Specific Structure Here */
  return(ocnt);
}
#endif


/*****************************************************************************/

#define XA_ADECODE_DECLARE_LOCAL xaUBYTE *ibuf; \
xaULONG byte_cnt, inc, inc_cnt, spec, samp_cnt; xaLONG dataL, dataR

#define XA_ADECODE_INIT_LOCAL 		\
{ spec		= snd_hdr->spec;	\
  inc		= snd_hdr->inc;		\
  inc_cnt	= snd_hdr->inc_cnt;	\
  byte_cnt	= snd_hdr->byte_cnt;	\
  samp_cnt	= snd_hdr->samp_cnt;	\
  dataL		= snd_hdr->dataL;	\
  dataR		= snd_hdr->dataR;	\
  ibuf		= snd_hdr->snd;		\
  ibuf += byte_cnt; 			}

#define XA_ADECODE_MOVE_ON 	{			\
if ( (snd_hdr = XA_Audio_Next_Snd(snd_hdr)) != 0)	\
{ snd_hdr->inc_cnt	= inc_cnt;			\
  snd_hdr->dataL	= dataL;			\
  snd_hdr->dataR	= dataL;			\
  ocnt = snd_hdr->delta(snd_hdr,obuf,ocnt,buff_size);	\
}							\
return(ocnt);						}		

#define XA_ADECODE_SAVE_LOCAL	\
{ snd_hdr->inc_cnt	= inc_cnt;	\
  snd_hdr->byte_cnt	= byte_cnt;	\
  snd_hdr->samp_cnt	= samp_cnt;	\
  snd_hdr->dataL	= dataL;	\
  snd_hdr->dataR	= dataL;	}

/********** XA_ADecode_1M_M *********************************
 * No conversion. simply pass along.
 *******************************************/
xaULONG XA_ADecode_1M_1M(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL;	/* Init Local Variables */
  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    { dataL = dataR = (xaULONG)*ibuf++;		byte_cnt++;
      samp_cnt--;
      inc_cnt += inc;
    }
    while(inc_cnt >= (1<<24))
    { *obuf++ = dataL;
      ocnt++;
      inc_cnt -= (1<<24);	
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;     /* save local variables */
  return(ocnt);
}

/********** XA_ADecode_PCMXM_PCM1M *********************************
 * Convert PCM 1+2 BPS Mono Samples into PCM 1 BPS Mono Samples
 * The order flag takes care of the various linear/signed/endian
 * conversions
 *  Input        order 1st  2nd
 *  -----------------------------------------
 *  Linear1M      0   D     -
 *  Signed1M      1   D^80  -
 *  Linear2MBig   2   D     skip
 *  Signed2MBig   3   D^80  skip
 *  Linear2MLit   4   skip  D
 *  Signed2MLit   5   skip  D^80
 *
 *  bit 3 (& 0x08) AU output instead of PCM.
 *
 * Global Variables:
 *   XA_Audio_Next_Snd()	routine to move to next sound header.
 ***************************************************************/
xaULONG XA_ADecode_PCMXM_PCM1M(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL;	xaULONG bps;
  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL; 
  bps		= ((spec & 2) | (spec & 4))?(2):(1);

  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    {	/*** Decode Sample ***/
      dataL = (spec & 4)?(ibuf[1]):(*ibuf);	
      ibuf += bps;	byte_cnt += bps;	samp_cnt--;
      inc_cnt += inc;
    }

    while(inc_cnt >= (1<<24))
    {
	/*** Output Sample ***/
      if (spec & 8)
      { /* note: ulaw takes signed input */
	if (spec & 1) *obuf++ = xa_sign_2_ulaw[ dataL ];
	else *obuf++ = xa_sign_2_ulaw[ (dataL ^ 0x80) ];
      }
      else *obuf++ = (spec & 1)?(dataL^0x80):(dataL);

      ocnt++;
      inc_cnt -= (1<<24);	
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  return(ocnt);
}

/********** XA_ADecode_PCM1M_PCM2M *********************************
 * Convert PCM 1 BPS Mono Samples into PCM 2 BPS Mono Samples
 * The order flag takes care of the various linear/signed/endian
 * conversions
 *  Input        Ouput       Order  1st  2nd
 *  -----------------------------------------
 *  Linear to Linear Big       0    D     D
 *  Linear to Linear Little    0    D     D
 *  Signed to Linear Big       1    D^80  D
 *  Signed to Linear Little    2    D     D^80
 *  Linear to Signed Big       1    D^80  D
 *  Linear to Signed Little    2    D     D^80
 *  Signed to Signed Big       2    D     D^80
 *  Signed to Signed Little    1    D^80  D
 *
 * Global Variables:
 *   xaUBYTE xa_sign_2_ulaw[256]	conversion table.
 *   XA_Audio_Next_Snd()	routine to move to next sound header.
 ***************************************************************/
xaULONG XA_ADecode_PCM1M_PCM2M(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL;
  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL;

  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    {   /*** Decode Sample ***/
      dataL = *ibuf++;
      byte_cnt++;        samp_cnt--;
      inc_cnt += inc;
    }
    while(inc_cnt >= (1<<24))
    {  /*** Output Sample ****/
      if (spec==1) { *obuf++ = dataL ^ 0x80; *obuf++ = dataL; }
      else if (spec==2) { *obuf++ = dataL; *obuf++ = dataL ^ 0x80; }
      else { *obuf++ = dataL; *obuf++ = dataL; }
      ocnt++;
      inc_cnt -= (1<<24);
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)	{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  return(ocnt);
}

/********** XA_Audio_PCM1S_PCMxM *********************************
 * Convert PCM 1 BPS Stereo Samples into PCM 2 BPS Mono Samples
 * The order flag takes care of the various linear/signed/endian
 * conversions
 *  Input        Ouput       Order  1st  2nd
 *  -----------------------------------------
 *  Linear to Linear Big       0    D     D
 *  Linear to Linear Little    0    D     D
 *  Signed to Linear Big       1 5  D^80  D
 *  Signed to Linear Little    2 6  D     D^80
 *  Linear to Signed Big       1    D^80  D
 *  Linear to Signed Little    2    D     D^80
 *  Signed to Signed Big       2 6  D     D^80
 *  Signed to Signed Little    1 5  D^80  D
 *
 *  bit 2(0x04) indicates incoming is signed(necessary for proper averaging)
 *  bit 3(0x08) indicates output is single byte
 *  bit 4(0x10) indicates output is ulaw(X to signed to ulaw)
 *
 * Global Variables:
 *   xaUBYTE xa_sign_2_ulaw[256]        conversion table.
 *   XA_Audio_Next_Snd()        routine to move to next sound header.
 ***************************************************************/
xaULONG XA_ADecode_PCM1S_PCMxM(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL;
  while(ocnt < buff_size)
  { if (inc_cnt < (1<<24))
    { /*** Decode Sample and increment byte_cnt ***/
      dataL = *ibuf++;
      dataR = *ibuf++;	
      if (spec & 0x04)	/* Signed Input */
      { if (dataL & 0x80) dataL -= 0x100;
        if (dataR & 0x80) dataR -= 0x100;
      }
      byte_cnt += 2;
      samp_cnt--;
      inc_cnt += inc;
    }
    while(inc_cnt >= (1<<24))
    { xaULONG data = ((dataL + dataR)>>1) & 0xff;
	/*** Output Sample ***/
      if (spec & 0x08) /* Single Byte out */
      { if (spec & 0x10)	
		*obuf++ = xa_sign_2_ulaw[((spec & 0x04)?(data):(data ^ 0x80))];
        else	*obuf++ = (spec & 0x01)?(data ^ 0x80):(data);
      }
      else
      {
	if (spec & 0x01)	{ *obuf++ = data ^ 0x80;   *obuf++ = data; }
	else if (spec & 0x02)	{ *obuf++ = data;   *obuf++ = data ^ 0x80; }
	else			{ *obuf++ = data;        *obuf++ = data; }
      }
/* POD Add uLaw and single byte output */

      ocnt++;
      inc_cnt -= (1<<24);	
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  return(ocnt);
}

/********** XA_ADecode_ULAWx_PCM2M *********************************
 * Convert Sun's ULAW Mono/Stereo Samples into PCM 2 BPS Mono Samples
 * The spec flag takes care of the various linear/signed/endian
 * conversions
 *  Input        Ouput      Spec  1st  2nd
 *  -----------------------------------------
 *  ULAW to Signed Big       0    D1    D0
 *  ULAW to Signed Little    1    D0    D1
 *  ULAW to Linear Big       2    D1^80 D0
 *  ULAW to Linear Little    3    D0    D1^80
 *
 *  bit 2 (& 0x04) 1 byte output.
 *  bit 3 (& 0x08) stereo input.
 *
 * Global Variables:
 *   xaUBYTE xa_sign_2_ulaw[256]        conversion table.
 *   XA_Audio_Next_Snd()        routine to move to next sound header.
 ***************************************************************/
xaULONG XA_ADecode_ULAWx_PCM2M(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL;

  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    { /*** Decode Sample and increment byte_cnt ***/
      dataL = xa_ulaw_2_sign[ (*ibuf++) ];
      if (spec & 0x08)
      { dataR = xa_ulaw_2_sign[ (*ibuf++) ];
	if (dataL & 0x8000) dataL -= 0x10000;
	if (dataR & 0x8000) dataR -= 0x10000;
        byte_cnt += 2;
      } else byte_cnt++;
      samp_cnt--;
      inc_cnt += inc;
    }
    while(inc_cnt >= (1<<24))
    { xaULONG data = (spec & 0x08)?((dataL + dataR)>>1):(dataL);
	/*** Output Sample ***/
      if (spec & 0x04)  /* 1 byte output */
      {  xaUBYTE d0 = ((xaULONG)(data) >> 8) & 0xff;
         if (spec & 0x02)    *obuf++ = d0;
         else             *obuf++ = d0 ^ 0x80;
/* POD Add uLaw output */
      }
      else
      { xaUBYTE d1,d0; d1 = (data>>8) & 0xff; d0 = data & 0xff;
        if (spec & 0x02) d1 ^= 0x80;
        if (spec & 0x01) {*obuf++ = d0; *obuf++ = d1; }
        else {*obuf++ = d1; *obuf++ = d0; }
      }

      ocnt++;
      inc_cnt -= (1<<24);	
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  return(ocnt);
}

/********** XA_ADecode_ARMLAWx_PCM2M *********************************
 * Convert ARM Logarithmic Mono/Stereo Samples into PCM 2 BPS Mono Samples
 * The spec flag takes care of the various linear/signed/endian
 * conversions
 *  Input        Ouput      Spec  1st  2nd
 *  -----------------------------------------
 *  ULAW to Signed Big       0    D1    D0
 *  ULAW to Signed Little    1    D0    D1
 *  ULAW to Linear Big       2    D1^80 D0
 *  ULAW to Linear Little    3    D0    D1^80
 *
 *  bit 2 (& 0x04) 1 byte output.
 *  bit 3 (& 0x08) stereo input.
 *
 * Global Variables:
 *   xaUBYTE xa_sign_2_ulaw[256]        conversion table.
 *   XA_Audio_Next_Snd()        routine to move to next sound header.
 ***************************************************************/
xaULONG XA_ADecode_ARMLAWx_PCM2M(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL;

  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    { /*** Decode Sample and increment byte_cnt ***/
      dataL = xa_arm_2_signed[ (*ibuf++) ];
      if (spec & 0x08)
      { dataR = xa_arm_2_signed[ (*ibuf++) ];
	if (dataL & 0x8000) dataL -= 0x10000;
	if (dataR & 0x8000) dataR -= 0x10000;
        byte_cnt += 2;
      } else byte_cnt++;
      samp_cnt--;
      inc_cnt += inc;
    }
    while(inc_cnt >= (1<<24))
    { xaULONG data = (spec & 0x08)?((dataL + dataR)>>1):(dataL);
	/*** Output Sample ***/
      if (spec & 0x04)  /* 1 byte output */
      {  xaUBYTE d0 = ((xaULONG)(data) >> 8) & 0xff;
         if (spec & 0x02)    *obuf++ = d0;
         else             *obuf++ = d0 ^ 0x80;
/* POD Add uLaw output */
      }
      else
      { xaUBYTE d1,d0; d1 = (data>>8) & 0xff; d0 = data & 0xff;
        if (spec & 0x02) d1 ^= 0x80;
        if (spec & 0x01) {*obuf++ = d0; *obuf++ = d1; }
        else {*obuf++ = d1; *obuf++ = d0; }
      }

      ocnt++;
      inc_cnt -= (1<<24);	
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  return(ocnt);
}

/********** XA_ADecode_PCM2X_PCM2M *********************************
 * Convert PCM 2 BPS (mono/stereo little/big endian) Samples
 * into PCM 2 BPS Mono (little/big endian) Samples.
 * The flag "spec' takes care of the various linear/signed/endian/stereo
 * conversions.
 *
 * bit   mask  meaning
 * -----------------------------------------
 * bit 0:  1  src endian  0 = big  1 = little
 * bit 1:  2  linear/signed conversion.  0 = none  1 = ^0x8000
 * bit 2:  4  dst endian  0 = big  1 = little
 * bit 3:  8  src stereo  0 = no   1 = yes
 * bit 4: 10  src signed  0 = no   1 = yes
 *
 * Global Variables:
 *   XA_Audio_Next_Snd()        routine to move to next sound header.
 ***************************************************************/
xaULONG XA_ADecode_PCM2X_PCM2M(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL;

  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    {	/*** Decode Sample and increment byte_cnt ***/
      if (spec & 1)   /* Little Endian Samples */
      { dataL = *ibuf++;  dataL |= *ibuf++ << 8;
	if (spec & 8)	/* stereo input */
        { dataR = *ibuf++;  dataR |= *ibuf++ << 8; byte_cnt += 4;
	  if (spec & 0x10)  /* signed stereo input */
	  { if (dataL & 0x8000) dataL -= 0x10000;
	    if (dataR & 0x8000) dataR -= 0x10000;
	  }
	} else byte_cnt += 2;
      }
      else /* Big Endian Samples */
      { dataL = *ibuf++ << 8;  dataL |= *ibuf++;
	if (spec & 8) /* stereo input */
        { dataR = *ibuf++ << 8;  dataR |= *ibuf++; byte_cnt += 4;
	  if (spec & 0x10)  /* signed stereo input */
	  { if (dataL & 0x8000) dataL -= 0x10000;
	    if (dataR & 0x8000) dataR -= 0x10000;
	  }
	} else byte_cnt += 2;
      }
      samp_cnt--;
      inc_cnt += inc;
    }
    while(inc_cnt >= (1<<24))
    { register xaULONG d1,d0 = (spec & 8)?((dataL+dataR)>>1):(dataL);

	/*** Output Sample ***/
      if (spec & 2)	d0 ^= 0x8000; /* sign conversion */

      if (spec & 4)	d1 = d0 >> 8;
      else		{ d1 = d0; d0 >>= 8; }
      *obuf++ = (d0 & 0xff);
      *obuf++ = (d1 & 0xff);
	/* POD add single byte and ulaw output */
      ocnt++;
      inc_cnt -= (1<<24);	
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  return(ocnt);
}

/********** XA_ADecode_PCMXS_PCM1M *********************************
 * Convert PCM 1+2 BPS Stereo Samples into PCM 1 BPS Mono Samples
 * The spec flag takes care of the various linear/signed/endian
 * conversions
 *  Input        flag 1st  2nd    3rd  4th
 *  -----------------------------------------
 *  Linear1S      0   D     D     -    -
 *  Signed1S      1   D     D     -    -      ^80
 *  Linear2SBig   2   D     skip  D    skip
 *  Signed2SBig   3   D     skip  D    skip   ^80
 *  Linear2SLit   4   skip  D     skip D
 *  Signed2SLit   5   skip  D     skip D      ^80
 *
 *  bit 3 (& 0x08) AU output instead of PCM.
 *
 * Global Variables:
 *   XA_Audio_Next_Snd()        routine to move to next sound header.
 ***************************************************************/
xaULONG XA_ADecode_PCMXS_PCM1M(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL;
  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    {	/*** Decode Sample and increment byte_cnt ***/

      if (spec & 2)      /* only read most sig byte */
	{ dataL = *ibuf++; ibuf++; dataR = *ibuf++; ibuf++; byte_cnt += 4; }
      else if (spec & 4) 
	{ ibuf++; dataL = *ibuf++; ibuf++; dataR = *ibuf++; byte_cnt += 4; }
      else		 { dataL = *ibuf++; dataR = *ibuf++; byte_cnt += 2; }
      if (spec & 1) /* signed input */
      { if (dataL & 0x80) dataL -= 0x100;
        if (dataR & 0x80) dataR -= 0x100;
      }
      samp_cnt--;
      inc_cnt += inc;
    }
    while(inc_cnt >= (1<<24))
    { xaULONG data = ((dataL + dataR)>>1) & 0xff;
      if (spec & 8)
      { /* note: ulaw takes signed input */
	if (spec & 1)	*obuf++ = xa_sign_2_ulaw[ data ];
	else		*obuf++ = xa_sign_2_ulaw[ (data ^ 0x80) ];
      }
      else *obuf++ = (spec & 1)?(data^0x80):(data);
      ocnt++;
      inc_cnt -= (1<<24);	
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  return(ocnt);
}

/* NEW CODECS HERE */


/********** XA_ADecode_NOP_PCMXM *********************************
 * Convert Silence(16bit Signed PCM silence 0x8000) Samples into various
 * other PCM/uLAW samples.
 * The spec flag takes care of the various linear/signed/endian
 * conversions
 *
 *  Input        Ouput        Spec  1st  2nd
 *  -----------------------------------------
 *  MSADPCM to Signed Big       0    D1    D0
 *  MSADPCM to Signed Little    1    D0    D1
 *  MSADPCM to Linear Big       2    D1^80 D0
 *  MSADPCM to Linear Little    3    D0    D1^80
 *
 *  bit 2 (& 0x04) 1 byte output.
 *  bit 3 (& 0x08) AU output instead of linear PCM.
 *
 * Global Variables:
 *   XA_Audio_Next_Snd()        routine to move to next sound header.
 ***************************************************************/
xaULONG XA_ADecode_NOP_PCMXM(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL; 

  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    {	/*** Decode Sample ***/
      byte_cnt++;	samp_cnt--;
      inc_cnt += inc;
    }

    while(inc_cnt >= (1<<24))
    { xaULONG data = 0x8000;
	/*** Output Sample ***/
      if (spec & 4)  /* 1 byte output */
      { xaUBYTE d0 = ((xaULONG)(data) >> 8) & 0xff;
        if (spec & 8)    *obuf++ = xa_sign_2_ulaw[ (xaULONG)(d0) ];
	else             *obuf++ = (spec & 2)?(d0 ^ 0x80):(d0);
      }
      else
      { xaUBYTE d1,d0; d1 = (data>>8) & 0xff; d0 = data & 0xff;
        if (spec & 0x02) d1 ^= 0x80;
        if (spec & 0x01) {*obuf++ = d0; *obuf++ = d1; }
        else {*obuf++ = d1; *obuf++ = d0; }
      }
      ocnt++;
      inc_cnt -= (1<<24);	
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  return(ocnt);
}


typedef struct 
{
  xaULONG	L_bpred ,R_bpred;
  xaLONG	L_delta ,R_delta;
  xaLONG	L_samp1 ,R_samp1;
  xaLONG	L_samp2 ,R_samp2;
  xaLONG	L_nyb1  ,R_nyb1;
  xaULONG	nyb_flag;
  xaULONG	flag;    
   /* 0 don't output samps, 1 output samp1, 2 output both  4 un-init'd */
} XA_MSADPCM_HDR;

XA_MSADPCM_HDR xa_msadpcm; 

#define MSADPCM_NUM_COEF        (7)
#define MSADPCM_MAX_CHANNELS    (2)

#define MSADPCM_PSCALE          (8)
#define MSADPCM_PSCALE_NUM      (1 << MSADPCM_PSCALE)
#define MSADPCM_CSCALE          (8)
#define MSADPCM_CSCALE_NUM      (1 << MSADPCM_CSCALE)

#define MSADPCM_DELTA4_MIN      (16)

static xaLONG  gaiP4[] = { 230, 230, 230, 230, 307, 409, 512, 614,
                          768, 614, 512, 409, 307, 230, 230, 230 };
static xaLONG gaiCoef1[] = { 256,  512,  0, 192, 240,  460,  392 };
static xaLONG gaiCoef2[] = {   0, -256,  0,  64,   0, -208, -232 };

#define AUD_READ_MSADPCM_HDR(ptr,bpred,delta,samp1,samp2)	\
{ bpred= *ptr++; 					\
  delta = *ptr++;	delta |= (*ptr++)<<8;		\
  samp1 = *ptr++;	samp1 |= (*ptr++)<<8;		\
  samp2 = *ptr++;	samp2 |= (*ptr++)<<8;		\
  if (delta & 0x8000)	delta -= 0x10000;	\
  if (samp1 & 0x8000)	samp1 -= 0x10000;	\
  if (samp2 & 0x8000)	samp2 -= 0x10000;	}


#define AUD_READ_MSADPCM_SHDR(ptr,Lbpred,Ldelta,Lsamp1,Lsamp2,Rbpred,Rdelta,Rsamp1,Rsamp2) \
{ Lbpred= *ptr++;	Rbpred= *ptr++;			\
  Ldelta = *ptr++;	Ldelta |= (*ptr++)<<8;		\
  Rdelta = *ptr++;	Rdelta |= (*ptr++)<<8;		\
  Lsamp1 = *ptr++;	Lsamp1 |= (*ptr++)<<8;		\
  Rsamp1 = *ptr++;	Rsamp1 |= (*ptr++)<<8;		\
  Lsamp2 = *ptr++;	Lsamp2 |= (*ptr++)<<8;		\
  Rsamp2 = *ptr++;	Rsamp2 |= (*ptr++)<<8;		\
  if (Ldelta & 0x8000)	Ldelta = Ldelta - 0x10000;	\
  if (Lsamp1 & 0x8000)	Lsamp1 = Lsamp1 - 0x10000;	\
  if (Lsamp2 & 0x8000)	Lsamp2 = Lsamp2 - 0x10000;	\
  if (Rdelta & 0x8000)	Rdelta = Rdelta - 0x10000;	\
  if (Rsamp1 & 0x8000)	Rsamp1 = Rsamp1 - 0x10000;	\
  if (Rsamp2 & 0x8000)	Rsamp2 = Rsamp2 - 0x10000;	}

  
#define AUD_CALC_MSADPCM(lsamp,nyb0,delta,samp1,samp2,coef1,coef2) \
{ xaLONG predict;						\
   /** Compute next Adaptive Scale Factor(ASF) */		\
  idelta = delta;						\
  delta = (gaiP4[nyb0] * idelta) >> MSADPCM_PSCALE;		\
  if (delta < MSADPCM_DELTA4_MIN) delta = MSADPCM_DELTA4_MIN;	\
  if (nyb0 & 0x08) nyb0 = nyb0 - 0x10;				\
   /** Predict next sample */					\
  predict = ((samp1 * coef1) + (samp2 * coef2)) >>  MSADPCM_CSCALE;	\
   /** reconstruct original PCM */				\
  lsamp = (nyb0 * idelta) + predict;				\
  if (lsamp > 32767) lsamp = 32767;				\
  else if (lsamp < -32768) lsamp = -32768;			}

/********** XA_ADecode_ADPCMM_PCM2M *********************************
 * Convert Microsoft ADPCM Mono Samples into PCM 2 BPS Mono Samples
 * The spec flag takes care of the various linear/signed/endian
 * conversions
 *  Input        Ouput        Spec  1st  2nd
 *  -----------------------------------------
 *  MSADPCM to Signed Big       0    D1    D0
 *  MSADPCM to Signed Little    1    D0    D1  
 *  MSADPCM to Linear Big       2    D1^80 D0
 *  MSADPCM to Linear Little    3    D0    D1^80
 *
 *  bit 2 (& 0x04) 1 byte output.
 *  bit 3 (& 0x08) AU output instead of linear PCM.
 *
 * Global Variables:
 *   xaUBYTE xa_sign_2_ulaw[256]	conversion table.
 *   XA_Audio_Next_Snd()	routine to move to next sound header.
 ***************************************************************/
xaULONG XA_ADecode_ADPCMM_PCM2M(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  xaULONG bpred, blk_cnt;
  xaLONG delta,coef1,coef2,samp1,samp2;

  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL;
  blk_cnt	= snd_hdr->blk_cnt;

  /* Init Codec specific Variables */
  bpred = xa_msadpcm.L_bpred;
  delta = xa_msadpcm.L_delta;
  samp1 = xa_msadpcm.L_samp1;
  samp2 = xa_msadpcm.L_samp2;
  coef1 = gaiCoef1[bpred];
  coef2 = gaiCoef2[bpred];
  
  while(ocnt < buff_size)
  { 
    if (inc_cnt < (1<<24))
    { inc_cnt += inc;  
         /*** Decode Sample ***/
      if (snd_hdr->flag == 0)
      {
        AUD_READ_MSADPCM_HDR(ibuf,bpred,delta,samp1,samp2);
	if (bpred >= 7)   /* 7 should be variable from AVI/WAV header */
	{ 
	  fprintf(stderr,"MSADPC bpred %x blk_cnt %d\n",bpred,blk_cnt);
	  return(ocnt);
	}
	coef1 = gaiCoef1[bpred];
	coef2 = gaiCoef2[bpred];
	byte_cnt += 7;
        blk_cnt = snd_hdr->blk_size - 7;
	snd_hdr->flag = 1;
	dataL = samp2;
      }
      else if (snd_hdr->flag == 1)
      {
	snd_hdr->flag = (blk_cnt)?(2):(0);
	dataL = samp1;
      }
      else /* if (snd_hdr->flag == 2) */
      { xaLONG nyb1,nyb0,idelta,lsamp;
	nyb1 = *ibuf++;		byte_cnt++;	blk_cnt--;
	nyb0 = (nyb1 >> 4) & 0x0f;
	nyb1 &= 0x0f;
	AUD_CALC_MSADPCM(lsamp,nyb0,delta,samp1,samp2,coef1,coef2);
	samp2 = samp1; samp1 = lsamp;
	AUD_CALC_MSADPCM(lsamp,nyb1,delta,samp1,samp2,coef1,coef2);
	samp2 = samp1; samp1 = lsamp;
	snd_hdr->flag = 1;
	dataL = samp2;
      }
      samp_cnt--;
    }

    while(inc_cnt >= (1<<24))
    { xaULONG data = samp2;
      inc_cnt -= (1<<24);
        /*** Output Sample ***/
      if (spec & 4)  /* 1 byte output */
      { xaUBYTE d0 = ((xaULONG)(data) >> 8) & 0xff;
	if (spec & 8)    *obuf++ = xa_sign_2_ulaw[ (xaULONG)(d0) ];
	else             *obuf++ = (spec & 2)?(d0 ^ 0x80):(d0);
      }
      else
      { xaUBYTE d1,d0; d1 = (data>>8) & 0xff; d0 = data & 0xff;
	if (spec & 0x02) d1 ^= 0x80;
	if (spec & 0x01) {*obuf++ = d0; *obuf++ = d1; }
	else {*obuf++ = d1; *obuf++ = d0; }
      }
      ocnt++;
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)          { XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  snd_hdr->blk_cnt	= blk_cnt;

  /* Save Codec Specific */
  xa_msadpcm.L_bpred	= bpred;
  xa_msadpcm.L_delta	= delta;
  xa_msadpcm.L_samp1	= samp1;
  xa_msadpcm.L_samp2	= samp2;
  return(ocnt);
}


/********** XA_ADecode_ADPCMS_PCM2M *********************************
 * Convert Microsoft ADPCM Stereo Samples into PCM 2 BPS Mono Samples
 * The spec flag takes care of the various linear/signed/endian
 * conversions
 *  Input        Ouput        Spec  1st  2nd
 *  -----------------------------------------
 *  MSADPCM to Signed Big       0    D1    D0
 *  MSADPCM to Signed Little    1    D0    D1
 *  MSADPCM to Linear Big       2    D1^80 D0
 *  MSADPCM to Linear Little    3    D0    D1^80
 *
 *  bit 2 (& 0x04) 1 byte output.
 *  bit 3 (& 0x08) AU output instead of linear PCM.
 *
 * Global Variables:
 *   xaUBYTE xa_sign_2_ulaw[256]        conversion table.
 *   XA_Audio_Next_Snd()        routine to move to next sound header.
 ***************************************************************/

xaULONG XA_ADecode_ADPCMS_PCM2M(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL;
  xaULONG blk_cnt; 
  xaLONG L_bpred,L_delta,L_coef1,L_coef2,L_samp1,L_samp2;
  xaLONG R_bpred,R_delta,R_coef1,R_coef2,R_samp1,R_samp2;

  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL;
  blk_cnt       = snd_hdr->blk_cnt;
  /* Init Codec specific Variables */
  L_bpred = xa_msadpcm.L_bpred; R_bpred = xa_msadpcm.R_bpred;
  L_delta = xa_msadpcm.L_delta; R_delta = xa_msadpcm.R_delta;
  L_samp1 = xa_msadpcm.L_samp1; R_samp1 = xa_msadpcm.R_samp1;
  L_samp2 = xa_msadpcm.L_samp2; R_samp2 = xa_msadpcm.R_samp2;
  L_coef1 = gaiCoef1[L_bpred];  R_coef1 = gaiCoef1[R_bpred];
  L_coef2 = gaiCoef2[L_bpred];  R_coef2 = gaiCoef2[R_bpred];

  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    { inc_cnt += inc;
         /*** Decode Sample ***/
      if (snd_hdr->flag == 0)
      {
	AUD_READ_MSADPCM_SHDR(ibuf,L_bpred,L_delta,L_samp1,L_samp2,
				   R_bpred,R_delta,R_samp1,R_samp2);
		/* 7 should be variable from AVI/WAV header */
	if ((L_bpred >= 7) || (R_bpred >= 7))
	{ fprintf(stderr,"MSADPC bpred %x %x\n",L_bpred,R_bpred);
	  return(ocnt);  /* POD do better abort here */
	}
	L_coef1 = gaiCoef1[L_bpred];  R_coef1 = gaiCoef1[R_bpred];
	L_coef2 = gaiCoef2[L_bpred];  R_coef2 = gaiCoef2[R_bpred];
	byte_cnt += 14;
	blk_cnt = snd_hdr->blk_size - 14;
	snd_hdr->flag = 1;
	dataL = L_samp2;	dataR = R_samp2;
      }
      else if (snd_hdr->flag == 1)
      { snd_hdr->flag = 2;
	dataL = L_samp1;	dataR = R_samp1;
      }
      else /* if (snd_hdr->flag == 2) */
      { xaLONG R_nyb,L_nyb,idelta,lsamp;
	R_nyb = *ibuf++;
	L_nyb = (R_nyb >> 4) & 0x0f;
	R_nyb &= 0x0f;
	byte_cnt++;		blk_cnt--;
	AUD_CALC_MSADPCM(lsamp,L_nyb,L_delta,L_samp1,L_samp2,L_coef1,L_coef2);
	L_samp2 = L_samp1; L_samp1 = lsamp;
	AUD_CALC_MSADPCM(lsamp,R_nyb,R_delta,R_samp1,R_samp2,R_coef1,R_coef2);
	R_samp2 = R_samp1; R_samp1 = lsamp;
	dataL = L_samp1;	dataR = R_samp1;
	snd_hdr->flag = (blk_cnt > 0)?(2):(0);
      }
      samp_cnt--;
    }

    while(inc_cnt >= (1<<24))
    { xaULONG data = (L_samp2 + R_samp2) / 2;
      inc_cnt -= (1<<24);
        /*** Output Sample ***/
      if (spec & 4)  /* 1 byte output */
      {  xaUBYTE d0 = ((xaULONG)(data) >> 8) & 0xff;
	if (spec & 8)    *obuf++ = xa_sign_2_ulaw[ (xaULONG)(d0) ];
	else             *obuf++ = (spec & 2)?(d0 ^ 0x80):(d0);
      }
      else
      { xaUBYTE d1,d0; d1 = (data>>8) & 0xff; d0 = data & 0xff;
	if (spec & 0x02) d1 ^= 0x80;
	if (spec & 0x01) {*obuf++ = d0; *obuf++ = d1; }
	else {*obuf++ = d1; *obuf++ = d0; }
      }
      ocnt++;
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)          { XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  snd_hdr->blk_cnt      = blk_cnt;

  /* Save Codec Specific */
  xa_msadpcm.L_bpred = L_bpred; xa_msadpcm.R_bpred = R_bpred;
  xa_msadpcm.L_delta = L_delta; xa_msadpcm.R_delta = R_delta;
  xa_msadpcm.L_samp1 = L_samp1; xa_msadpcm.R_samp1 = R_samp1;
  xa_msadpcm.L_samp2 = L_samp2; xa_msadpcm.R_samp2 = R_samp2;
  return(ocnt);
}


typedef struct XA_AUDIO_DVI_STRUCT
{
    xaLONG	L_valprev, R_valprev;	/* Previous output value */
    xaBYTE	L_index,   R_index;	/* Index into stepsize table */
    xaLONG	L_store;
    xaLONG	R_store;
} XA_AUDIO_DVI_STATE;

XA_AUDIO_DVI_STATE xa_dvi_state;

/* Intel ADPCM step variation table */
static int xa_audio_DVI_index_table[16] = {
    -1, -1, -1, -1, 2, 4, 6, 8,
    -1, -1, -1, -1, 2, 4, 6, 8
};

static int xa_audio_DVI_stepsize_table[89] = {
    7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
    19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
    50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
    130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
    337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
    876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
    2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
    5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
    15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};

#define AUD_CALC_DVI(valpred,delta,index,step)		\
{ xaLONG vpdiff, sign;					\
  /* Find new index value (for later) */		\
  index += xa_audio_DVI_index_table[delta];		\
  if ( index < 0 ) index = 0;				\
  else if ( index > 88 ) index = 88;			\
  /* Separate sign and magnitude */			\
  sign = delta & 8;					\
  delta = delta & 7;					\
  /* Compute difference and new predicted value */	\
  vpdiff = step >> 3;					\
  if (delta & 4)  vpdiff += step;			\
  if (delta & 2)  vpdiff += step>>1;			\
  if (delta & 1)  vpdiff += step>>2;			\
  if ( sign )     valpred -= vpdiff;			\
  else            valpred += vpdiff;			\
  if ( valpred > 32767 )          valpred = 32767;	\
  else if ( valpred < -32768 )    valpred = -32768;	\
  /* update step value */				\
  step = xa_audio_DVI_stepsize_table[index];		}

/********** XA_ADecode_DVIM_PCMxM *********************************
 * Convert DVI ADPCM Mono Samples into PCM 2 BPS Mono Samples
 * The spec flag takes care of the various linear/signed/endian
 * conversions
 *  Input        Ouput        Spec  1st  2nd
 *  -----------------------------------------
 *  MSADPCM to Signed Big       0    D1    D0
 *  MSADPCM to Signed Little    1    D0    D1
 *  MSADPCM to Linear Big       2    D1^80 D0
 *  MSADPCM to Linear Little    3    D0    D1^80
 *
 *  bit 2 (& 0x04) 1 byte output.
 *  bit 3 (& 0x08) AU output instead of linear PCM.
 *
 * Global Variables:
 *   xaUBYTE xa_sign_2_ulaw[256]        conversion table.
 *   XA_Audio_Next_Snd()        routine to move to next sound header.
 ***************************************************************/

xaULONG XA_ADecode_DVIM_PCMxM(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  xaLONG blk_cnt,valpred, index, step;

  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL; 
  blk_cnt	= snd_hdr->blk_cnt;

  /* Init Codec specific Variables */
  valpred	= xa_dvi_state.L_valprev;
  index		= xa_dvi_state.L_index;
  step		= xa_audio_DVI_stepsize_table[index];

  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    { inc_cnt += inc;
	/*** Decode Sample ***/
      if (snd_hdr->flag == 0)
      {  /* Read Header - POD macro */
	valpred = *ibuf++;	valpred |= (*ibuf++)<<8;
	if (valpred & 0x8000)	valpred = valpred - 0x10000;
	index = *ibuf++;
	ibuf++;   /* pad */

	if (index > 88)
	{ fprintf(stderr,"DVI: index err %d\n",index);
	  index = 88;
	}
	step = xa_audio_DVI_stepsize_table[index];
	blk_cnt = snd_hdr->blk_size - 4;
	byte_cnt += 4;
	snd_hdr->flag = 1;
	dataL = valpred;
      }
      else if (snd_hdr->flag == 1)
      { xaLONG nyb0,nyb1;
	if (xa_kludge2_dvi)	/* old style MS DVI implementation */
	{ nyb1 = *ibuf++;		/* MSB held 1st sample */
	  nyb0 = (nyb1 >> 4) & 0x0f;
	  nyb1 &= 0x0f;
	}
	else			/* new style MS DVI implementation */
	{ nyb0 = *ibuf++;		/* LSB held 1st sample */
	  nyb1 = (nyb0 >> 4) & 0x0f;
	  nyb0 &= 0x0f;
	}
	byte_cnt++;	blk_cnt--;


	AUD_CALC_DVI(valpred,nyb0,index,step);
	dataL = valpred;
	AUD_CALC_DVI(valpred,nyb1,index,step);
	snd_hdr->flag = 2;
      }
      else /* if (snd_hdr->flag == 2) */
      { dataL = valpred;
	snd_hdr->flag = (blk_cnt>0)?(1):(0);
      }
      samp_cnt--;
    }

    while(inc_cnt >= (1<<24))
    { inc_cnt -= (1<<24);	
        /*** Output Sample ***/
      if (spec & 4)  /* 1 byte output */
      { xaUBYTE d0 = ((xaULONG)(dataL) >> 8) & 0xff;
	if (spec & 8)    *obuf++ = xa_sign_2_ulaw[ (xaULONG)(d0) ];
	else             *obuf++ = (spec & 2)?(d0 ^ 0x80):(d0);
      }
      else
      { xaUBYTE d1,d0; d1 = (dataL>>8) & 0xff; d0 = dataL & 0xff;
	if (spec & 0x02) d1 ^= 0x80;
	if (spec & 0x01) {*obuf++ = d0; *obuf++ = d1; }
	else {*obuf++ = d1; *obuf++ = d0; }
      }
      ocnt++;
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  snd_hdr->blk_cnt	= blk_cnt;
  /* Save Codec Specific */
  xa_dvi_state.L_valprev	= valpred;
  xa_dvi_state.L_index		= index;
  return(ocnt);
}


/********** XA_ADecode_DVIS_PCMxM *********************************
 * Convert DVI ADPCM Stereo Samples into PCM 2 BPS Mono Samples
 * The spec flag takes care of the various linear/signed/endian
 * conversions
 *  Input        Ouput        Spec  1st  2nd
 *  -----------------------------------------
 *  MSADPCM to Signed Big       0    D1    D0
 *  MSADPCM to Signed Little    1    D0    D1
 *  MSADPCM to Linear Big       2    D1^80 D0
 *  MSADPCM to Linear Little    3    D0    D1^80
 *
 *  bit 2 (& 0x04) 1 byte output.
 *  bit 3 (& 0x08) AU output instead of linear PCM.
 *
 * Global Variables:
 *   xaUBYTE xa_sign_2_ulaw[256]        conversion table.
 *   XA_Audio_Next_Snd()        routine to move to next sound header.
 ***************************************************************/

xaULONG XA_ADecode_DVIS_PCMxM(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  xaLONG blk_cnt;
  xaLONG L_valpred, L_index, L_step, R_valpred, R_index, R_step;
  xaULONG L_store, R_store;

  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL; 
  blk_cnt	= snd_hdr->blk_cnt;

  /* Init Codec specific Variables */
  L_valpred	= xa_dvi_state.L_valprev;
  L_index	= xa_dvi_state.L_index;
  L_step	= xa_audio_DVI_stepsize_table[L_index];
  L_store	= xa_dvi_state.L_store;
  R_valpred	= xa_dvi_state.R_valprev;
  R_index	= xa_dvi_state.R_index;
  R_step	= xa_audio_DVI_stepsize_table[R_index];
  R_store	= xa_dvi_state.R_store;

  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    { inc_cnt += inc;
	/*** Decode Sample ***/
      if (snd_hdr->flag == 0)
      {  /* Read Header - POD macro */
	L_valpred = *ibuf++;	L_valpred |= (*ibuf++)<<8;
	if (L_valpred & 0x8000)	L_valpred = L_valpred - 0x10000;
	L_index = *ibuf++;	if (L_index > 88)	L_index = 88;
	L_step = xa_audio_DVI_stepsize_table[L_index];
	ibuf++;   /* pad */
	R_valpred = *ibuf++;	R_valpred |= (*ibuf++)<<8;
	if (R_valpred & 0x8000)	R_valpred = R_valpred - 0x10000;
	R_index = *ibuf++;	if (R_index > 88)	R_index = 88;
	R_step = xa_audio_DVI_stepsize_table[R_index];
	ibuf++;   /* pad */

	blk_cnt = snd_hdr->blk_size - 8;	byte_cnt += 8;
	snd_hdr->flag = 1;
	dataL = L_valpred;
	dataR = R_valpred;
      }
      else  /* flag == 1,2,3,4..8 */
      { xaLONG nyb; 
	if (snd_hdr->flag == 1)
	{ if (xa_kludge2_dvi)	/* old style MS DVI implementation */
	  { L_store = *ibuf++;			R_store = L_store >> 4;
	    byte_cnt += 1;			blk_cnt -= 1;
	  }
	  else			/* new style MS DVI implementation */ 
	  { L_store  = *ibuf++;
	    L_store |= *ibuf++ <<  8;
	    L_store |= *ibuf++ << 16;		
	    L_store |= *ibuf++ << 24;
	    R_store  = *ibuf++;
	    R_store |= *ibuf++ <<  8;
	    R_store |= *ibuf++ << 16;		
	    R_store |= *ibuf++ << 24;
	    byte_cnt += 8;			blk_cnt -= 8;
	  }
	}
	else { L_store >>= 4;  R_store >>= 4; }

	nyb = L_store & 0x0f;
	AUD_CALC_DVI(L_valpred,nyb,L_index,L_step);
	dataL = L_valpred;

	nyb = R_store & 0x0f;
	AUD_CALC_DVI(R_valpred,nyb,R_index,R_step);
	dataR = R_valpred;


	if ((xa_kludge2_dvi) || (snd_hdr->flag >= 8))
				snd_hdr->flag = (blk_cnt > 0)?(1):(0);
	else			snd_hdr->flag++;
      }
      samp_cnt--;
    }

    while(inc_cnt >= (1<<24))
    { xaLONG data = (dataL + dataR) / 2;

      inc_cnt -= (1<<24);	
        /*** Output Sample ***/
      if (spec & 4)  /* 1 byte output */
      { xaUBYTE d0 = ((xaULONG)(data) >> 8) & 0xff;
	if (spec & 8)    *obuf++ = xa_sign_2_ulaw[ (xaULONG)(d0) ];
	else             *obuf++ = (spec & 2)?(d0 ^ 0x80):(d0);
      }
      else
      { xaUBYTE d1,d0; d1 = (data>>8) & 0xff; d0 = data & 0xff;
	if (spec & 0x02) d1 ^= 0x80;
	if (spec & 0x01) {*obuf++ = d0; *obuf++ = d1; }
	else {*obuf++ = d1; *obuf++ = d0; }
      }
      ocnt++;
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  snd_hdr->blk_cnt	= blk_cnt;
  /* Save Codec Specific */
  xa_dvi_state.L_valprev	= L_valpred;
  xa_dvi_state.L_index		= L_index;
  xa_dvi_state.R_valprev	= R_valpred;
  xa_dvi_state.R_index		= R_index;
  xa_dvi_state.L_store		= L_store;
  xa_dvi_state.R_store		= R_store;
  return(ocnt);
}

/********** XA_ADecode_IMA4M_PCMxM *********************************
 * Convert QT IMA4 ADPCM Mono Samples into PCM 2 BPS Mono Samples
 * The spec flag takes care of the various linear/signed/endian
 * conversions
 *  Input        Ouput        Spec  1st  2nd
 *  -----------------------------------------
 *  MSADPCM to Signed Big       0    D1    D0
 *  MSADPCM to Signed Little    1    D0    D1
 *  MSADPCM to Linear Big       2    D1^80 D0
 *  MSADPCM to Linear Little    3    D0    D1^80
 *
 *  bit 2 (& 0x04) 1 byte output.
 *  bit 3 (& 0x08) AU output instead of linear PCM.
 *
 * Global Variables:
 *   xaUBYTE xa_sign_2_ulaw[256]        conversion table.
 *   XA_Audio_Next_Snd()        routine to move to next sound header.
 ***************************************************************/
xaULONG XA_ADecode_IMA4M_PCMxM(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  xaLONG blk_cnt,valpred, index, step;

  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL; 
  blk_cnt	= snd_hdr->blk_cnt;

  /* Init Codec specific Variables */
  valpred	= xa_dvi_state.L_valprev;
  index		= xa_dvi_state.L_index;
  step		= xa_audio_DVI_stepsize_table[index];

  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    { inc_cnt += inc;
	/*** Decode Sample ***/
      if (snd_hdr->flag == 2)
      { dataL = valpred;
	snd_hdr->flag = (blk_cnt>0)?(1):(0);
      }
      else
      { xaLONG nyb0,nyb1;
        if (snd_hdr->flag == 0)
        {  /* Read Header - POD macro */
	  valpred = *ibuf++ << 8;	valpred |= (*ibuf++);
	  index = valpred & 0x7f;
	  if (index > 88)
	  { fprintf(stderr,"IMA4: index err %d\n",index);
	    index = 88;
	  }
	  valpred &= 0xff80;
	  if (valpred & 0x8000)	valpred = valpred - 0x10000;
	  blk_cnt = snd_hdr->blk_size - 2;
	  byte_cnt += 2;
	  step = xa_audio_DVI_stepsize_table[index];
	  snd_hdr->flag = 1;
        }

	nyb0 = *ibuf++;		/* LSB held 1st sample */
	nyb1 = (nyb0 >> 4) & 0x0f;
	nyb0 &= 0x0f;
	byte_cnt++;	blk_cnt--;

	AUD_CALC_DVI(valpred,nyb0,index,step);
	dataL = valpred;
	AUD_CALC_DVI(valpred,nyb1,index,step);
	snd_hdr->flag = 2;
      }
      samp_cnt--;
    }

    while(inc_cnt >= (1<<24))
    { inc_cnt -= (1<<24);	
        /*** Output Sample ***/
      if (spec & 4)  /* 1 byte output */
      { xaUBYTE d0 = ((xaULONG)(dataL) >> 8) & 0xff;
	if (spec & 8)    *obuf++ = xa_sign_2_ulaw[ (xaULONG)(d0) ];
	else             *obuf++ = (spec & 2)?(d0 ^ 0x80):(d0);
      }
      else
      { xaUBYTE d1,d0; d1 = (dataL>>8) & 0xff; d0 = dataL & 0xff;
	if (spec & 0x02) d1 ^= 0x80;
	if (spec & 0x01) {*obuf++ = d0; *obuf++ = d1; }
	else {*obuf++ = d1; *obuf++ = d0; }
      }
      ocnt++;
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  snd_hdr->blk_cnt	= blk_cnt;
  /* Save Codec Specific */
  xa_dvi_state.L_valprev	= valpred;
  xa_dvi_state.L_index		= index;
  return(ocnt);
}

/********** XA_ADecode_IMA4S_PCMxM *********************************
 * Convert QT IMA4 ADPCM Stereo Samples into PCM 2 BPS Mono Samples
 * The spec flag takes care of the various linear/signed/endian
 * conversions
 *  Input        Ouput        Spec  1st  2nd
 *  -----------------------------------------
 *  MSADPCM to Signed Big       0    D1    D0
 *  MSADPCM to Signed Little    1    D0    D1
 *  MSADPCM to Linear Big       2    D1^80 D0
 *  MSADPCM to Linear Little    3    D0    D1^80
 *
 *  bit 2 (& 0x04) 1 byte output.
 *  bit 3 (& 0x08) AU output instead of linear PCM.
 *
 * Global Variables:
 *   xaUBYTE xa_sign_2_ulaw[256]        conversion table.
 *   XA_Audio_Next_Snd()        routine to move to next sound header.
 ***************************************************************/

xaULONG XA_ADecode_IMA4S_PCMxM(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  xaUBYTE *ibufR;
  xaLONG blk_cnt,blk_size;
  xaLONG L_valpred, L_index, L_step, R_valpred, R_index, R_step;

  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL; 
  blk_cnt	= snd_hdr->blk_cnt;
  blk_size	= snd_hdr->blk_size >> 1;

  /* Init Codec specific Variables */
  L_valpred	= xa_dvi_state.L_valprev;
  L_index	= xa_dvi_state.L_index;
  L_step	= xa_audio_DVI_stepsize_table[L_index];
  R_valpred	= xa_dvi_state.R_valprev;
  R_index	= xa_dvi_state.R_index;
  R_step	= xa_audio_DVI_stepsize_table[R_index];

/* POD: assume Right channel is always within same block as left channel 
 * for now at least */
  ibufR = ibuf;
  ibufR += blk_size;
  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    { inc_cnt += inc;
	/*** Decode Sample ***/
      if (snd_hdr->flag == 2)
      { dataL = L_valpred;
	dataR = R_valpred;

	if (blk_cnt == 0)
        {  byte_cnt += blk_size;
	   ibuf += blk_size;	/* skip R channel */
	   ibufR += blk_size;
	   snd_hdr->flag = 0;
	}
        else snd_hdr->flag = 1;
      }
      else 
      { xaLONG nyb0,nyb1; 
	if (snd_hdr->flag == 0)
	{  /* Read Header - POD macro */
	  L_valpred = *ibuf++ << 8;	L_valpred |= (*ibuf++);
	  L_index = L_valpred & 0x7f;

	  if (L_index > 88)
	  { fprintf(stderr,"IMA4: L index err %d\n",L_index);
	    L_index = 88;
	  }
	  L_valpred &= 0xff80;
	  if (L_valpred & 0x8000)	L_valpred = L_valpred - 0x10000;
	  L_step = xa_audio_DVI_stepsize_table[L_index];

	  R_valpred = *ibufR++ << 8;	R_valpred |= (*ibufR++);
	  R_index = R_valpred & 0x7f;

	  if (R_index > 88)
	  { fprintf(stderr,"IMA4: R_index err %d\n",R_index);
	    R_index = 88;
	  }
	  R_valpred &= 0xff80;
	  if (R_valpred & 0x8000)	R_valpred = R_valpred - 0x10000;
	  R_step = xa_audio_DVI_stepsize_table[R_index];

	  blk_cnt = blk_size - 2;		byte_cnt += 2;
	  snd_hdr->flag = 1;
	}

	nyb0 = *ibuf++; nyb1 = (nyb0 >> 4) & 0x0f; nyb0 &= 0x0f;

	byte_cnt += 1;			blk_cnt -= 1;
	AUD_CALC_DVI(L_valpred,nyb0,L_index,L_step);
	dataL = L_valpred;
	AUD_CALC_DVI(L_valpred,nyb1,L_index,L_step);

	nyb0 = *ibufR++; nyb1 = (nyb0 >> 4) & 0x0f; nyb0 &= 0x0f;

	AUD_CALC_DVI(R_valpred,nyb0,R_index,R_step);
	dataR = R_valpred;
	AUD_CALC_DVI(R_valpred,nyb1,R_index,R_step);

        snd_hdr->flag = 2;
      }
      samp_cnt--;
    }

    while(inc_cnt >= (1<<24))
      { xaLONG data = (dataL + dataR) / 2;
/*    { xaULONG data = ( (dataL & 0xffff) + (dataR & 0xffff)) >> 1; */
      inc_cnt -= (1<<24);	
        /*** Output Sample ***/
      if (spec & 4)  /* 1 byte output */
      { xaUBYTE d0 = ((xaULONG)(data) >> 8) & 0xff;
	if (spec & 8)    *obuf++ = xa_sign_2_ulaw[ (xaULONG)(d0) ];
	else             *obuf++ = (spec & 2)?(d0 ^ 0x80):(d0);
      }
      else
      { xaUBYTE d1,d0; d1 = (data>>8) & 0xff; d0 = data & 0xff;
	if (spec & 0x02) d1 ^= 0x80;
	if (spec & 0x01) {*obuf++ = d0; *obuf++ = d1; }
	else {*obuf++ = d1; *obuf++ = d0; }
      }
      ocnt++;
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;
  snd_hdr->blk_cnt	= blk_cnt;
  /* Save Codec Specific */
  xa_dvi_state.L_valprev	= L_valpred;
  xa_dvi_state.L_index		= L_index;
  xa_dvi_state.R_valprev	= R_valpred;
  xa_dvi_state.R_index		= R_index;
  return(ocnt);
}


#include "xa_gsm.h"

typedef struct
{
  xaSHORT	buf0[160];
  xaSHORT	buf1[160];
} XA_AUDIO_GSM_STATE;
static XA_AUDIO_GSM_STATE gsm_state;


/***************************************************************************
 *
 *
 */ 
xaULONG XA_ADecode_GSMM_PCMxM(snd_hdr,obuf,ocnt,buff_size)
XA_SND *snd_hdr;
xaUBYTE *obuf;
xaULONG ocnt,buff_size;
{ XA_ADECODE_DECLARE_LOCAL; 
  if (snd_hdr==0) return(ocnt);
  XA_ADECODE_INIT_LOCAL;	/* Init Local Variables */
  /* Optionally Init Codec Specific Structure Here */ 
  while(ocnt < buff_size)
  {
    if (inc_cnt < (1<<24))
    {	
      if (flag == 0)
      { 
	xaSHORT sr;
	sr = *ibuf++;
	LARc[0] = sr & 0x3f;  sr >>= 6;
	sr |= (xaShort)*ibuf++ << 2;
	LARc[1] = sr & 0x3f;  sr >>= 6;
	sr |= (xaShort)*ibuf++ << 4;
	LARc[2] = sr & 0x1f;  sr >>= 5;
	LARc[3] = sr & 0x1f;  sr >>= 5;
	sr |= (xaShort)*ibuf++ << 2;
	LARc[4] = sr & 0xf;  sr >>= 4;
	LARc[5] = sr & 0xf;  sr >>= 4;
	sr |= (xaShort)*ibuf++ << 2;			/* 5 */
	LARc[6] = sr & 0x7;  sr >>= 3;
	LARc[7] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 4;
	Nc[0] = sr & 0x7f;  sr >>= 7;
	bc[0] = sr & 0x3;  sr >>= 2;
	Mc[0] = sr & 0x3;  sr >>= 2;
	sr |= (xaShort)*ibuf++ << 1;
	xmaxc[0] = sr & 0x3f;  sr >>= 6;
	xmc[0] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;
	xmc[1] = sr & 0x7;  sr >>= 3;
	xmc[2] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 2;
	xmc[3] = sr & 0x7;  sr >>= 3;
	xmc[4] = sr & 0x7;  sr >>= 3;
	xmc[5] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 1;			/* 10 */
	xmc[6] = sr & 0x7;  sr >>= 3;
	xmc[7] = sr & 0x7;  sr >>= 3;
	xmc[8] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;
	xmc[9] = sr & 0x7;  sr >>= 3;
	xmc[10] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 2;
	xmc[11] = sr & 0x7;  sr >>= 3;
	xmc[12] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 4;
	Nc[1] = sr & 0x7f;  sr >>= 7;
	bc[1] = sr & 0x3;  sr >>= 2;
	Mc[1] = sr & 0x3;  sr >>= 2;
	sr |= (xaShort)*ibuf++ << 1;
	xmaxc[1] = sr & 0x3f;  sr >>= 6;
	xmc[13] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;				/* 15 */
	xmc[14] = sr & 0x7;  sr >>= 3;
	xmc[15] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 2;
	xmc[16] = sr & 0x7;  sr >>= 3;
	xmc[17] = sr & 0x7;  sr >>= 3;
	xmc[18] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 1;
	xmc[19] = sr & 0x7;  sr >>= 3;
	xmc[20] = sr & 0x7;  sr >>= 3;
	xmc[21] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;
	xmc[22] = sr & 0x7;  sr >>= 3;
	xmc[23] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 2;
	xmc[24] = sr & 0x7;  sr >>= 3;
	xmc[25] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 4;			/* 20 */
	Nc[2] = sr & 0x7f;  sr >>= 7;
	bc[2] = sr & 0x3;  sr >>= 2;
	Mc[2] = sr & 0x3;  sr >>= 2;
	sr |= (xaShort)*ibuf++ << 1;
	xmaxc[2] = sr & 0x3f;  sr >>= 6;
	xmc[26] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;
	xmc[27] = sr & 0x7;  sr >>= 3;
	xmc[28] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 2;
	xmc[29] = sr & 0x7;  sr >>= 3;
	xmc[30] = sr & 0x7;  sr >>= 3;
	xmc[31] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 1;
	xmc[32] = sr & 0x7;  sr >>= 3;
	xmc[33] = sr & 0x7;  sr >>= 3;
	xmc[34] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;				/* 25 */
	xmc[35] = sr & 0x7;  sr >>= 3;
	xmc[36] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 2;
	xmc[37] = sr & 0x7;  sr >>= 3;
	xmc[38] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 4;
	Nc[3] = sr & 0x7f;  sr >>= 7;
	bc[3] = sr & 0x3;  sr >>= 2;
	Mc[3] = sr & 0x3;  sr >>= 2;
	sr |= (xaShort)*ibuf++ << 1;
	xmaxc[3] = sr & 0x3f;  sr >>= 6;
	xmc[39] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;
	xmc[40] = sr & 0x7;  sr >>= 3;
	xmc[41] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 2;			/* 30 */
	xmc[42] = sr & 0x7;  sr >>= 3;
	xmc[43] = sr & 0x7;  sr >>= 3;
	xmc[44] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 1;
	xmc[45] = sr & 0x7;  sr >>= 3;
	xmc[46] = sr & 0x7;  sr >>= 3;
	xmc[47] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;
	xmc[48] = sr & 0x7;  sr >>= 3;
	xmc[49] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 2;
	xmc[50] = sr & 0x7;  sr >>= 3;
	xmc[51] = sr & 0x7;  sr >>= 3;

	Gsm_Decoder(&gsm_state, LARc, Nc, bc, Mc, xmaxc, xmc, gsm_buf.buf0);
/*
	carry = sr & 0xf;
	sr = carry;
*/
	/* 2nd frame */
	sr &= 0xf;
	sr |= (xaShort)*ibuf++ << 4;			/* 1 */
	LARc[0] = sr & 0x3f;  sr >>= 6;
	LARc[1] = sr & 0x3f;  sr >>= 6;
	sr = *ibuf++;
	LARc[2] = sr & 0x1f;  sr >>= 5;
	sr |= (xaShort)*ibuf++ << 3;
	LARc[3] = sr & 0x1f;  sr >>= 5;
	LARc[4] = sr & 0xf;  sr >>= 4;
	sr |= (xaShort)*ibuf++ << 2;
	LARc[5] = sr & 0xf;  sr >>= 4;
	LARc[6] = sr & 0x7;  sr >>= 3;
	LARc[7] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;				/* 5 */
	Nc[0] = sr & 0x7f;  sr >>= 7;
	sr |= (xaShort)*ibuf++ << 1;
	bc[0] = sr & 0x3;  sr >>= 2;
	Mc[0] = sr & 0x3;  sr >>= 2;
	sr |= (xaShort)*ibuf++ << 5;
	xmaxc[0] = sr & 0x3f;  sr >>= 6;
	xmc[0] = sr & 0x7;  sr >>= 3;
	xmc[1] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 1;
	xmc[2] = sr & 0x7;  sr >>= 3;
	xmc[3] = sr & 0x7;  sr >>= 3;
	xmc[4] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;
	xmc[5] = sr & 0x7;  sr >>= 3;
	xmc[6] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 2;			/* 10 */
	xmc[7] = sr & 0x7;  sr >>= 3;
	xmc[8] = sr & 0x7;  sr >>= 3;
	xmc[9] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 1;
	xmc[10] = sr & 0x7;  sr >>= 3;
	xmc[11] = sr & 0x7;  sr >>= 3;
	xmc[12] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;
	Nc[1] = sr & 0x7f;  sr >>= 7;
	sr |= (xaShort)*ibuf++ << 1;
	bc[1] = sr & 0x3;  sr >>= 2;
	Mc[1] = sr & 0x3;  sr >>= 2;
	sr |= (xaShort)*ibuf++ << 5;
	xmaxc[1] = sr & 0x3f;  sr >>= 6;
	xmc[13] = sr & 0x7;  sr >>= 3;
	xmc[14] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 1;			/* 15 */
	xmc[15] = sr & 0x7;  sr >>= 3;
	xmc[16] = sr & 0x7;  sr >>= 3;
	xmc[17] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;
	xmc[18] = sr & 0x7;  sr >>= 3;
	xmc[19] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 2;
	xmc[20] = sr & 0x7;  sr >>= 3;
	xmc[21] = sr & 0x7;  sr >>= 3;
	xmc[22] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 1;
	xmc[23] = sr & 0x7;  sr >>= 3;
	xmc[24] = sr & 0x7;  sr >>= 3;
	xmc[25] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;
	Nc[2] = sr & 0x7f;  sr >>= 7;
	sr |= (xaShort)*ibuf++ << 1;			/* 20 */
	bc[2] = sr & 0x3;  sr >>= 2;
	Mc[2] = sr & 0x3;  sr >>= 2;
	sr |= (xaShort)*ibuf++ << 5;
	xmaxc[2] = sr & 0x3f;  sr >>= 6;
	xmc[26] = sr & 0x7;  sr >>= 3;
	xmc[27] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 1;	
	xmc[28] = sr & 0x7;  sr >>= 3;
	xmc[29] = sr & 0x7;  sr >>= 3;
	xmc[30] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;
	xmc[31] = sr & 0x7;  sr >>= 3;
	xmc[32] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 2;
	xmc[33] = sr & 0x7;  sr >>= 3;
	xmc[34] = sr & 0x7;  sr >>= 3;
	xmc[35] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 1;			/* 25 */
	xmc[36] = sr & 0x7;  sr >>= 3;
	xmc[37] = sr & 0x7;  sr >>= 3;
	xmc[38] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;
	Nc[3] = sr & 0x7f;  sr >>= 7;
	sr |= (xaShort)*ibuf++ << 1;		
	bc[3] = sr & 0x3;  sr >>= 2;
	Mc[3] = sr & 0x3;  sr >>= 2;
	sr |= (xaShort)*ibuf++ << 5;
	xmaxc[3] = sr & 0x3f;  sr >>= 6;
	xmc[39] = sr & 0x7;  sr >>= 3;
	xmc[40] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 1;
	xmc[41] = sr & 0x7;  sr >>= 3;
	xmc[42] = sr & 0x7;  sr >>= 3;
	xmc[43] = sr & 0x7;  sr >>= 3;
	sr = *ibuf++;				/* 30 */
	xmc[44] = sr & 0x7;  sr >>= 3;
	xmc[45] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 2;
	xmc[46] = sr & 0x7;  sr >>= 3;
	xmc[47] = sr & 0x7;  sr >>= 3;
	xmc[48] = sr & 0x7;  sr >>= 3;
	sr |= (xaShort)*ibuf++ << 1;
	xmc[49] = sr & 0x7;  sr >>= 3;
	xmc[50] = sr & 0x7;  sr >>= 3;
	xmc[51] = sr & 0x7;  sr >>= 3;
	Gsm_Decoder(&gsm_state, LARc, Nc, bc, Mc, xmaxc, xmc, gsm_buf.buf1);

	byte_cnt += 65;
      }
	/*** Decode Sample and increment byte_cnt ***/
      Gsm_Decoder(s, LARc, Nc, bc, Mc, xmaxc, xmc, target);
      if (flag < 160)  dataL  = gsm_buf.buf0[flag];
      else if (flag < 320)  dataL  = gsm_buf.buf1[ (flag - 160) ];
      else /* ERROR */ dataL = 0;

      flag++; if (flag >= 320) flag = 0;
      samp_cnt--;
      inc_cnt += inc;
    }
    while(inc_cnt >= (1<<24))
    { 
        /*** Output Sample ***/
      if (spec & 4)  /* 1 byte output */
      { xaUBYTE d0 = ((xaULONG)(dataL) >> 8) & 0xff;
        if (spec & 8)    *obuf++ = xa_sign_2_ulaw[ (xaULONG)(d0) ];
        else             *obuf++ = (spec & 2)?(d0 ^ 0x80):(d0);
      }
      else
      { xaUBYTE d1,d0; d1 = (dataL>>8) & 0xff; d0 = dataL & 0xff;
        if (spec & 0x02) d1 ^= 0x80;
        if (spec & 0x01) {*obuf++ = d0; *obuf++ = d1; }
        else {*obuf++ = d1; *obuf++ = d0; }
      }
      ocnt++;
      inc_cnt -= (1<<24);	
      if (ocnt >= buff_size) break;
    }
    if (samp_cnt <= 0)		{ XA_ADECODE_MOVE_ON; }
  }
  XA_ADECODE_SAVE_LOCAL;     /* save local variables */
  /* Optionally Save Codec Specific Structure Here */
  return(ocnt);
}


/*+_+_+_+_+_+_+_+___+_+_+_+_+_+_+_+_+_++_+_++_+_+_++_+_+++_+_+_+_+_+*/
/*+_+_+_+_+_+_+_+___+_+_+_+_+_+_+_+_+_++_+_++_+_+_++_+_+++_+_+_+_+_+*/
/*+_+_+_+_+_+_+_+___+_+_+_+_+_+_+_+_+_++_+_++_+_+_++_+_+++_+_+_+_+_+*/

void XA_Audio_Init_Snd(snd_hdr)
XA_SND *snd_hdr;
{
  snd_hdr->flag     = 0;
  snd_hdr->inc_cnt  = 0;
  snd_hdr->byte_cnt = 0;
  snd_hdr->samp_cnt = snd_hdr->tot_samps;
  Gen_Ulaw_2_Signed();
  Gen_Arm_2_Signed();
}


extern XA_AUD_FLAGS *vaudiof;
extern xaULONG xa_vaudio_present;

/********* XA_Add_Sound ****************************************
 * IMPORTANT: THIS ROUTINE IS IN THE VIDEO DOMAIN
 *
 * Global Variables Used:
 *   double XAAUD->scale	linear scale of frequency
 *   xaULONG  xa_audio_hard_buff	size of sound chunk - set by XA_Closest_Freq().
 *   xaULONG  XAAUD->bufferit	xaTRUE if this routine is to convert and buffer
 * 				the audio data ahead of time.
 *   xaULONG  xa_audio_hard_type	Audio Type of Current Hardware
 *
 * Add sound double checks xa_audio_present. 
 *   If UNK then it calls XA_Audio_Init().
 *   If OK adds the sound, else returns false.
 *****/
xaULONG XA_Add_Sound(anim_hdr,isnd,itype,fpos,ifreq,ilen,stime,stimelo,
			blockalign, sampsblock)
XA_ANIM_HDR *anim_hdr;
xaUBYTE *isnd;
xaULONG itype;	/* sound type */
xaULONG fpos;	/* file position */
xaULONG ifreq;	/* input frequency */
xaULONG ilen;	/* length of snd sample chunk in bytes */
xaLONG *stime;	/* start time of sample */
xaULONG *stimelo;	/* fractional start time of sample */
xaULONG blockalign;
xaULONG sampsblock;
{ XA_SND *new_snd;
  xaULONG bps,isamps,totsamps,hfreq,inc,ret;
  double finc,ftime,fadj_freq;

#ifndef XA_AUDIO

  if (xa_verbose) 
  { fprintf(stderr,
	"Warning: Since Audio Support was not enabled in this executable\n");
    fprintf(stderr,"the audio portion of this file is ignored.\n");
  }
  return(xaFALSE);

#else

  /* If audio hasn't been initialized, then init it */
  if (xa_vaudio_present == XA_AUDIO_UNK)
  { XA_AUDIO_INIT(xa_vaudio_present);  /* note: also sets xa_forkit */
    if (xa_forkit==xaFALSE) xa_vaudio_present = XA_AUDIO_ERR;
  }
  /* Return xaFALSE if it's not OK */
  if (xa_vaudio_present != XA_AUDIO_OK)
  {
    if (xa_forkit == xaTRUE)
    { XA_AUDIO_EXIT();
      xa_forkit = xaFALSE;
    }
    return(xaFALSE);
  }

  new_snd = (XA_SND *)malloc(sizeof(XA_SND));
  if (new_snd==0) TheEnd1("snd malloc err");

  bps = 1;

  if ( (itype & XA_AUDIO_TYPE_MASK) == XA_AUDIO_IMA4)
  { xaLONG w,tmp_len;
    new_snd->blk_size = blockalign;

     /** calculate total samples in entire chunk for timing purposes */
    w = (ilen / blockalign);  
    tmp_len = sampsblock * w;  		/* out len based on full blocks */

    w = ilen - (w * blockalign);	/* bytes remaining for partial blocks*/

    if (itype == XA_AUDIO_IMA4_M)
    { w -= 2;	/* sub header */
      if (w >= 0)
      { w *= 2;  /* 2 samps per byte */
        w += 0;  /* 1 samp in header */
        tmp_len += w;
      }
    }
    if (itype == XA_AUDIO_IMA4_S)
    { w -= 2;	/* sub header */
      if (w >= 0)
      { w *= 1;  /* 1 samps per byte */
        w += 0;  /* 1 samp in header */
        tmp_len += w;
      }
    }
    totsamps = isamps = tmp_len;
  }
  else if ( (itype & XA_AUDIO_TYPE_MASK) == XA_AUDIO_DVI)
  { xaLONG w,tmp_len;
    new_snd->blk_size = blockalign;

     /** calculate total samples in entire chunk for timing purposes */
    w = (ilen / blockalign);  
    tmp_len = sampsblock * w;  		/* out len based on full blocks */

    w = ilen - (w * blockalign);	/* bytes remaining for partial blocks*/

    if (itype == XA_AUDIO_DVI_M)
    { w -= 4;	/* sub header */
      if (w >= 0)
      { w *= 2;  /* 2 samps per byte */
        w += 1;  /* 1 samp in header */
        tmp_len += w;
      }
    }
    if (itype == XA_AUDIO_DVI_S)
    { w -= 8;	/* sub header */
      if (w >= 0)
      { w *= 1;  /* 1 samps per byte */
        w += 1;  /* 1 samp in header */
        tmp_len += w;
      }
    }
    totsamps = isamps = tmp_len;
  }
  else if ((itype & XA_AUDIO_TYPE_MASK) == XA_AUDIO_ADPCM)
  { xaLONG w,tmp_len;

    new_snd->blk_size = blockalign;

     /** calculate total samples in entire chunk for timing purposes */
    w = (ilen / blockalign);  
    tmp_len = sampsblock * w;  		/* out len based on full blocks */

    w = ilen - (w * blockalign);	/* bytes remaining for partial blocks*/
    if (itype == XA_AUDIO_ADPCM_M)
    { 
      w -= (7 * 1);			/* subtract header */
      if (w >= 0)			/* if anything left */
      { w *= 2;				/* 2 samps per byte */
        w += 2;				/* plus samples in header */
        tmp_len += w;
      }
    }
    else if (itype == XA_AUDIO_ADPCM_S)
    { 
      w -= (7 * 2);			/* subtract header */
      if (w >= 0)			/* if anything left */
      { w *= 1;				/* 1 stereo samps per byte */
        w += 2;				/* plus samples in header */
        tmp_len += w;
      }
    }
    totsamps = isamps = tmp_len;
  }
  else
  {
    if (itype & XA_AUDIO_STEREO_MSK) bps *= 2;
    if (itype & XA_AUDIO_BPS_2_MSK) bps *= 2;
    totsamps = isamps = ilen / bps;
    new_snd->blk_size = bps;
  }

  new_snd->tot_samps = new_snd->samp_cnt = isamps;
  new_snd->tot_bytes = ilen;
  new_snd->byte_cnt = 0;
  new_snd->blk_cnt  = 0;

  new_snd->fpos = fpos;
  new_snd->type = itype;
  new_snd->flag = 0;
  new_snd->ifreq = ifreq;
  hfreq = (vaudiof->playrate)?(vaudiof->playrate):(ifreq);

  if (xa_forkit == xaTRUE) xa_forkit = XA_Video_Send2_Audio(XA_IPC_GET_CFREQ,
					NULL,0,hfreq,2000,&hfreq);
  else hfreq = 0;
  if (xa_forkit == xaTRUE) xa_forkit = XA_Video_Send2_Audio(XA_IPC_GET_BSIZE,
					NULL,0,0,2000,&xa_vaudio_hard_buff);
  if (xa_forkit == xaFALSE) return(xaFALSE);

  new_snd->hfreq = hfreq;
  new_snd->ch_size = xa_vaudio_hard_buff;


  /* Setup and return Chunk Start Time */
  new_snd->snd_time = *stime;
  { xaULONG tint;
    ftime = ((double)(totsamps) * 1000.0) / (double)(ifreq);
    tint = (xaULONG)(ftime);   /* get integer time */
    *stime += tint;
    ftime -= (double)(tint); /* get fraction time */
    *stimelo += (xaULONG)( ftime * (double)(1<<24) );
    while( (*stimelo) > (1<<24)) { *stime += 1; *stimelo -= (1<<24); }
  }

  /* Determine f2f inc */
  /** NEW STYLE  hfreq/ifreq **/
  fadj_freq = (double)(hfreq) * vaudiof->scale;
  finc = (double)(fadj_freq)/ (double)(ifreq);
  new_snd->inc = inc = (xaULONG)( finc * (double)(1<<24) );
  new_snd->inc_cnt = 0;

  /* Determine Chunk Time */
  ftime = ((double)(xa_vaudio_hard_buff) * 1000.0) / (double)(hfreq);
  new_snd->ch_time = (xaLONG)ftime;
  ftime -= (double)(new_snd->ch_time);
  new_snd->ch_timelo = (xaULONG)(ftime * (double)(1<<24));

  new_snd->prev = 0;
  new_snd->next = 0;

/* POD
fprintf(stderr,"Fork_Add_Sound itype %x\n",new_snd->type);
*/

  /* Send SND HDR */
  if (xa_forkit == xaTRUE) xa_forkit = XA_Video_Send2_Audio(XA_IPC_SND_ADD,
	new_snd, (sizeof(XA_SND)), anim_hdr->file_num, 2000, &ret);
  if (xa_forkit == xaFALSE) return(xaFALSE);
  if (ret == xaFALSE) return(xaFALSE);

  if (isnd==0) ilen = 0;

  /* Send SND Buffer */
  if (xa_forkit == xaTRUE) 
  {
    xa_forkit = XA_Video_Send2_Audio(XA_IPC_SND_BUF, isnd, 
					ilen, anim_hdr->file_num, 2000, &ret);
    free(isnd); isnd = 0;
    if (xa_forkit == xaFALSE) return(xaFALSE);
    if (ret == xaFALSE) return(xaFALSE);
  } 
  else 
  { free(isnd); isnd = 0; 
    return(xaFALSE); 
  }


/* new_snd->snd = isnd; */
/* new_snd->spec  */
/* new_snd->delta */

  return(xaTRUE);
#endif
}


/*******************************
 *
 ******************/
xaULONG XA_IPC_Sound(aud_hdr,new_snd)
XA_AUD_HDR *aud_hdr;
XA_SND *new_snd;
{ 
  xaULONG itype = new_snd->type;

/*POD
fprintf(stderr,"XA_IPC_Sound itype %x\n",itype);
*/
  /* Figure out which conversion routine to use */
  switch(xa_audio_hard_type)
  {
    case XA_AUDIO_SUN_AU:
      {
	switch(itype)
	{
	  case XA_AUDIO_SIGNED_1M:
	  case XA_AUDIO_SIGNED_2MB:
	  case XA_AUDIO_SIGNED_2ML:
	  case XA_AUDIO_LINEAR_1M:
	  case XA_AUDIO_LINEAR_2ML:
	  case XA_AUDIO_LINEAR_2MB:
	  case XA_AUDIO_SIGNED_1S:
	  case XA_AUDIO_SIGNED_2SB:
	  case XA_AUDIO_SIGNED_2SL:
	  case XA_AUDIO_LINEAR_1S:
	  case XA_AUDIO_LINEAR_2SL:
	  case XA_AUDIO_LINEAR_2SB:
		new_snd->spec = 
		    ((itype & XA_AUDIO_TYPE_MASK)==XA_AUDIO_LINEAR)?(0):(1);
		if (itype & XA_AUDIO_BPS_2_MSK)
		  new_snd->spec |= (itype & XA_AUDIO_BIGEND_MSK)?(2):(4);
		new_snd->spec |= 8; /* SUN AU bit */
		if (itype & XA_AUDIO_STEREO_MSK)
			new_snd->delta = XA_ADecode_PCMXS_PCM1M;
		else
			new_snd->delta = XA_ADecode_PCMXM_PCM1M;
		break;
	  case XA_AUDIO_SUN_AU:
		new_snd->delta = XA_ADecode_1M_1M;
		break;
	  case XA_AUDIO_ADPCM_M:
	        new_snd->spec = 2 | 4 | 8;
		new_snd->delta = XA_ADecode_ADPCMM_PCM2M;
		break;
	  case XA_AUDIO_ADPCM_S:
	        new_snd->spec = 2 | 4 | 8;
		new_snd->delta = XA_ADecode_ADPCMS_PCM2M;
		break;
	  case XA_AUDIO_DVI_M:
	        new_snd->spec = 2 | 4 | 8;
		new_snd->delta = XA_ADecode_DVIM_PCMxM;
		break;
	  case XA_AUDIO_DVI_S:
	        new_snd->spec = 2 | 4 | 8;
		new_snd->delta = XA_ADecode_DVIS_PCMxM;
		break;
	  case XA_AUDIO_IMA4_M:
	        new_snd->spec = 2 | 4 | 8;
		new_snd->delta = XA_ADecode_IMA4M_PCMxM;
		break;
	  case XA_AUDIO_IMA4_S:
	        new_snd->spec = 2 | 4 | 8;
		new_snd->delta = XA_ADecode_IMA4S_PCMxM;
		break;
	  case XA_AUDIO_NOP:
	        new_snd->spec = 2 | 4 | 8;
		new_snd->delta = XA_ADecode_NOP_PCMXM;
		break;
	  default: 
	    fprintf(stderr,"SUN_AU_AUDIO: Unsupported Software Type %x\n",
				itype);
		return(xaFALSE);
		break;
	}
      }
      break;

    case XA_AUDIO_SIGNED_2ML:
    case XA_AUDIO_SIGNED_2MB:
      {
	switch(itype)
	{
	  case XA_AUDIO_LINEAR_1M:      /* LIN1M -> SIN2M*  */
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 1;
		else    new_snd->spec = 2;
		new_snd->delta = XA_ADecode_PCM1M_PCM2M;
		break;
	  case XA_AUDIO_LINEAR_1S:      /* LIN1S -> SIN2M*  */
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 1;
		else    new_snd->spec = 2;
		new_snd->delta = XA_ADecode_PCM1S_PCMxM;
		break;
	  case XA_AUDIO_SIGNED_1S:      /* SIN1S -> SIN2M*  */
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 6;
		else    new_snd->spec = 5;
		new_snd->delta = XA_ADecode_PCM1S_PCMxM;
		break;
	  case XA_AUDIO_SIGNED_1M:      /* SIN1M -> SIN2M*  */
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 2;
		else    new_snd->spec = 1;
		new_snd->delta = XA_ADecode_PCM1M_PCM2M;
		break;
	  case XA_AUDIO_LINEAR_2MB:     /* LIN2M* -> SIN2M*  */
	  case XA_AUDIO_LINEAR_2ML:
	  case XA_AUDIO_SIGNED_2MB:     /* SIN2M* -> SIN2M*  */
	  case XA_AUDIO_SIGNED_2ML:
	  case XA_AUDIO_LINEAR_2SB:     /* LIN2S* -> SIN2M*  */
	  case XA_AUDIO_LINEAR_2SL:
	  case XA_AUDIO_SIGNED_2SB:     /* SIN2S* -> SIN2M*  */
	  case XA_AUDIO_SIGNED_2SL:
		  /* sign conversion? */
		if ( (itype & XA_AUDIO_TYPE_MASK) == XA_AUDIO_SIGNED)
			new_snd->spec = 0x10;
		else	new_snd->spec = 0x02;
		  /* src endian? */
		new_snd->spec |= (itype & XA_AUDIO_BIGEND_MSK)?(0):(1);
		  /* dst endian? */
		new_snd->spec |= 
			(xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)?(0):(4);
		  /* stereo? */
		new_snd->spec |= (itype & XA_AUDIO_STEREO_MSK)?(8):(0); 
		new_snd->delta = XA_ADecode_PCM2X_PCM2M;
		break;
	  case XA_AUDIO_ADPCM_M:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 0;
		else	new_snd->spec = 1;
		new_snd->delta = XA_ADecode_ADPCMM_PCM2M;
		break;
	  case XA_AUDIO_ADPCM_S:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 0;
		else	new_snd->spec = 1;
		new_snd->delta = XA_ADecode_ADPCMS_PCM2M;
		break;
	  case XA_AUDIO_DVI_M:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 0;
		else	new_snd->spec = 1;
		new_snd->delta = XA_ADecode_DVIM_PCMxM;
		break;
	  case XA_AUDIO_DVI_S:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 0;
		else	new_snd->spec = 1;
		new_snd->delta = XA_ADecode_DVIS_PCMxM;
		break;
	  case XA_AUDIO_IMA4_M:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 0;
		else	new_snd->spec = 1;
		new_snd->delta = XA_ADecode_IMA4M_PCMxM;
		break;
	  case XA_AUDIO_IMA4_S:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 0;
		else	new_snd->spec = 1;
		new_snd->delta = XA_ADecode_IMA4S_PCMxM;
		break;
	  case XA_AUDIO_NOP:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 0;
		else	new_snd->spec = 1;
		new_snd->delta = XA_ADecode_NOP_PCMXM;
		break;
	  case XA_AUDIO_ULAWS:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 0 | 8;
		else	new_snd->spec = 1 | 8;
		new_snd->delta = XA_ADecode_ULAWx_PCM2M;
		break;
	  case XA_AUDIO_ULAW:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 0;
		else	new_snd->spec = 1;
		new_snd->delta = XA_ADecode_ULAWx_PCM2M;
		break;
	  case XA_AUDIO_ARMLAWS:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 0 | 8;
		else	new_snd->spec = 1 | 8;
		new_snd->delta = XA_ADecode_ARMLAWx_PCM2M;
		break;
	  case XA_AUDIO_ARMLAW:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 0;
		else	new_snd->spec = 1;
		new_snd->delta = XA_ADecode_ARMLAWx_PCM2M;
		break;
	  case XA_AUDIO_GSM_M:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 0;
		else	new_snd->spec = 1;
		new_snd->delta = XA_ADecode_GSMM_PCMxM;
		break;
	  default:
	fprintf(stderr,"F_AUDIO_SIN2M: Unsupported Software Type(%x)\n",
			itype);
		return(xaFALSE);
		break;

	}
      }
      break;

    case XA_AUDIO_LINEAR_1M:
      {
	switch(itype)
	{
	  case XA_AUDIO_SIGNED_1M:
	  case XA_AUDIO_SIGNED_2MB:
	  case XA_AUDIO_SIGNED_2ML:
	  case XA_AUDIO_LINEAR_1M:
	  case XA_AUDIO_LINEAR_2ML:
	  case XA_AUDIO_LINEAR_2MB:
	  case XA_AUDIO_SIGNED_1S:
	  case XA_AUDIO_SIGNED_2SB:
	  case XA_AUDIO_SIGNED_2SL:
	  case XA_AUDIO_LINEAR_1S:
	  case XA_AUDIO_LINEAR_2SL:
	  case XA_AUDIO_LINEAR_2SB:
		new_snd->spec = 
		    ((itype & XA_AUDIO_TYPE_MASK)==XA_AUDIO_LINEAR)?(0):(1);
		if (itype & XA_AUDIO_BPS_2_MSK)
		  new_snd->spec |= (itype & XA_AUDIO_BIGEND_MSK)?(2):(4);
		if (itype & XA_AUDIO_STEREO_MSK)
			new_snd->delta = XA_ADecode_PCMXS_PCM1M;
		else
			new_snd->delta = XA_ADecode_PCMXM_PCM1M;
		break;
	  case XA_AUDIO_ADPCM_M:
		new_snd->spec = 2 | 4;  /* 1 byte output */
		new_snd->delta = XA_ADecode_ADPCMM_PCM2M;
		break;
	  case XA_AUDIO_ADPCM_S:
		new_snd->spec = 2 | 4;  /* 1 byte output */
		new_snd->delta = XA_ADecode_ADPCMS_PCM2M;
		break;
	  case XA_AUDIO_DVI_M:
		new_snd->spec = 2 | 4;  /* 1 byte output */
		new_snd->delta = XA_ADecode_DVIM_PCMxM;
		break;
	  case XA_AUDIO_DVI_S:
		new_snd->spec = 2 | 4;  /* 1 byte output */
		new_snd->delta = XA_ADecode_DVIS_PCMxM;
		break;
	  case XA_AUDIO_IMA4_M:
		new_snd->spec = 2 | 4;  /* 1 byte output */
		new_snd->delta = XA_ADecode_IMA4M_PCMxM;
		break;
	  case XA_AUDIO_IMA4_S:
		new_snd->spec = 2 | 4;  /* 1 byte output */
		new_snd->delta = XA_ADecode_IMA4S_PCMxM;
		break;
	  case XA_AUDIO_NOP:
		new_snd->spec = 2 | 4;  /* 1 byte output */
		new_snd->delta = XA_ADecode_NOP_PCMXM;
		break;
	  default:
		fprintf(stderr,"AUDIO_LIN1M: Unsupported Software Type\n");
		return(xaFALSE);
		break;
	}
      }
      break;

    case XA_AUDIO_LINEAR_2ML:
    case XA_AUDIO_LINEAR_2MB:
      {
	switch(itype)
	{
	  case XA_AUDIO_LINEAR_1M:      /* LIN1M -> LIN2M*  */
		new_snd->spec = 0;
		new_snd->delta = XA_ADecode_PCM1M_PCM2M;
		break;
	  case XA_AUDIO_SIGNED_1M:      /* SIN1M -> LIN2M*  */
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 1;
		else    new_snd->spec = 2;
		new_snd->delta = XA_ADecode_PCM1M_PCM2M;
		break;
	  case XA_AUDIO_LINEAR_1S:      /* LIN1S -> LIN2M*  */
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 0;
		else    new_snd->spec = 0;
		new_snd->delta = XA_ADecode_PCM1S_PCMxM;
		break;
	  case XA_AUDIO_SIGNED_1S:      /* SIN1S -> LIN2M*  */
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 5;
		else    new_snd->spec = 6;
		new_snd->delta = XA_ADecode_PCM1S_PCMxM;
		break;
	  case XA_AUDIO_LINEAR_2MB:     /* LIN2M* -> LIN2M*  */
	  case XA_AUDIO_LINEAR_2ML:
	  case XA_AUDIO_SIGNED_2MB:     /* SIN2M* -> LIN2M*  */
	  case XA_AUDIO_SIGNED_2ML:
	  case XA_AUDIO_LINEAR_2SB:     /* LIN2S* -> LIN2M*  */
	  case XA_AUDIO_LINEAR_2SL:
	  case XA_AUDIO_SIGNED_2SB:     /* SIN2S* -> LIN2M*  */
	  case XA_AUDIO_SIGNED_2SL:
		  /* sign conversion? */
		if ( (itype & XA_AUDIO_TYPE_MASK) == XA_AUDIO_SIGNED)
			new_snd->spec = 0x12;
		else	new_snd->spec = 0;
		  /* src endian? */
		new_snd->spec |= (itype & XA_AUDIO_BIGEND_MSK)?(0):(1);
		  /* dst endian? */
		new_snd->spec |= 
			(xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)?(0):(4);
		  /* stereo? */
		new_snd->spec |= (itype & XA_AUDIO_STEREO_MSK)?(8):(0); 
		new_snd->delta = XA_ADecode_PCM2X_PCM2M;
		break;
	  case XA_AUDIO_ADPCM_M:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 2;
		else	new_snd->spec = 3;
		new_snd->delta = XA_ADecode_ADPCMM_PCM2M;
		break;
	  case XA_AUDIO_ADPCM_S:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 2;
		else	new_snd->spec = 3;
		new_snd->delta = XA_ADecode_ADPCMS_PCM2M;
		break;
	  case XA_AUDIO_DVI_M:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 2;
		else	new_snd->spec = 3;
		new_snd->delta = XA_ADecode_DVIM_PCMxM;
		break;
	  case XA_AUDIO_DVI_S:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 2;
		else	new_snd->spec = 3;
		new_snd->delta = XA_ADecode_DVIS_PCMxM;
		break;
	  case XA_AUDIO_IMA4_M:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 2;
		else	new_snd->spec = 3;
		new_snd->delta = XA_ADecode_IMA4M_PCMxM;
		break;
	  case XA_AUDIO_IMA4_S:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 2;
		else	new_snd->spec = 3;
		new_snd->delta = XA_ADecode_IMA4S_PCMxM;
		break;
	  case XA_AUDIO_NOP:
		if (xa_audio_hard_type & XA_AUDIO_BIGEND_MSK)
			new_snd->spec = 2;
		else	new_snd->spec = 3;
		new_snd->delta = XA_ADecode_NOP_PCMXM;
		break;
	  default:
		fprintf(stderr,"AUDIO_LIN2M: Unsupported Software Type\n");
		return(xaFALSE);
		break;
	}
      }
      break;


    default: 
      FREE(new_snd,0x507); new_snd = 0;
      fprintf(stderr,"AUDIO: Unknown Hardware Type\n");
      return(xaFALSE);
      break;
  }

  /** Set up prev pointer */
  if (aud_hdr->first_snd==0) new_snd->prev = 0;
  else new_snd->prev = aud_hdr->last_snd;

  /** Set up next pointer */
  if (aud_hdr->first_snd == 0)	aud_hdr->first_snd = new_snd;
  if (aud_hdr->last_snd)	aud_hdr->last_snd->next = new_snd;
  aud_hdr->last_snd = new_snd;
  return(xaTRUE);
}
