/*-------------- Telecommunications & Signal Processing Lab --------------- McGill University Routine: AFILE *AFsetAIpar (const char Fname[], int Format, long int Nchan, double Sfreq, FILE *fpout) Purpose: Write header information to a AIFF-C file Description: This routine writes header information to a AIFF-C format audio file. The file is assumed to have been opened with routine AFopenWrite. Optionally, the file header information is printed. AIFF-C audio file: Offset Length Type Contents 0 4 char File identifier ("FORM") 4 4 int Form chunk length 8 4 char File identifier ("AIFF" or "AIFC") 12 4 char COMM chunk identifier ("COMM") 16 4 int COMM chunk length 24 2 int Number of interleaved channels 26 4 int Number of sample frames 30 2 int Bits per sample 32 10 float Sample frames per second 42 4 int Compression type 46 ... char Compression name ... ... ... ... d 4 char SSND chunk identifier ("SSND") d+4 4 int SSND chunk length d+8 4 int Data offset (0) d+12 4 int Block size (0) d+16 ... ... Audio data 8-bit mu-law, 8-bit A-law, 8-bit integer, and 16-bit integer data formats are supported. Parameters: <- AFILE AFsetAIpar Audio file pointer for the audio file -> const char Fname[] File name -> int Format Audio file data format code, FD_MULAW8 = 1, mu-law 8-bit data FD_ALAW8 = 2, A-law 8-bit data FD_INT8 = 4, two's-complement 8-bit integer data FD_INT16 = 5, two's-complement 16-bit integer data -> long int Nchan Number of channels -> double Sfreq Sampling frequency -> FILE *fpout File pointer for printing audio file information. If fpout is not NULL, information about the audio file is printed on the stream selected by fpout. Author / revision: P. Kabal Copyright (C) 1996 $Revision: 1.6 $ $Date: 1996/08/14 18:05:35 $ -------------------------------------------------------------------------*/ static char rcsid [] = "$Id: AFsetAIpar.c 1.6 1996/08/14 AFsp-V2R1 $"; #include #include #include #include #include #include #define WHEAD_S(fp,offs,string) \ AFwriteHead (fp, (long int) (offs), \ (void *) (string), \ 1, sizeof (string), DS_NATIVE) #define WHEAD_P(fp,offs,string) \ AFwriteHead (fp, (long int) (offs), \ (void *) (string), \ 1, strlen (string), DS_NATIVE) #define WHEAD_V(fp,offs,value,swap) \ AFwriteHead (fp, (long int) (offs), \ (void *) &(value), \ sizeof (value), 1, swap) #define MCOPY(src,dest) memcpy ((void *) (dest), (void *) (src), \ sizeof (dest)) #define ICEILV(n, m) (((n) + ((m) - 1)) / (m)) /* int n,m >= 0 */ #define RUP(value) (2 * ICEILV (value, 2)) /* Round up */ AFILE * AFsetAIpar (Fname, Format, Nchan, Sfreq, fpout) const char Fname[]; int Format; long int Nchan; double Sfreq; FILE *fpout; { FILE *fp; AFILE *AFp; long int offs; double ScaleF; struct { struct AI_CkPreamb FORM_p; char AIFFid[4]; struct AI_CkPreamb COMM_p; struct AI_CkCOMM COMM; struct AI_CkPreamb FVER_p; struct AI_CkFVER FVER; struct AI_CkPreamb SSND_p; struct AI_CkSSND SSND; } Fhead; static const uint1_t Pad = 0; /* Set up the encoding parameters */ switch (Format) { case FD_INT16: MCOPY (CT_NONE, Fhead.COMM.compressionType); strcpy (Fhead.COMM.compressionName, CN_NONE); Fhead.COMM.sampleSize = 8 * FDL_INT16; ScaleF = 1.; break; case FD_INT8: MCOPY (CT_NONE, Fhead.COMM.compressionType); strcpy (Fhead.COMM.compressionName, CN_NONE); Fhead.COMM.sampleSize = 8 * FDL_INT8; ScaleF = 1./128.; break; case FD_MULAW8: MCOPY (CT_ULAW, Fhead.COMM.compressionType); strcpy (Fhead.COMM.compressionName, CN_ULAW); Fhead.COMM.sampleSize = 16; /* Uncompressed data size in bits */ ScaleF = 1.; break; case FD_ALAW8: MCOPY (CT_ALAW, Fhead.COMM.compressionType); strcpy (Fhead.COMM.compressionName, CN_ALAW); Fhead.COMM.sampleSize = 16; /* Uncompressed data size in bits */ ScaleF = 1.; break; default: UThalt ("AFsetAIpar: Unsupported data encoding"); break; } /* Set up the fixed header parameters */ MCOPY (FM_IFF, Fhead.FORM_p.ckID); /* Defer setting ckDataSize */ MCOPY (FM_AIFF_C, Fhead.AIFFid); MCOPY (CKID_COMM, Fhead.COMM_p.ckID); Fhead.COMM_p.ckDataSize = 22 + strlen (Fhead.COMM.compressionName); Fhead.COMM.numChannels = (uint2_t) Nchan; Fhead.COMM.numSampleFrames = 0; UTeIEEE80 (Sfreq, Fhead.COMM.sampleRate); /* Fhead.COMM.compressionType filled in above */ /* Fhead.COMM.compressionName filled in above */ /* Fhead.COMM.sampleSize filled in above */ MCOPY (CKID_FVER, Fhead.FVER_p.ckID); Fhead.FVER_p.ckDataSize = 4; Fhead.FVER.timestamp = AIFCVersion1; MCOPY (CKID_SSND, Fhead.SSND_p.ckID); Fhead.SSND_p.ckDataSize = 8; Fhead.SSND.offset = 0; Fhead.SSND.blockSize = 0; /* Fill in the FORM chunk size */ Fhead.FORM_p.ckDataSize = (uint4_t) (4 + 8 + RUP(Fhead.COMM_p.ckDataSize) + 8 + RUP(Fhead.FVER_p.ckDataSize) + 8 + RUP(Fhead.SSND_p.ckDataSize)); /* Open the file for writing */ fp = fopen (Fname, "wb"); if (fp == NULL) UTerror ("AFsetAIpar: Cannot open file \"%s\"", Fname); /* Write out the header */ offs = 0L; offs += WHEAD_S (fp, offs, Fhead.FORM_p.ckID); offs += WHEAD_V (fp, offs, Fhead.FORM_p.ckDataSize, DS_EB); offs += WHEAD_S (fp, offs, Fhead.AIFFid); offs += WHEAD_S (fp, offs, Fhead.COMM_p.ckID); offs += WHEAD_V (fp, offs, Fhead.COMM_p.ckDataSize, DS_EB); offs += WHEAD_V (fp, offs, Fhead.COMM.numChannels, DS_EB); offs += WHEAD_V (fp, offs, Fhead.COMM.numSampleFrames, DS_EB); offs += WHEAD_V (fp, offs, Fhead.COMM.sampleSize, DS_EB); offs += WHEAD_S (fp, offs, Fhead.COMM.sampleRate); offs += WHEAD_S (fp, offs, Fhead.COMM.compressionType); offs += WHEAD_P (fp, offs, Fhead.COMM.compressionName); if (offs % 2 != 0) offs += WHEAD_V (fp, offs, Pad, DS_EB); /* Pad byte */ offs += WHEAD_S (fp, offs, Fhead.FVER_p.ckID); offs += WHEAD_V (fp, offs, Fhead.FVER_p.ckDataSize, DS_EB); offs += WHEAD_V (fp, offs, Fhead.FVER.timestamp, DS_EB); offs += WHEAD_S (fp, offs, Fhead.SSND_p.ckID); offs += WHEAD_V (fp, offs, Fhead.SSND_p.ckDataSize, DS_EB); offs += WHEAD_V (fp, offs, Fhead.SSND.offset, DS_EB); offs += WHEAD_V (fp, offs, Fhead.SSND.blockSize, DS_EB); /* Set the parameters for file access */ AFp = AFsetAFp (fp, FO_WO, FT_AIFF_C, Format, DS_EB, ScaleF, Nchan, offs, 0L, 0L); /* Print the header information */ AFprintAFh (AFp, Fname, "", Sfreq, fpout); return AFp; }