/*-------------- Telecommunications & Signal Processing Lab --------------- McGill University Routine: AFILE *AFgetSPpar (FILE *fp, const char Fname[], long int *Nsamp, long int *Nchan, float *Sfreq, FILE *fpout) Purpose: Get file format information from a NIST SPHERE audio file Description: This routine reads the header for a NIST SPHERE 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. NIST SPHERE audio file header: Offset Length Type Contents 0 8 char File identifier ("NIST_1A\n") 8 8 char Header length in ASCII (" 1024\n") 16 ... struct Object-oriented fields 1024 ... -- Audio data 8-bit mu-law and 16-bit integer data formats are supported. Parameters: <- AFILE *AFgetSPpar 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.41 $ $Date: 1996/08/14 18:21:35 $ -------------------------------------------------------------------------*/ static char rcsid [] = "$Id: AFgetSPpar.c 1.41 1996/08/14 AFsp-V2R1 $"; #include #include #include #include #include #define RHEAD_S(fp,offs,string) \ AFreadHead (fp, (long int) (offs), (void *) (string), \ 1, sizeof (string), DS_NATIVE) #define SAME_CSTR(str,ref) (memcmp (str, ref, sizeof (str)) == 0) #define GET_REC(field,type,vp,errcont) \ AFgetSPrec (field, type, (void *) vp, errcont, Fhead.rec, SP_LR) #define GOT_REC(field,type,vp,errcont) \ (AFgetSPrec (field, type, (void *) vp, errcont, Fhead.rec, SP_LR) == 0) #define LHEAD 1024 /* NIST SPHERE file identifier as a character string */ #define SP_ident "\116\111\123\124\137\061\101\012" /* "NIST_1A\n" */ #define SP_hsize "\040\040\040\061\060\062\064\012" /* " 1024\n" */ #define SP_LI ((sizeof (SP_ident)) - 1) #define SP_LH ((sizeof (SP_hsize)) - 1) #define SP_LR (LHEAD - SP_LI - SP_LH) #define T_INTEGER 0 #define T_REAL 1 #define T_STRING 2 #define MAXSTRING 80 #define ERR_NOMSG 0 #define ERR_MSG 1 #define ERR_STOP 2 #define REQUIRED (ERR_STOP + 4 * ERR_STOP) #define OPTIONAL (ERR_NOMSG + 4 * ERR_STOP) struct SP_head { char ident[SP_LI]; char hsize[SP_LH]; char rec[SP_LR]; }; AFILE * AFgetSPpar (fp, Fname, Nsamp, Nchan, Sfreq, fpout) FILE *fp; const char Fname[]; long int *Nsamp; long int *Nchan; float *Sfreq; FILE *fpout; { struct SP_head Fhead; AFILE *AFp; int Format, Fbo; long int offs, Lw, nbis, Srate, Ldata, Nbytes, Nsampx, Nchanx; char hstring[MAXSTRING+1], Date[MAXSTRING+1]; /* Get the size of the file */ Nbytes = FLfileSize (fp); if (Nbytes < LHEAD) UThalt ("AFgetSPpar: File header too short"); /* Read in the fixed portion of the header */ offs = 0L; offs += RHEAD_S (fp, offs, Fhead.ident); if (! SAME_CSTR (Fhead.ident, SP_ident)) UThalt ("AFgetSPpar: Invalid file identifier"); offs += RHEAD_S (fp, offs, Fhead.hsize); if (! SAME_CSTR (Fhead.hsize, SP_hsize)) UThalt ("AFgetSPpar: Invalid header length specifier"); /* Read the remaining part of the header */ RHEAD_S (fp, offs, Fhead.rec); /* Number of samples, number of channels and word size */ GET_REC ("sample_count", T_INTEGER, &Nsampx, REQUIRED); GET_REC ("channel_count", T_INTEGER, &Nchanx, REQUIRED); GET_REC ("sample_n_bytes",T_INTEGER, &Lw, REQUIRED); /* Data format */ strcpy (hstring, "pcm"); GET_REC ("sample_coding", T_STRING, hstring, OPTIONAL); if (Lw == 2 && strcmp (hstring, "pcm") == 0) { GET_REC ("sample_byte_format", T_STRING, hstring, OPTIONAL); Fbo = DS_NATIVE; if (GOT_REC ("sample_byte_format", T_STRING, hstring, OPTIONAL)) { if (strcmp (hstring, "10")) Fbo = DS_EL; else if (strcmp(hstring, "01")) Fbo = DS_EB; else UThalt ("AFgetSPpar: Unsupported NIST SPHERE byte format"); } nbis = 16; GET_REC ("sample_sig_bits", T_INTEGER, &nbis, OPTIONAL); if (nbis != 16) UThalt ("AFgetSPpar: Unsupported NIST SPHERE data resolution (%ld bits)", nbis); Format = FD_INT16; } else if (Lw == 1 && (strcmp (hstring, "ulaw") == 0 || strcmp (hstring, "mu-law") == 0)) { Fbo = DS_NATIVE; Format = FD_MULAW8; } else UThalt ("AFgetSPpar: Unsupported NIST SPHERE data format"); /* Sampling frequency */ GET_REC ("sample_rate", T_INTEGER, &Srate, REQUIRED); /* Warnings, error checks */ Ldata = Nsampx * Lw; if (Ldata > Nbytes - LHEAD) UThalt ("AFgetSPpar: Invalid data length"); if (Ldata != (Lw * ((Nbytes - LHEAD) / Lw))) UTwarn ("AFgetSPpar - Data length does not match the file length"); if (Nchanx > 1) { hstring[0] = '\0'; GET_REC ("channels_interleaved", T_STRING, hstring, OPTIONAL); if (strcmp (hstring, "TRUE") != 0) UTwarn ("AFgetSPpar - Channels may not be interleaved"); } /* Set the parameters for file access */ AFp = AFsetAFp (fp, FO_RO, FT_SPHERE, Format, Fbo, 1.0, Nchanx, (long int) LHEAD, Ldata, Nsampx); /* Get the date */ Date[0] = '\0'; GET_REC ("recording_date", T_STRING, Date, OPTIONAL); /* Check and print the header information */ AFprintAFh (AFp, Fname, Date, (double) Srate, fpout); /* Set the return parameters */ *Nsamp = Nsampx; *Nchan = Nchanx; *Sfreq = Srate; return AFp; }