1 /*-------------- Telecommunications & Signal Processing Lab ---------------
2 
3 Routine:
4   AFILE *AFrdAIhead (FILE *fp)
5 
6 Purpose:
7   Get file format information from an AIFF or AIFF-C sound file
8 
9 Description:
10   This routine reads the header for an AIFF or AIFF-C sound file.  The header
11   information is used to set the file data format information in the audio
12   file pointer structure.
13 
14   AIFF or AIFF-C sound file:
15    Offset Length Type    Contents
16       0     4    char   "FORM" file identifier
17       4     4    int    Chunk length
18       8     4    char   File identifier ("AIFF" or "AIFC")
19     ...   ...    ...    ...
20       C     4    char   "COMM" chunk identifier ("COMM")
21      +4     4    int    Chunk length
22      +8     2    int      Number of interleaved channels
23     +10     4    int      Number of sample frames
24     +14     2    int      Bits per sample
25     +16    10    float    Sample frames per second
26     +26     4    int      Compression type
27     +30   ...    char     Compression name
28     ...    ...   ...    ...
29       S     4    char   "SSND" chunk identifier
30      +4     4    int    Chunk length
31      +8     4    int      Data offset
32     +12     4    int      Block size
33     +16   ...    ...      Audio data
34 
35 Parameters:
36   <-  AFILE *AFrdAIhead
37       Audio file pointer for the audio file
38    -> FILE *fp
39       File pointer for the file
40 
41 Author / revision:
42   P. Kabal  Copyright (C) 2003
43   $Revision: 1.68 $  $Date: 2003/11/03 18:53:37 $
44 
45 -------------------------------------------------------------------------*/
46 
47 #include <setjmp.h>
48 #include <string.h>
49 
50 #include <libtsp.h>
51 #include <libtsp/nucleus.h>
52 #include <libtsp/AFdataio.h>
53 #include <libtsp/AFheader.h>
54 #include <libtsp/AFmsg.h>
55 #include <libtsp/AFpar.h>
56 #include <libtsp/AIpar.h>
57 
58 #define ICEILV(n,m)	(((n) + ((m) - 1)) / (m))	/* int n,m >= 0 */
59 #define MINV(a, b)	(((a) < (b)) ? (a) : (b))
60 #define RNDUPV(n,m)	((m) * ICEILV (n, m))		/* Round up */
61 
62 #define SAME_CSTR(str,ref) 	(memcmp (str, ref, sizeof (str)) == 0)
63 
64 #define ALIGN		2	/* Chunks padded out to a multiple of ALIGN */
65 
66 /* setjmp / longjmp environment */
67 extern jmp_buf AFR_JMPENV;
68 
69 static int
70 AF_rdFORM_AIFF (FILE *fp, struct AI_CkFORM *CkFORM, int *Ftype);
71 static int
72 AF_rdCOMM (FILE *fp, int Ftype, struct AI_CkCOMM *CkCOMM);
73 static void
74 AF_decCOMM (struct AI_CkCOMM *CkCOMM, struct AF_read *AFr);
75 static int
76 AF_checkFVER (FILE *fp, struct AI_CkFVER *CkFVER);
77 static long int
78 AF_decSSND (FILE *fp, struct AI_CkSSND *CkSSND);
79 static int
80 AF_rPstring (FILE *fp, char string[], int ncMax);
81 
82 AF_READ_DEFAULT(AFr_default);	/* Define the AF_read defaults */
83 
84 
85 AFILE *
AFrdAIhead(FILE * fp)86 AFrdAIhead (FILE *fp)
87 
88 {
89   AFILE *AFp;
90   long int offs, LFORM, Dstart, EoD;
91   int Ftype, AtData;
92   char Info[AF_MAXINFO];
93   struct AF_read AFr;
94   struct AI_CkFORM CkFORM;
95   struct AI_CkPreamb CkHead;
96   struct AI_CkCOMM CkCOMM;
97 
98 /* Set the long jump environment; on error return a NULL */
99   if (setjmp (AFR_JMPENV))
100     return NULL;	/* Return from a header read error */
101 
102 /* Each chunk has an identifier and a length.  The length gives the number of
103    bytes in the chunk (not including the ckID or ckDataSize fields).  If the
104    ckDataSize field is odd, a zero byte fills the space before the start of the
105    next chunk.
106    - Some AIFF-C files do not have this zero byte at the end of the file,
107      i.e. the total file length is odd, yet the FORM chunk size indicates that
108      the padding byte is there.
109    - The chunks after the FORM chunk can appear in any order.
110    - The standard is written in such a way that it is implied that one should
111      scan the whole file for chunks.  Here we are trying to allow for non-
112      seekable input.
113      - If the COMM chunk comes ahead of the SSND chunk all is fine.  We get to
114        the SSND chunk and then skip forward to the data.
115      - If the COMM chunk follows the SSND chunk we will have to seek back to
116        the data in the SSND chunk.  The file has to be seekable.
117      - If the number of samples is zero (in the COMM chunk), there need be no
118        SSND chunk.  When we get to the end-of-file, we will declare this to be
119        the start of data.
120 */
121 
122 /* Defaults and inital values */
123   AFr = AFr_default;
124   AFr.InfoX.Info = Info;
125   AFr.InfoX.Nmax = AF_MAXINFO;
126 
127 /* Check the FORM chunk */
128   if (AF_rdFORM_AIFF (fp, &CkFORM, &Ftype))
129     return NULL;
130   offs = 12L;	/* Positioned after FORM/AIFF preamble */
131   LFORM = CkFORM.ckSize + 8;
132 
133   Dstart = 0L;
134   EoD = 0L;
135   AtData = 0;
136   while (offs < LFORM-8) {	/* Leave 8 bytes for the chunk preamble */
137 
138     /* Read the chunk preamble */
139     offs += RHEAD_S (fp, CkHead.ckID);
140 
141     /* COMM chunk */
142     if (SAME_CSTR (CkHead.ckID, CKID_COMM)) {
143       offs += AF_rdCOMM (fp, Ftype, &CkCOMM);
144       AF_decCOMM (&CkCOMM, &AFr);
145     }
146 
147     /* FVER chunk */
148     else if (Ftype == FT_AIFF_C && SAME_CSTR (CkHead.ckID, CKID_FVER)) {
149       offs += AF_checkFVER (fp, &CkFORM.CkFVER);
150     }
151     /* Text chunks */
152     else if (SAME_CSTR (CkHead.ckID, CKID_NAME)) {
153       offs += RHEAD_V (fp, CkHead.ckSize, DS_EB);
154       offs += AFrdTextAFsp (fp, (int) CkHead.ckSize, "name: ",
155 			    &AFr.InfoX, ALIGN);
156     }
157     else if (SAME_CSTR (CkHead.ckID, CKID_AUTHOR)) {
158       offs += RHEAD_V (fp, CkHead.ckSize, DS_EB);
159       offs += AFrdTextAFsp (fp, (int) CkHead.ckSize, "author: ",
160 			    &AFr.InfoX, ALIGN);
161     }
162     else if (SAME_CSTR (CkHead.ckID, CKID_COPYRIGHT)) {
163       offs += RHEAD_V (fp, CkHead.ckSize, DS_EB);
164       offs += AFrdTextAFsp (fp, (int) CkHead.ckSize, "copyright: ",
165 			    &AFr.InfoX, ALIGN);
166     }
167     /* Annotation chunk */
168     else if (SAME_CSTR (CkHead.ckID, CKID_ANNOTATION)) {
169       offs += RHEAD_V (fp, CkHead.ckSize, DS_EB);
170       offs += AFrdTextAFsp (fp, (int) CkHead.ckSize, "annotation: ",
171 			    &AFr.InfoX, ALIGN);
172     }
173 
174     /* SSND chunk */
175     else if (SAME_CSTR (CkHead.ckID, CKID_SSND)) {
176       offs += AF_decSSND (fp, &CkFORM.CkSSND);
177       AFr.NData.Ldata = CkFORM.CkSSND.ckSize - 8 - CkFORM.CkSSND.offset;
178       offs += RSKIP (fp, CkFORM.CkSSND.offset);
179       Dstart = offs;
180       EoD = RNDUPV (Dstart + AFr.NData.Ldata, ALIGN);
181       if (EoD >= LFORM || ! FLseekable (fp)) {
182 	AtData = 1;
183 	break;
184       }
185       else {
186 	AtData = 0;
187 	offs += RSKIP (fp, EoD - Dstart);
188       }
189     }
190 
191     /* Miscellaneous chunks */
192     else {
193       offs += RHEAD_V (fp, CkHead.ckSize, DS_EB);
194       offs += RSKIP (fp, RNDUPV (CkHead.ckSize, ALIGN));
195     }
196 
197   }
198 
199   /* Error Checks */
200   if (AFr.DFormat.Format == FD_UNDEF) {
201     UTwarn ("AFrdAIhead - %s", AFM_AIFF_BadHead);
202     return NULL;
203   }
204   if ((! AtData && offs != LFORM) || (AtData && EoD != LFORM))
205     UTwarn ("AFrdAIhead - %s", AFM_AIFF_BadSize);
206 
207   /* If no SSND chunk has been found, check for a zero data size (does not
208      need a SSND chunk)
209   */
210   if (Dstart == 0L) {
211     if (CkCOMM.numSampleFrames == 0) {
212       AFr.NData.Ldata = 0L;
213       AtData = 1;
214       Dstart = offs;
215     }
216     else {
217       UTwarn ("AFrdAIhead - %s", AFM_AIFF_NoSSND);
218       return NULL;
219     }
220   }
221 
222   /* Position at the start of data */
223   if (! AtData) {
224     if (AFseek (fp, Dstart, NULL))
225       return NULL;
226   }
227 
228 /* Set the parameters for file access */
229   AFp = AFsetRead (fp, Ftype, &AFr, AF_FIX_NSAMP_HIGH + AF_FIX_LDATA_HIGH);
230 
231   return AFp;
232 }
233 
234 /* Check the RIFF/AIFF file preamble */
235 
236 
237 static int
AF_rdFORM_AIFF(FILE * fp,struct AI_CkFORM * CkFORM,int * Ftype)238 AF_rdFORM_AIFF (FILE *fp, struct AI_CkFORM *CkFORM, int *Ftype)
239 
240 {
241   long int Lfile, LFORM;
242 
243   RHEAD_S (fp, CkFORM->ckID);
244   if (! SAME_CSTR (CkFORM->ckID, FM_IFF)) {
245     UTwarn ("AFrdAIhead - %s", AFM_AIFF_BadId);
246     return 1;
247   }
248 
249   RHEAD_V (fp, CkFORM->ckSize, DS_EB);
250   LFORM = CkFORM->ckSize + 8;
251 
252   if (FLseekable (fp)) {
253     Lfile = FLfileSize (fp);
254     if (LFORM > Lfile) {
255       CkFORM->ckSize = Lfile - 8;
256       UTwarn ("AFrdAIhead - %s", AFM_AIFF_FixFORM);
257     }
258   }
259 
260   RHEAD_S (fp, CkFORM->ckID);
261   if (SAME_CSTR (CkFORM->ckID, FM_AIFF_C))
262     *Ftype = FT_AIFF_C;
263   else if (SAME_CSTR (CkFORM->ckID, FM_AIFF))
264     *Ftype = FT_AIFF;
265   else {
266     UTwarn ("AFrdAIhead - %s", AFM_AIFF_BadId);
267     return 1;
268   }
269 
270   return 0;
271 }
272 
273 /* Read the COMM chunk */
274 
275 
276 static int
AF_rdCOMM(FILE * fp,int Ftype,struct AI_CkCOMM * CkCOMM)277 AF_rdCOMM (FILE *fp, int Ftype, struct AI_CkCOMM *CkCOMM)
278 
279 {
280   int offs;
281 
282   offs  = RHEAD_V (fp, CkCOMM->ckSize, DS_EB);
283   offs += RHEAD_V (fp, CkCOMM->numChannels, DS_EB);
284   offs += RHEAD_V (fp, CkCOMM->numSampleFrames, DS_EB);
285   offs += RHEAD_V (fp, CkCOMM->sampleSize, DS_EB);
286   offs += RHEAD_S (fp, CkCOMM->sampleRate);
287 
288   /* Set the compressionType field for both AIFF and AIFF-C files */
289   if (Ftype == FT_AIFF_C) {
290     offs += RHEAD_S (fp, CkCOMM->compressionType);
291     offs += AF_rPstring (fp, CkCOMM->compressionName, CNAME_MAX);
292   }
293   else {
294     memcpy (CkCOMM->compressionType, CT_NONE, sizeof (CT_NONE));
295     CkCOMM->compressionName[0] = '\0';
296   }
297 
298   /* Some AIFF-C COMM chunks are declared to be of length 18 (the size for
299      AIFF files) when they are in fact larger.  Here we find the actual
300      length of the COMM chunk.
301   */
302   if (offs - 4 > (int) CkCOMM->ckSize) {
303     UTwarn ("AFrdAIhead - %s", AFM_AIFF_FixCOMM);
304     CkCOMM->ckSize = offs - 4;
305   }
306   offs += RSKIP (fp, RNDUPV (CkCOMM->ckSize, ALIGN) - (offs-4));
307 
308   return offs;
309 }
310 
311 /* Read a P-string */
312 
313 
314 static int
AF_rPstring(FILE * fp,char string[],int ncMax)315 AF_rPstring (FILE *fp, char string[], int ncMax)
316 
317 {
318   int offs, nc, ncP, nr;
319   char slen[1];
320 
321   offs = RHEAD_S (fp, slen);	/* 1 byte length */
322 
323   nc = (int) slen[0];
324   ncP = RNDUPV (nc + 1, 2);
325   nr = MINV (nc, ncMax);
326 
327   offs += RHEAD_SN (fp, string, nr);
328   string[nr] = '\0';
329   offs += RSKIP (fp, ncP - (nc + 1));
330 
331   return offs;
332 }
333 
334 /* Decode the data format: On error return via longjmp */
335 
336 
337 static void
AF_decCOMM(struct AI_CkCOMM * CkCOMM,struct AF_read * AFr)338 AF_decCOMM (struct AI_CkCOMM *CkCOMM, struct AF_read *AFr)
339 
340 {
341   int NBytesS;
342 
343   /* Uncompressed */
344   if (SAME_CSTR (CkCOMM->compressionType, CT_NONE)) {
345 
346     NBytesS = ICEILV (CkCOMM->sampleSize, 8);
347     AFr->DFormat.NbS = (int) CkCOMM->sampleSize;
348     if (NBytesS == 1)
349       AFr->DFormat.Format = FD_INT8;
350     else if (NBytesS == 2)
351       AFr->DFormat.Format = FD_INT16;
352     else if (NBytesS == 3)
353       AFr->DFormat.Format = FD_INT24;
354     else if (NBytesS == 4)
355       AFr->DFormat.Format = FD_INT32;
356     else {
357       UTwarn ("AFrdAIhead - %s: \"%d\"", AFM_AIFF_UnsSSize,
358 	      (int) CkCOMM->sampleSize);
359       longjmp (AFR_JMPENV, 1);
360     }
361   }
362 
363   /* AIFF-C, compressed */
364   /* A-law and mu-law are compressed formats; for these formats
365    CkCOMM.sampleSize = 16 (not checked) */
366   else if (SAME_CSTR (CkCOMM->compressionType, CT_ULAW) ||
367 	   SAME_CSTR (CkCOMM->compressionType, CT_X_ULAW)) {
368     AFr->DFormat.Format = FD_MULAW8;
369     AFr->DFormat.NbS = 8 * FDL_MULAW8;
370   }
371   else if (SAME_CSTR (CkCOMM->compressionType, CT_ALAW) ||
372 	   SAME_CSTR (CkCOMM->compressionType, CT_X_ALAW)) {
373     AFr->DFormat.Format = FD_ALAW8;
374     AFr->DFormat.NbS = 8 * FDL_ALAW8;
375   }
376   else if (SAME_CSTR (CkCOMM->compressionType, CT_FLOAT32) ||
377 	   SAME_CSTR (CkCOMM->compressionType, CT_FL32)) {
378     AFr->DFormat.Format = FD_FLOAT32;
379     AFr->DFormat.NbS = 8 * FDL_FLOAT32;
380     if (! UTcheckIEEE ())
381       UTwarn ("AFrdAIhead - %s", AFM_NoIEEE);
382   }
383   else if (SAME_CSTR (CkCOMM->compressionType, CT_FLOAT64) ||
384 	   SAME_CSTR (CkCOMM->compressionType, CT_FL64)) {
385     AFr->DFormat.Format = FD_FLOAT64;
386     AFr->DFormat.NbS = 8 * FDL_FLOAT64;
387     if (! UTcheckIEEE ())
388       UTwarn ("AFrdAIhead - %s", AFM_NoIEEE);
389   }
390   else {
391     UTwarn ("AFrdAIhead - %s: \"%.4s\" (\"%s\")", AFM_AIFF_UnsComp,
392 	    CkCOMM->compressionType, STstrDots (CkCOMM->compressionName, 32));
393     longjmp (AFR_JMPENV, 1);
394   }
395   AFr->DFormat.Swapb = DS_EB;
396 
397   AFr->Sfreq = UTdIEEE80 (CkCOMM->sampleRate);
398   AFr->NData.Nsamp = CkCOMM->numSampleFrames * CkCOMM->numChannels;
399   AFr->NData.Nchan = CkCOMM->numChannels;
400 
401   return;
402 }
403 
404 /* Check the format version */
405 
406 
407 static int
AF_checkFVER(FILE * fp,struct AI_CkFVER * CkFVER)408 AF_checkFVER (FILE *fp, struct AI_CkFVER *CkFVER)
409 
410 {
411   int offs;
412 
413   offs  = RHEAD_V (fp, CkFVER->ckSize, DS_EB);
414   offs += RHEAD_V (fp, CkFVER->timestamp, DS_EB);
415   if (CkFVER->timestamp != AIFCVersion1)
416     UTwarn ("AFrdAIhead - %s", AFM_AIFF_BadVer);
417   offs += RSKIP (fp, RNDUPV (CkFVER->ckSize + 4, ALIGN) - offs);
418 
419   return offs;
420 }
421 
422 /* Decode the SSND chunk
423    Position left at the beginning of data or at the end of the SSND chunk
424 */
425 
426 
427 static long int
AF_decSSND(FILE * fp,struct AI_CkSSND * CkSSND)428 AF_decSSND (FILE *fp, struct AI_CkSSND *CkSSND)
429 
430 {
431   long int offs;
432 
433   /* Data size, skip to start of data */
434   offs  = RHEAD_V (fp, CkSSND->ckSize, DS_EB);
435   offs += RHEAD_V (fp, CkSSND->offset, DS_EB);
436   offs += RHEAD_V (fp, CkSSND->blockSize, DS_EB);
437 
438   return offs;
439 }
440