/*-------------- Telecommunications & Signal Processing Lab --------------- McGill University Routine: AFILE *AFgetSFpar (FILE *fp, const char Fname[], long int *Nsamp, long int *Nchan, float *Sfreq, FILE *fpout) Purpose: Get file format information from an IRCAM soundfile Description: This routine reads the header for an IRCAM soundfile. 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. IRCAM soundfile header: Offset Length Type Contents 0 4 int File identifier 4 4 float Sampling frequency 8 4 int Number of interleaved channels 12 4 int Data type 16 ... -- Additional header information 1024 ... -- Audio data 8-bit mu-law, 8-bit A-law, 16-bit integer, and 32-bit floating-point data formats are supported. Parameters: <- AFILE *AFgetSFpar 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.36 $ $Date: 1996/08/14 17:57:30 $ -------------------------------------------------------------------------*/ static char rcsid [] = "$Id: AFgetSFpar.c 1.36 1996/08/14 AFsp-V2R1 $"; #include #include #include #include #include #include #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 1024 #define LHMIN ((int) sizeof (struct SF_head)) /* Magic in file byte order */ #define FM_SF_VAX_L "\144\243\001\0" /* vax native */ #define FM_SF_VAX_B "\0\001\243\144" /* vax - byte reversed */ #define FM_SF_SUN "\144\243\002\0" /* big-endian */ #define FM_SF_MIPS_L "\144\243\003\0" /* big-endian */ #define FM_SF_MIPS_B "\0\003\243\144" /* little-endian */ #define FM_SF_NEXT "\144\243\004\0" /* big-endian */ #define SF_CHAR 0x00001 #define SF_ALAW 0x10001 #define SF_ULAW 0x20001 #define SF_SHORT 0x00002 #define SF_LONG 0x40004 #define SF_FLOAT 0x00004 struct SF_head { char Magic[4]; /* File magic */ float4_t sf_srate; /* Sampling frequency */ uint4_t sf_chans; /* Number of channels */ uint4_t sf_packmode; /* Encoding type */ }; AFILE * AFgetSFpar (fp, Fname, Nsamp, Nchan, Sfreq, fpout) FILE *fp; const char Fname[]; long int *Nsamp; long int *Nchan; float *Sfreq; FILE *fpout; { struct SF_head Fhead; AFILE *AFp; long int offs, Nbytes, Nsampx, Ldata; int fileIEEE, Fbo, Lw, Format; float Sfreqx; /* Get the size of the file */ Nbytes = FLfileSize (fp); if (Nbytes < LHEAD) UThalt ("AFgetSFpar: File header too short"); /* Check the file magic */ offs = 0L; offs += RHEAD_S (fp, offs, Fhead.Magic); fileIEEE = 1; if (SAME_CSTR (Fhead.Magic, FM_SF_VAX_L)) { fileIEEE = 0; Fbo = DS_EL; } else if (SAME_CSTR (Fhead.Magic, FM_SF_MIPS_L)) Fbo = DS_EL; else if (SAME_CSTR (Fhead.Magic, FM_SF_VAX_B) || SAME_CSTR (Fhead.Magic, FM_SF_SUN) || SAME_CSTR (Fhead.Magic, FM_SF_MIPS_B) || SAME_CSTR (Fhead.Magic, FM_SF_NEXT)) Fbo = DS_EB; else UThalt ("AFgetSFpar: Invalid file identifier"); /* Notes: - IRCAM files can be written by a number of different hosts. The data is normally written out in native format (byte order and float format). - Early IRCAM software ran on VAX computers (little-endian) with float data (sampling frequency) in VAX float format. - Subsequent IRCAM software ran on Sun computers (big-endian). The file data including the header values is byte-swapped with respect to the native VAX format. The float format is IEEE. - The file magic for the VAX files is "\144\243\001\0". The file magic for the corresponding Sun files is the byte reverse of this. - The MIT csound, the Princeton cmix and earlier sox systems support files as described above. - Subsequently, the magic in IRCAM files has been updated to indicate the host type used to create the file. In file byte order the magic values and the corresponding host type are: "\144\243\001\0" vax little-endian "\144\243\002\0" sun big-endian "\144\243\003\0" mips little-endian "\144\243\004\0" next big-endian - The new sox utility sets the machine to mips if the symbol mips is defined. However, the symbol is defined for DEC-mips as well as SGI-mips machines which have different byte orders. This means that sox will write the file magic as: "\144\243\003\0" little-endian mips "\0\003\243\144" big-endian mips - There are some incompatibilities between the IRCAM data format codes and those used by csound. For csound SF_ULAW = 0x00001 while for IRCAM, SF_ULAW = 0x200001. Here we use the latter. For this implementation we accept IRCAM files as shown in the table below. magic value machine code byte-order float-type "\144\243\001\0" vax big-endian vax ? "\0\001\243\144" vax little-endian IEEE "\144\243\002\0" sun big-endian IEEE "\144\243\003\0" mips big-endian IEEE "\0\003\243\144" mips little-endian IEEE "\144\243\004\0" next big-endian IEEE */ /* Read the file parameters */ offs += RHEAD_V (fp, offs, Fhead.sf_srate, Fbo); offs += RHEAD_V (fp, offs, Fhead.sf_chans, Fbo); RHEAD_V (fp, offs, Fhead.sf_packmode, Fbo); /* Set up the decoding parameters */ switch (Fhead.sf_packmode) { case SF_ULAW: Lw = FDL_MULAW8; Format = FD_MULAW8; break; case SF_ALAW: Lw = FDL_ALAW8; Format = FD_ALAW8; break; case SF_SHORT: Lw = FDL_INT16; Format = FD_INT16; break; case SF_FLOAT: Lw = FDL_FLOAT32; Format = FD_FLOAT32; break; default: UThalt ("AFgetSFpar: Unsupported IRCAM soundfile data format"); break; } Sfreqx = Fhead.sf_srate; Ldata = Nbytes - LHEAD; /* Data size is implicit */ /* Error checks */ if (fileIEEE && ! UTcheckIEEE ()) UThalt ("AFgetSFpar: Host does not use IEEE float format"); if (fileIEEE != UTcheckIEEE ()) UTwarn ("AFgetSFpar - Host and file floating-point formats may differ"); /* Set the parameters for file access */ Nsampx = Ldata / Lw; AFp = AFsetAFp (fp, FO_RO, FT_SF, Format, Fbo, 1.0, (long int) Fhead.sf_chans, (long int) LHEAD, Ldata, Nsampx); /* Check and print the header information */ AFprintAFh (AFp, Fname, "", Sfreqx, fpout); /* Set the return parameters */ *Nsamp = Nsampx; *Nchan = Fhead.sf_chans; *Sfreq = Sfreqx; return AFp; }