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

Routine:
  AFILE *AFrdAUhead (FILE *fp)

Purpose:
  Get file format information from an AU audio file

Description:
  This routine reads the header for an AU audio file.  The header information
  is used to set the file data format information in the audio file pointer
  structure.

  AU audio file header:
   Offset Length Type    Contents
      0     4     int   File identifier (".snd")
      4     4     int   Header size (bytes)
      8     4     int   Audio data length (bytes)
     12     4     int   Data encoding format
     16     4     int   Sample rate (samples per second)
     20     4     int   Number of interleaved channels
     24     4     int   AFsp identifier ("AFsp")
     28    ...    --    Additional header information
      -    ...    --    Audio data
  8-bit mu-law, 8-bit A-law, 8-bit integer, 16-bit integer, 32-bit IEEE
  floating-point, and 64-bit IEEE floating-point data formats are supported.

Parameters:
  <-  AFILE *AFrdAUhead
      Audio file pointer for the audio file
   -> FILE *fp
      File pointer for the file

Author / revision:
  P. Kabal  Copyright (C) 1998
  $Revision: 1.71 $  $Date: 1998/06/26 20:34:19 $

-------------------------------------------------------------------------*/

static char rcsid [] = "$Id: AFrdAUhead.c 1.71 1998/06/26 libtsp-v3r0 $";

#include <setjmp.h>
#include <string.h>

#include <libtsp.h>
#include <libtsp/nucleus.h>
#include <libtsp/AFheader.h>
#include <libtsp/AFmsg.h>
#include <libtsp/AFpar.h>
#include <libtsp/AUpar.h>

#define SAME_CSTR(str,ref) 	(memcmp (str, ref, sizeof (str)) == 0)

/* setjmp / longjmp environment */
extern jmp_buf AFR_JMPENV;


AFILE *
AFrdAUhead (fp)

     FILE *fp;

{
  AFILE *AFp;
  int Format;
  long int Ldata, offs;
  double ScaleF;
  char Info[AF_MAXINFO];
  struct AF_info Hinfo;
  struct AU_head Fhead;

/* Set the long jump environment; on error return a NULL */
  if (setjmp (AFR_JMPENV))
    return NULL;	/* Return from a header read error */

/* Read the data parameters */
  offs = RHEAD_S (fp, Fhead.Magic);
  offs += RHEAD_V (fp, Fhead.Lhead, DS_EB);
  offs += RHEAD_V (fp, Fhead.Ldata, DS_EB);
  offs += RHEAD_V (fp, Fhead.Dencod, DS_EB);
  offs += RHEAD_V (fp, Fhead.Srate, DS_EB);
  offs += RHEAD_V (fp, Fhead.Nchan, DS_EB);

/* Check the file magic */
  if (! SAME_CSTR (Fhead.Magic, FM_AU)) {
    UTwarn ("AFrdAUhead - %s", AFM_AU_BadId);
    return NULL;
  }

/* Pick up AFsp information records */
  Hinfo.Info = Info;
  Hinfo.N = 0;
  AFrdHinfo (fp, (int) (Fhead.Lhead - offs), &Hinfo, 1);

/* Set up the decoding parameters */
  switch (Fhead.Dencod) {
  case AU_MULAW8:
    Format = FD_MULAW8;
    ScaleF = AU_SF_MULAW8;
    break;
  case AU_ALAW8:
    Format = FD_ALAW8;
    ScaleF = AU_SF_ALAW8;
    break;
  case AU_LIN8:
    Format = FD_INT8;
    ScaleF = AU_SF_LIN8;
    break;
  case AU_LIN16:
    Format = FD_INT16;
    ScaleF = AU_SF_LIN16;
    break;
  case AU_FLOAT32:
    if (! UTcheckIEEE ())
      UTwarn ("AFrdAUhead - %s", AFM_AU_NoIEEE);
    Format = FD_FLOAT32;
    ScaleF = AU_SF_FLOAT32;
    break;
  case AU_DOUBLE64:
    if (! UTcheckIEEE ())
      UTwarn ("AFrdAUhead - %s", AFM_AU_NoIEEE);
    Format = FD_FLOAT64;
    ScaleF = AU_SF_DOUBLE64;
    break;
  default:
    UTwarn ("AFrdAUhead: %s: \"%ld\"", AFM_AU_UnsData,
	    (long int) Fhead.Dencod);
    return NULL;
  }

/* Set the parameters for file access */
  if (Fhead.Ldata == AU_NOSIZE)
    Ldata = AF_LDATA_UNDEF;
  else
    Ldata = (long int) Fhead.Ldata;
  AFp = AFsetRead (fp, FT_AU, Format, DS_EB, (double) Fhead.Srate, ScaleF,
		   (long int) Fhead.Nchan, Ldata, AF_NSAMP_UNDEF,
		   &Hinfo, AF_FIX_LDATA_HIGH);

  return AFp;
}
