/*-------------- Telecommunications & Signal Processing Lab ---------------
                             McGill University

Routine:
  void AFwriteAlaw (AFILE *AFp, const float Fbuff[], int Nval)

Purpose:
  Write 8-bit A-law data to an audio file (float input values)

Description:
  This routine writes a specified number of 8-bit A-law samples to an audio
  file.  The input to this routine is a buffer of float values. The file must
  have been opened using subroutine AFopenWrite.  A warning message is printed
  if the input values exceed the dynamic range of the A-law representation.

Parameters:
   -> AFILE *AFp
      Audio file pointer for an audio file opened by AFopenWrite
   -> const float Fbuff[]
      Array of floats with the samples to be written
   -> int Nval
      Number of samples to be written

Author / revision:
  P. Kabal  Copyright (C) 1996
  $Revision: 1.6 $  $Date: 1996/08/14 18:15:59 $

-------------------------------------------------------------------------*/

static char rcsid [] = "$Id: AFwriteAlaw.c 1.6 1996/08/14 AFsp-V2R1 $";

#include <libtsp.h>
#include <libtsp/nucleus.h>
#include <libtsp/AFpar.h>
#include <libtsp/UTtypes.h>

#define LW		FDL_ALAW8
#define MINV(a, b)	(((a) < (b)) ? (a) : (b))
#define NBBUF		8192
#define NLEV		256
#define AMAX		32768

/* ITU-T Recommendation G.711
   Conversion to A-law is carried out using a quantization operation.  Given
   an array of (ordered) decision levels, the interval containing the input
   value is determined.  However, there is an ambiguity at the quantizer 
   decision levels themselves.  G.711 allows the output value corresponding to
   the decision levels to either go up or down.  For the quantization routine
   SPquant, the intervals are defined as Xq[i-1] < x <= Xq[i], and so that
   input values which lie at the decision level move downward.  In this routine
   SPquant is used to quantize the magnitude, with the sign being handled
   separately.

   A-law data is stored in sign-magnitude bit-complemented format.  The sign
   bit is 1 for positive data.  The uncomplemented byte is in sign-segment-
   mantissa format.

    bin no.   signal value     bit pattern  complement
     0-15      1, ... , 31     1 000 xxxx   1 101 xyxy
    16-31     33, ... , 63     1 001 xxxx   1 100 xyxy
    32-47     66, ... , 126    1 010 xxxx   1 111 xyxy
    48-63    132, ... , 252    1 011 xxxx   1 110 xyxy
    64-79    264, ... , 504    1 100 xxxx   1 001 xyxy
    80-95    528, ... , 1008   1 101 xxxx   1 000 xyxy
    96-111  1056, ... , 2016   1 110 xxxx   1 011 xyxy
   112-127  2112, ... , 4032   1 111 xxxx   1 010 xyxy

   SPquant is used to find a bin number for the absolute value of the samples.
   The bin number with sign directly corresponds to the (uncomplemented) A-law
   representation.  The decision levels are scaled by 8, corresponding to
   quantized values from -32256 to +32256 (for AFp->ScaleF = 1).
*/

static const float Xq[NLEV/2-1] = {
     16,    32,    48,    64,    80,    96,   112,   128,
    144,   160,   176,   192,   208,   224,   240,   256,
    272,   288,   304,   320,   336,   352,   368,   384,
    400,   416,   432,   448,   464,   480,   496,   512,
    544,   576,   608,   640,   672,   704,   736,   768,
    800,   832,   864,   896,   928,   960,   992,  1024,
   1088,  1152,  1216,  1280,  1344,  1408,  1472,  1536,
   1600,  1664,  1728,  1792,  1856,  1920,  1984,  2048,
   2176,  2304,  2432,  2560,  2688,  2816,  2944,  3072,
   3200,  3328,  3456,  3584,  3712,  3840,  3968,  4096,
   4352,  4608,  4864,  5120,  5376,  5632,  5888,  6144,
   6400,  6656,  6912,  7168,  7424,  7680,  7936,  8192,
   8704,  9216,  9728, 10240, 10752, 11264, 11776, 12288,
  12800, 13312, 13824, 14336, 14848, 15360, 15872, 16384,
  17408, 18432, 19456, 20480, 21504, 22528, 23552, 24576,
  25600, 26624, 27648, 28672, 29696, 30720, 31744
};

void
AFwriteAlaw (AFp, Fbuff, Nval)

     AFILE *AFp;
     const float Fbuff[];
     int Nval;

{
  int is, N, i;
  long int Novld, offs;
  uint1_t Buf[NBBUF/LW];
  double Fv;
  uint1_t ibin;

/* Write data to the audio file */
  offs = AFp->End;
  is = 0;
  Novld = AFp->Novld;
  while (is < Nval) {
    N = MINV (NBBUF / LW, Nval - is);
    for (i = 0; i < N; ++i) {
      Fv = AFp->ScaleF * Fbuff[i+is];
      if (Fv >= 0.0) {
	if (Fv > AMAX)
	  ++Novld;
	ibin = SPquant (Fv, Xq, NLEV/2);
	Buf[i] = ibin ^ 0xD5;	/* Set the sign bit, flip alternate bits */
      }
      else {
	if (-Fv > AMAX)
	  ++Novld;
	ibin = SPquant (-Fv, Xq, NLEV/2);
	Buf[i] = ibin ^ 0x55;	/* Flip alternate bits */
      }
    }
    FLwriteFile (AFp->fp, offs, (void *) Buf, (size_t) LW, (size_t) N);
    is = is + N;
    offs = offs + LW * N;
  }

  /* Update the file position and number of overloads*/
  AFp->End = offs;
  if (Novld > 0L && AFp->Novld == 0L)
      UTwarn ("AFwriteAlaw - Output data clipped");
  AFp->Novld = Novld;

  return;
}