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