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

Routine:
  AFILE *AFopenRead (const char Fname[], long int *Nsamp, long int *Nchan,
		     float *Sfreq, FILE *fpinfo)

Purpose:
  Open an audio file for reading

Description:
  This routine opens an audio file for reading.  The companion routine
  AFreadData reads data from the file.  Routine AFclose should be used to
  close the file.

  This routine reads the audio file header and optionally prints the header
  information.  Several file header formats are supported.  For files with
  no header or an unrecognized header, the file format can be declared by
  calling routine AFsetNHpar.  A banner identifying the audio file and its
  parameters is printed.

  AU audio file:
    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.
  RIFF WAVE:
    8-bit mu-law, 8-bit A-law, offset-binary 8-bit integer, and 16-bit integer
    data formats are supported.
  AIFF or AIFF-C audio file:
    8-bit mu-law, 8-bit A-law, 8-bit integer, and 16-bit integer data formats
    are supported.
  NIST SPHERE audio file:
    8-bit mu-law and 16-bit integer data formats are supported.
  IRCAM soundfile:
    8-bit mu-law, 8-bit A-law, 8-bit integer, 16-bit integer, and 32-bit
    floating-point data formats are supported.
  ESPS sampled data feature file:
    16-bit integer, 32-bit floating-point and 64-bit floating-point data
    formats are supported.
  SPPACK sampled data file:
    8-bit mu-law, 8-bit A-law and 16-bit integer data formats are supported.
  INRS-Telecommunications audio file:
    16-bit integer format is supported.
  Comdisco SPW Signal file:
    8-bit integer, 16-bit integer, 32-bit floating-point, 64-point
    floating-point, and text formats are supported.
  Text audio file:
    Data in character format (usually representing 16-bit integer values).
  Headerless audio file:
    Data format is specified by calling routine AFsetNHpar.

  For the fixed point file data representations, read operations return data
  values as follows.
     format            returned values
    8-bit mu-law   - [ -32124, +32124 ]
    8-bit A-law    - [ -32256, +32256 ]
    8-bit integer  - [ -16384, -16383 ]
    16-bit integer - [ -32768, +32767 ]
  Floating-point data in the input audio file are scaled by 32768 (except for
  ESPS sample data feature files).  For file float data values between -1 and
  +1, the returned values will be in the range [ -32768, +32768 ].

  File type determination:
    The default behaviour is to determine the file type from the header of the
    input file.  However this requires look-ahead and is not possible with
    files that are not random access (for instance a file stream from a pipe).
    For both random access and sequential access files, the file type can be
    specified explicitly with a call to routine AFsetFileType, obviating the
    need to determine the file type from the header.

  Number of samples:
    In some types of audio file types, the number of samples is specified in
    the file header.  In others, the number of samples is known only if the
    file size can be determined, specifically if the file random access.  For
    input from a stream which does not allow random access (for instance a file
    stream from a pipe), the file size cannot be determined for those files
    without that information in the file header.
                        no. samples
      file type          in header
       AU                  yes
       RIFF WAVE           yes
       AIFF or AIFF-C      yes
       NIST SPHERE         yes
       IRCAM               no
       ESPS                yes
       SPPACK              yes
       INRS-Telecom        no
       Comdisco SPW        no
       Text file           no
       Headerless          no
  Notes:
  - Some AU audio files and some ESPS audio files do not specify the number of
    samples.
  - AIFF/AIFF-C files with a perverse header cannot be opened for non-random
    access.

  On encountering an error, the default behaviour is to print an error message
  and halt execution.

Parameters:
  <-  AFILE *AFopenRead
      Audio file pointer for the audio file..  The file name "-" means
      standard input.
   -> const char Fname[]
      Character string specifying the file name
  <-  long int *Nsamp
      Total number of samples in the file (all channels)
  <-  long int *Nchan
      Number of channels
  <-  float *Sfreq
      Sampling frequency
   -> FILE *fpinfo
      File pointer for printing audio file information.  If fpinfo is not NULL,
      information about the audio file is printed on the stream selected by
      fpinfo.

