/*-------------- Telecommunications & Signal Processing Lab --------------- McGill University Routine: AFILE *AFgetINpar (FILE *fp, const char Fname[], long int *Nsamp, long int *Nchan, float *Sfreq, FILE *fpout) Purpose: Get file format information from an INRS-Telecommunications audio file. Description: This routine reads the header for an INRS-Telecommunications audio file. 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. INRS-Telecommunications audio file: Offset Length Type Contents 0 4 float Sampling Frequency (VAX float format) 6 20 char Creation time (e.g. " 8-DEC-1982 16:52:50") 26 4 int Number of speech samples in the file 512 ... -- Audio data The number of speech samples is checked against the total extent of the file. If unspecified, the file size is used to determine the number of samples. The data in an INRS-Telecommunications audio file are in 16-bit integer format. Parameters: <- AFILE *AFgetINpar 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.40 $ $Date: 1996/08/19 13:37:55 $ -------------------------------------------------------------------------*/ static char rcsid [] = "$Id: AFgetINpar.c 1.40 1996/08/19 AFsp-V2R1 $"; #include #include #include #include #include #include #define ICEILV(n, m) (((n) + ((m) - 1)) / (m)) /* int n,m >= 0 */ #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) #define LHEAD 512 #define LW FDL_INT16 #define IN_NOSIZE (~((uint4_t) 0)) /* Unspecified data length */ /* Common sampling frequencies (VAX floating-point values) in file byte order. The sampling frequencies recognized are 6500, 20000/3, 8000, 10000, 12000, 16000, and 20000 Hz. */ #define NINRS 7 static const char *FM_INRS[NINRS] = { "\313\106\0\040", "\320\106\125\125", "\372\106\0\0", "\034\107\0\100", "\073\107\0\200", "\172\107\0\0", "\234\107\0\100" }; static const float VSfreq[NINRS] = { 6500., 20000./3., 8000., 10000., 12000., 16000., 20000. }; #define NDT 20 struct IN_head { char Sfreq[4]; /* Sampling freq (VAX float) */ /* int2_t fill; */ char Datetime[NDT]; /* Date/time string */ uint4_t Nsamp; /* No. samples */ }; AFILE * AFgetINpar (fp, Fname, Nsamp, Nchan, Sfreq, fpout) FILE *fp; const char Fname[]; long int *Nsamp; long int *Nchan; float *Sfreq; FILE *fpout; { struct IN_head Fhead; AFILE *AFp; long int Nbytes, Nsampx, Ldata; int iSF; char *p; char Datetime[NDT+1]; /* Get the size of the file */ Nbytes = FLfileSize (fp); if (Nbytes < LHEAD) UThalt ("AFgetINpar: INRS file header too short"); /* Read in portions of the header */ RHEAD_S (fp, 0L, Fhead.Sfreq); RHEAD_S (fp, 6L, Fhead.Datetime); RHEAD_V (fp, 26L, Fhead.Nsamp, DS_EL); /* Use the sampling frequency as a file magic value */ for (iSF = 0; iSF < NINRS; iSF++) { if (SAME_CSTR (Fhead.Sfreq, FM_INRS[iSF])) break; } if (iSF >= NINRS) UThalt ("AFgetINpar: Invalid INRS file identifier"); /* Notes: - Very old INRS-Telecom audio files (generated on a PDP-11) have ~0 values for unwritten bytes in the header. - Old INRS-Telecom audio file used the Fhead.Nsamp field. These files were an integral number of disk blocks long (512 bytes per disk block), with possibly part of the last block being unused. - Old INRS-Telecom audio files (generated on a PDP-11) have only an 18 byte date and time, followed by two 0 or two ~0 bytes. */ Datetime[NDT]='\0'; strncpy (Datetime, Fhead.Datetime, NDT); p = strchr (Datetime, '\377'); if (p != NULL) *p = '\0'; /* Check the file length */ Ldata = Nbytes - LHEAD; if (Fhead.Nsamp == 0 || Fhead.Nsamp == IN_NOSIZE) Fhead.Nsamp = (uint4_t) (Ldata / LW); else { if (ICEILV (Ldata, 512) != ICEILV (LW * Fhead.Nsamp, 512)) UThalt ("AFgetINpar: Header specifies an invalid number of samples"); Ldata = LW * Fhead.Nsamp; } /* Set the parameters for file access */ Nsampx = Fhead.Nsamp; AFp = AFsetAFp (fp, FO_RO, FT_INRS, FD_INT16, DS_EL, 1.0, 1L, (long int) LHEAD, Ldata, Nsampx); /* Check and print the header information */ AFprintAFh (AFp, Fname, Datetime, (double) VSfreq[iSF], fpout); /* Set the return parameters */ *Nsamp = Nsampx; *Nchan = 1L; *Sfreq = VSfreq[iSF]; return AFp; }