/*
 *  This file is part of jcabc2ps,
 *  Copyright (C) 1996-1999  Michael Methfessel
 *  See file jcabc2ps.c for details.
 */

/*  The contents of this file (sox.h) permit the generation of .au
 *  files on arbitrary machines. All this material was taken from
 *  playabc, Copyright (C) 1994  Don Ward.
 */


/**************************************************************************/
/*
 * These are a few defines which allow Don Ward's playabc and tune programs
 * to use sound_tools routines from the publicly available sox libst.a library.
 * This means that playabc and tune can be run on platforms other than Suns.
 * This should work fine with sox versions 7 and later.
 *
 * Observers will note that this file contains elements which were inspired
 * by both the Sun multimedia headers and the sox headers.
 * Steve Allen (sla@lick.ucsc.edu) can be blamed for this.
 *
 */

#define audio_s2u st_linear_to_ulaw

#define audio_s2d(pcms) (((unsigned short)(pcms)) == 0x8000 ? -1. : \
                        ((double)((short)(pcms))) / 32767.)

#define audio_d2s(pcmd) ((pcmd) >= 1. ? 32767 : (pcmd) <= -1. ? -32767 :\
                                    (short)((pcmd) * 32767.))

#define AUDIO_SUCCESS (0)
#define AUDIO_UNIXERROR (-1)

#define SUN_UNSPEC ((unsigned)(~0))        /* Unspecified data size */
#define SUN_MAGIC       0x2e736e64              /* Really '.snd' */
#define SUN_ULAW        1                       /* u-law encoding */
#define SUN_HDRSIZE     24                      /* Size of minimal header */


/* libst.c - portable sound tools library
*/

/*
** This routine converts from linear to ulaw.
**
** Craig Reese: IDA/Supercomputing Research Center
** Joe Campbell: Department of Defense
** 29 September 1989
**
** References:
** 1) CCITT Recommendation G.711  (very difficult to follow)
** 2) "A New Digital Technique for Implementation of Any
**     Continuous PCM Companding Law," Villeret, Michel,
**     et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
**     1973, pg. 11.12-11.17
** 3) MIL-STD-188-113,"Interoperability and Performance Standards
**     for Analog-to_Digital Conversion Techniques,"
**     17 February 1987
**
** Input: Signed 16 bit linear sample
** Output: 8 bit ulaw sample
*/

#define ZEROTRAP    /* turn on the trap as per the MIL-STD */
#define BIAS 0x84   /* define the add-in bias for 16 bit samples */
#define CLIP 32635

unsigned char
st_linear_to_ulaw( sample )
int sample;
    {
    static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
                               4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
                               5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
                               5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
                               6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
                               6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
                               6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
                               6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
    int sign, exponent, mantissa;
    unsigned char ulawbyte;

    /* Get the sample into sign-magnitude. */
    sign = (sample >> 8) & 0x80;		/* set aside the sign */
    if ( sign != 0 ) sample = -sample;		/* get magnitude */
    if ( sample > CLIP ) sample = CLIP;		/* clip the magnitude */

    /* Convert from 16 bit linear to ulaw. */
    sample = sample + BIAS;
    exponent = exp_lut[( sample >> 7 ) & 0xFF];
    mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
    ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
#ifdef ZEROTRAP
    if ( ulawbyte == 0 ) ulawbyte = 0x02;	/* optional CCITT trap */
#endif

    return ulawbyte;
    }

/*
** This routine converts from ulaw to 16 bit linear.
**
** Craig Reese: IDA/Supercomputing Research Center
** 29 September 1989
**
** References:
** 1) CCITT Recommendation G.711  (very difficult to follow)
** 2) MIL-STD-188-113,"Interoperability and Performance Standards
**     for Analog-to_Digital Conversion Techniques,"
**     17 February 1987
**
** Input: 8 bit ulaw sample
** Output: signed 16 bit linear sample
*/

int
st_ulaw_to_linear_slow( ulawbyte )
unsigned char ulawbyte;
    {
    static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
    int sign, exponent, mantissa, sample;

    ulawbyte = ~ ulawbyte;
    sign = ( ulawbyte & 0x80 );
    exponent = ( ulawbyte >> 4 ) & 0x07;
    mantissa = ulawbyte & 0x0F;
    sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
    if ( sign != 0 ) sample = -sample;

    return sample;
    }


/*
 * Write out an unsigned long making sure that the byte order is big-endian
 * as is used by 680x0 and Sparc processors (which is where the use of
 * .snd and .au files originated--on Sun and NeXT systems).
 * This is to ensure that the byte order of the sound header is right.
 */
void be4(unsigned char * p, unsigned long ul)
{
  *p++ = (ul >> 24) & 0xff;
  *p++ = (ul >> 16) & 0xff;
  *p++ = (ul >> 8) & 0xff;
  *p++ = (ul) & 0xff;
}

/* write a generic header for .au or .snd file as on Sun, NeXT systems */
int write_header (int fd )
{
  unsigned char hdrbuf[SUN_HDRSIZE];

  be4(&hdrbuf[0], SUN_MAGIC);
  be4(&hdrbuf[4], SUN_HDRSIZE);
  be4(&hdrbuf[8], SUN_UNSPEC);
  be4(&hdrbuf[12], SUN_ULAW);
  be4(&hdrbuf[16], SAMPLES_PER_SEC);
  be4(&hdrbuf[20], 1);             /* No. of channels */

  /* and we leave the comment field as blank */

  if(write(fd, hdrbuf, SUN_HDRSIZE) == SUN_HDRSIZE)
    return AUDIO_SUCCESS;
  else
    return AUDIO_UNIXERROR;

}