Author / revision:
  P. Kabal  Copyright (C) 1998
  $Revision: 1.69 $  $Date: 1998/06/18 12:55:46 $

-------------------------------------------------------------------------*/

static char rcsid[] = "$Id: AFopenRead.c 1.69 1998/06/18 libtsp-v3r0 $";

#include <string.h>

#include <libtsp.h>
#include <libtsp/nucleus.h>
#include <libtsp/AFheader.h>
#include <libtsp/Xstdio.h>
#include <libtsp/Xstdlib.h>	/* EXIT_FAILURE */
#include <libtsp/AFmsg.h>
#include <libtsp/AFpar.h>

static void
AF_error p_((const char Fname[], int sysFlag));

/* If AFopts_ErrorHalt is clear, execution continues after an error */


AFILE *
AFopenRead (Fname, Nsamp, Nchan, Sfreq, fpinfo)

     const char Fname[];
     long int *Nsamp;
     long int *Nchan;
     float *Sfreq;
     FILE *fpinfo;

{
  FILE *fp;
  AFILE *AFp;
  int Ftype;

/* Open the file for reading */
  if (strcmp (Fname, "-") == 0)
    fp = stdin;
  else
    fp = fopen (Fname, "rb");	/* binary mode */
  if (fp == NULL) {
    AF_error (Fname, 1);
    return NULL;
  }

/* Check whether the file must be random access */
  if (AFopt_RAccess != 0 && ! FLseekable (fp)) {
    UTwarn ("AFopenRead: %s", AFM_RRAccess);
    fclose (fp);
    AF_error (Fname, 0);
    return NULL;
  }

/* Identify the file type */
  Ftype = AFfindType (fp);

/* Read and print the header information */
  switch (Ftype) {
  case FT_NH:
    AFp = AFsetNHread (fp, Fname);
    break;
  case FT_AU:
    AFp = AFrdAUhead (fp);
    break;
  case FT_WAVE:
    AFp = AFrdWVhead (fp);
    break;
  case FT_AIFF:
  case FT_AIFF_C:
    AFp = AFrdAIhead (fp);
    break;
  case FT_SPHERE:
    AFp = AFrdSPhead (fp);
    break;
  case FT_SF:
    AFp = AFrdSFhead (fp);
    break;
  case FT_ESPS:
    AFp = AFrdEShead (fp);
    break;
  case FT_SPPACK:
    AFp = AFrdBLhead (fp);
    break;
  case FT_INRS:
    AFp = AFrdINhead (fp);
    break;
  case FT_SPW:
    AFp = AFrdSWhead (fp);
    break;
  case FT_TXAUD:
    AFp = AFrdTAhead (fp);
    break;
  default:
    AFp = NULL;	/* Error or unknown / unsupported file type */
    break;
  }

/* Error messages */
  if (AFp == NULL) {
    fclose (fp);
    AF_error (Fname, 0);
    return NULL;
  }

/* Print the header information */
  AFprAFpar (AFp, Fname, fpinfo);

/* Return the file parameters */
  *Nsamp = AFp->Nsamp;
  *Nchan = AFp->Nchan;
  *Sfreq = AFp->Sfreq;

  return AFp;
}

/* Print an error message with the file name */


static void
AF_error (Fname, sysFlag)

     const char Fname[];
     int sysFlag;

{
  const char *fn;

  if (strcmp (Fname, "-") == 0)
    fn = "<stdin>";
  else
    fn = Fname;

  if (sysFlag)
    UTsysMsg ("AFopenRead: %s \"%s\"", AFM_OpenRErr, fn);
  else
    UTwarn ("AFopenRead: %s \"%s\"", AFM_OpenRErr, fn);

  if (AFopt_ErrorHalt)
    exit (EXIT_FAILURE);

  return;
}
