/*-------------- Telecommunications & Signal Processing Lab --------------- McGill University Routine: AFILE *AFgetAUpar (FILE *fp, const char Fname[], long int *Nsamp, long int *Nchan, float *Sfreq, FILE *fpout) Purpose: Get file format information from an AFsp or Sun audio file Description: This routine reads the header for an AFsp or Sun format audio file. The AFsp audio file format uses a file header which is compatible with a Sun audio file header. The header information is used to set the file data format information in the audio file pointer structure and to set the returned argument values. A banner identifying the audio file and its parameters is printed. AFsp (Sun) 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, and 32-bit IEEE floating-point data formats are supported. Parameters: <- AFILE *AFgetAUpar Audio file pointer for the audio file -> FILE *fp File pointer for the file -> const char Fname[] File name <- long int *Nsamp Total number of samples in the file (all channels) <- long int *Nchan Number of channels <- float *Sfreq Sampling frequency from the file header -> FILE *fpout File pointer for printing the audio file identification information. If fpout is NULL, no information is printed. Author / revision: P. Kabal Copyright (C) 1996 $Revision: 1.51 $ $Date: 1996/08/15 16:03:32 $ -------------------------------------------------------------------------*/ static char rcsid [] = "$Id: AFgetAUpar.c 1.51 1996/08/15 AFsp-V2R1 $"; #include #include #include #include #include #include #define ABSV(x) (((x) < 0) ? -(x) : (x)) #define RHEAD_S(fp,offs,string) \ AFreadHead (fp, (long int) (offs), (void *) (string), \ 1, sizeof (string), DS_NATIVE) #define RHEAD_V(fp,offs,value,swap) \ AFreadHead (fp, (long int) (offs), (void *) &(value), \ sizeof (value), 1, swap) #define SAME_CSTR(str,ref) (memcmp (str, ref, sizeof (str)) == 0) AFILE * AFgetAUpar (fp, Fname, Nsamp, Nchan, Sfreq, fpout) FILE *fp; const char Fname[]; long int *Nsamp; long int *Nchan; float *Sfreq; FILE *fpout; { struct AU_head Fhead; AFILE *AFp; long int Nbytes, Nsampx, offs; int Ftype, Lw, Format, Ninfo; float ScaleF, Sfreqx, Fv; char *Hinfo, *Datetime, *Csf; /* Get the size of the file */ Nbytes = FLfileSize (fp); if (Nbytes < AU_LHMIN) UThalt ("AFgetAUpar: Audio file header too short"); /* Check the file magic */ offs = 0L; offs += RHEAD_S (fp, offs, Fhead.Magic); if (! SAME_CSTR (Fhead.Magic, FM_SUN)) UThalt ("AFgetAUpar: Invalid audio file identifier"); Ftype = FT_SUN; /* Read the data parameters */ offs += RHEAD_V (fp, offs, Fhead.Lhead, DS_EB); offs += RHEAD_V (fp, offs, Fhead.Ldata, DS_EB); offs += RHEAD_V (fp, offs, Fhead.Dencod, DS_EB); offs += RHEAD_V (fp, offs, Fhead.Srate, DS_EB); offs += RHEAD_V (fp, offs, Fhead.Nchan, DS_EB); /* Check for an AFsp header */ if (Fhead.Lhead >= AFsp_LHMIN) { RHEAD_S (fp, offs, Fhead.AFspID); if (SAME_CSTR (Fhead.AFspID, FM_AFSP)) Ftype = FT_AFSP; } /* Set up the decoding parameters */ switch (Fhead.Dencod) { case AU_MULAW8: Lw = FDL_MULAW8; Format = FD_MULAW8; ScaleF = 1.; break; case AU_ALAW8: Lw = FDL_ALAW8; Format = FD_ALAW8; ScaleF = 1.; break; case AU_LIN8: Lw = FDL_INT8; Format = FD_INT8; ScaleF = 128.; break; case AU_LIN16: Lw = FDL_INT16; Format = FD_INT16; ScaleF = 1.; break; case AU_FLOAT32: if (! UTcheckIEEE ()) UThalt ("AFgetAUpar: Host does not use IEEE float format"); Lw = FDL_FLOAT32; Format = FD_FLOAT32; ScaleF = 32768.; break; default: UThalt ("AFgetAUpar: Unsupported audio file data encoding"); break; } /* Warnings, error checks */ if (Fhead.Lhead < AU_LHMIN || Fhead.Lhead > Nbytes) UThalt ("AFgetAUpar: Invalid audio file header length"); if (Fhead.Ldata == AU_NOSIZE) Fhead.Ldata = (uint4_t) (Nbytes - Fhead.Lhead); if (Fhead.Ldata > Nbytes - Fhead.Lhead) { UTwarn ("AFgetAUpar - Fixup for invalid header data length field"); Fhead.Ldata = (uint4_t) (Nbytes - Fhead.Lhead); } /* Set the parameters for file access */ Nsampx = Fhead.Ldata / Lw; AFp = AFsetAFp (fp, FO_RO, Ftype, Format, DS_EB, ScaleF, (long int) Fhead.Nchan, (long int) Fhead.Lhead, (long int) Fhead.Ldata, Nsampx); /* Scan the AFsp header for "sample_rate:" and "date:" records */ Sfreqx = Fhead.Srate; Datetime = ""; if (Ftype == FT_AFSP) { Hinfo = AFreadHinfo (AFp, &Ninfo); Csf = AFgetAUrec ("sample_rate:", Hinfo, Ninfo); if (Csf != NULL) { if (STdec1float (Csf, &Fv)) UTwarn ("AFgetAUpar - Invalid AFsp sample_rate record"); else if (ABSV(Fv - Sfreqx) <= 0.5) Sfreqx = Fv; else UTwarn ("AFgetAUpar - AFsp sample rate mismatch, %g : %g", Sfreqx, Fv); } Datetime = AFgetAUrec ("date:", Hinfo, Ninfo); } /* Check and print the header information */ AFprintAFh (AFp, Fname, Datetime, Sfreqx, fpout); /* Set the return parameters */ *Nsamp = Nsampx; *Nchan = Fhead.Nchan; *Sfreq = Sfreqx; return AFp; }