id3: fix COMM frame handling
[sox.git] / src / aiff.c
blobf25b5ebb1427f0bdde0fe9391ddd63cf9411e9bf
1 /* libSoX SGI/Amiga AIFF format.
2 * Copyright 1991-2007 Guido van Rossum And Sundry Contributors
4 * This source code is freely redistributable and may be used for
5 * any purpose. This copyright notice must be maintained.
6 * Guido van Rossum And Sundry Contributors are not responsible for
7 * the consequences of using this software.
9 * Used by SGI on 4D/35 and Indigo.
10 * This is a subformat of the EA-IFF-85 format.
11 * This is related to the IFF format used by the Amiga.
12 * But, apparently, not the same.
13 * Also AIFF-C format output that is defined in DAVIC 1.4 Part 9 Annex B
14 * (usable for japanese-data-broadcasting, specified by ARIB STD-B24.)
17 #include "sox_i.h"
18 #include "aiff.h"
20 #include <time.h> /* for time stamping comments */
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <limits.h>
27 /* forward declarations */
28 static double read_ieee_extended(sox_format_t *);
29 static int aiffwriteheader(sox_format_t *, uint64_t);
30 static int aifcwriteheader(sox_format_t *, uint64_t);
31 static void write_ieee_extended(sox_format_t *, double);
32 static double ConvertFromIeeeExtended(unsigned char*);
33 static void ConvertToIeeeExtended(double, char *);
34 static int textChunk(char **text, char *chunkDescription, sox_format_t * ft);
35 static int commentChunk(char **text, char *chunkDescription, sox_format_t * ft);
36 static void reportInstrument(sox_format_t * ft);
38 int lsx_aiffstartread(sox_format_t * ft)
40 char buf[5];
41 uint32_t totalsize;
42 uint32_t chunksize;
43 unsigned short channels = 0;
44 sox_encoding_t enc = SOX_ENCODING_SIGN2;
45 uint32_t frames;
46 unsigned short bits = 0;
47 double rate = 0.0;
48 uint32_t offset = 0;
49 uint32_t blocksize = 0;
50 int foundcomm = 0, foundmark = 0, foundinstr = 0, is_sowt = 0;
51 struct mark {
52 unsigned short id;
53 uint32_t position;
54 char name[40];
55 } marks[32];
56 unsigned short looptype;
57 int i, j;
58 unsigned short nmarks = 0;
59 unsigned short sustainLoopBegin = 0, sustainLoopEnd = 0,
60 releaseLoopBegin = 0, releaseLoopEnd = 0;
61 off_t seekto = 0;
62 size_t ssndsize = 0;
63 char *annotation;
64 char *author;
65 char *copyright;
66 char *nametext;
68 uint8_t trash8;
69 uint16_t trash16;
70 uint32_t trash32;
72 int rc;
74 /* FORM chunk */
75 if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "FORM", (size_t)4) != 0) {
76 lsx_fail_errno(ft,SOX_EHDR,"AIFF header does not begin with magic word `FORM'");
77 return(SOX_EOF);
79 lsx_readdw(ft, &totalsize);
80 if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || (strncmp(buf, "AIFF", (size_t)4) != 0 &&
81 strncmp(buf, "AIFC", (size_t)4) != 0)) {
82 lsx_fail_errno(ft,SOX_EHDR,"AIFF `FORM' chunk does not specify `AIFF' or `AIFC' as type");
83 return(SOX_EOF);
87 /* Skip everything but the COMM chunk and the SSND chunk */
88 /* The SSND chunk must be the last in the file */
89 while (1) {
90 if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF) {
91 if (seekto > 0)
92 break;
93 else {
94 lsx_fail_errno(ft,SOX_EHDR,"Missing SSND chunk in AIFF file");
95 return(SOX_EOF);
98 if (strncmp(buf, "COMM", (size_t)4) == 0) {
99 /* COMM chunk */
100 lsx_readdw(ft, &chunksize);
101 lsx_readw(ft, &channels);
102 lsx_readdw(ft, &frames);
103 lsx_readw(ft, &bits);
104 rate = read_ieee_extended(ft);
105 chunksize -= 18;
106 if (chunksize > 0) {
107 lsx_reads(ft, buf, (size_t)4);
108 chunksize -= 4;
109 if (strncmp(buf, "sowt", (size_t)4) == 0) {
110 /* CD audio as read on Mac OS machines */
111 /* Need to endian swap all the data */
112 is_sowt = 1;
114 else if (strncmp(buf, "fl32", (size_t)4) == 0 ||
115 strncmp(buf, "FL32", (size_t)4) == 0) {
116 enc = SOX_ENCODING_FLOAT;
117 if (bits != 32) {
118 lsx_fail_errno(ft, SOX_EHDR,
119 "Sample size of %u is not consistent with `fl32' compression type", bits);
120 return SOX_EOF;
123 else if (strncmp(buf, "fl64", (size_t)4) == 0 ||
124 strncmp(buf, "FL64", (size_t)4) == 0) {
125 enc = SOX_ENCODING_FLOAT;
126 if (bits != 64) {
127 lsx_fail_errno(ft, SOX_EHDR,
128 "Sample size of %u is not consistent with `fl64' compression type", bits);
129 return SOX_EOF;
132 else if (strncmp(buf, "NONE", (size_t)4) != 0 &&
133 strncmp(buf, "twos", (size_t)4) != 0) {
134 buf[4] = 0;
135 lsx_fail_errno(ft, SOX_EHDR, "Unsupported AIFC compression type `%s'", buf);
136 return(SOX_EOF);
139 while(chunksize-- > 0)
140 lsx_readb(ft, &trash8);
141 foundcomm = 1;
143 else if (strncmp(buf, "SSND", (size_t)4) == 0) {
144 /* SSND chunk */
145 lsx_readdw(ft, &chunksize);
146 lsx_readdw(ft, &offset);
147 lsx_readdw(ft, &blocksize);
148 chunksize -= 8;
149 ssndsize = chunksize;
150 /* word-align chunksize in case it wasn't
151 * done by writing application already.
153 chunksize += (chunksize % 2);
154 /* if can't seek, just do sound now */
155 if (!ft->seekable)
156 break;
157 /* else, seek to end of sound and hunt for more */
158 seekto = lsx_tell(ft);
159 lsx_seeki(ft, (off_t)chunksize, SEEK_CUR);
161 else if (strncmp(buf, "MARK", (size_t)4) == 0) {
162 /* MARK chunk */
163 lsx_readdw(ft, &chunksize);
164 if (chunksize >= sizeof(nmarks)) {
165 lsx_readw(ft, &nmarks);
166 chunksize -= sizeof(nmarks);
168 else nmarks = 0;
170 /* Some programs like to always have a MARK chunk
171 * but will set number of marks to 0 and force
172 * software to detect and ignore it.
174 if (nmarks == 0)
175 foundmark = 0;
176 else
177 foundmark = 1;
179 /* Make sure its not larger then we support */
180 if (nmarks > 32)
181 nmarks = 32;
183 for(i = 0; i < nmarks && chunksize; i++) {
184 unsigned char len, read_len, tmp_c;
186 if (chunksize < 6)
187 break;
188 lsx_readw(ft, &(marks[i].id));
189 lsx_readdw(ft, &(marks[i].position));
190 chunksize -= 6;
191 /* If error reading length then
192 * don't try to read more bytes
193 * based on that value.
195 if (lsx_readb(ft, &len) != SOX_SUCCESS)
196 break;
197 --chunksize;
198 if (len > chunksize)
199 len = chunksize;
200 read_len = len;
201 if (read_len > 39)
202 read_len = 39;
203 for(j = 0; j < len && chunksize; j++) {
204 lsx_readb(ft, &tmp_c);
205 if (j < read_len)
206 marks[i].name[j] = tmp_c;
207 chunksize--;
209 marks[i].name[read_len] = 0;
210 if ((len & 1) == 0 && chunksize) {
211 chunksize--;
212 lsx_readb(ft, &trash8);
215 /* HA HA! Sound Designer (and others) makes */
216 /* bogus files. It spits out bogus chunksize */
217 /* for MARK field */
218 while(chunksize-- > 0)
219 lsx_readb(ft, &trash8);
221 else if (strncmp(buf, "INST", (size_t)4) == 0) {
222 /* INST chunk */
223 lsx_readdw(ft, &chunksize);
224 lsx_readsb(ft, &(ft->oob.instr.MIDInote));
225 lsx_readb(ft, &trash8);
226 lsx_readsb(ft, &(ft->oob.instr.MIDIlow));
227 lsx_readsb(ft, &(ft->oob.instr.MIDIhi));
228 /* Low velocity */
229 lsx_readb(ft, &trash8);
230 /* Hi velocity */
231 lsx_readb(ft, &trash8);
232 lsx_readw(ft, &trash16);/* gain */
233 lsx_readw(ft, &looptype); /* sustain loop */
234 ft->oob.loops[0].type = looptype;
235 lsx_readw(ft, &sustainLoopBegin); /* begin marker */
236 lsx_readw(ft, &sustainLoopEnd); /* end marker */
237 lsx_readw(ft, &looptype); /* release loop */
238 ft->oob.loops[1].type = looptype;
239 lsx_readw(ft, &releaseLoopBegin); /* begin marker */
240 lsx_readw(ft, &releaseLoopEnd); /* end marker */
242 foundinstr = 1;
244 else if (strncmp(buf, "APPL", (size_t)4) == 0) {
245 lsx_readdw(ft, &chunksize);
246 /* word-align chunksize in case it wasn't
247 * done by writing application already.
249 chunksize += (chunksize % 2);
250 while(chunksize-- > 0)
251 lsx_readb(ft, &trash8);
253 else if (strncmp(buf, "ALCH", (size_t)4) == 0) {
254 /* I think this is bogus and gets grabbed by APPL */
255 /* INST chunk */
256 lsx_readdw(ft, &trash32); /* ENVS - jeez! */
257 lsx_readdw(ft, &chunksize);
258 while(chunksize-- > 0)
259 lsx_readb(ft, &trash8);
261 else if (strncmp(buf, "ANNO", (size_t)4) == 0) {
262 rc = textChunk(&annotation, "Annotation:", ft);
263 if (rc) {
264 /* Fail already called in function */
265 return(SOX_EOF);
267 if (annotation)
268 sox_append_comments(&ft->oob.comments, annotation);
269 free(annotation);
271 else if (strncmp(buf, "COMT", (size_t)4) == 0) {
272 char *comment = NULL;
273 rc = commentChunk(&comment, "Comment:", ft);
274 if (rc) {
275 /* Fail already called in function */
276 return(SOX_EOF);
278 if (comment)
279 sox_append_comments(&ft->oob.comments, comment);
280 free(comment);
282 else if (strncmp(buf, "AUTH", (size_t)4) == 0) {
283 /* Author chunk */
284 rc = textChunk(&author, "Author:", ft);
285 if (rc) {
286 /* Fail already called in function */
287 return(SOX_EOF);
289 free(author);
291 else if (strncmp(buf, "NAME", (size_t)4) == 0) {
292 /* Name chunk */
293 rc = textChunk(&nametext, "Name:", ft);
294 if (rc) {
295 /* Fail already called in function */
296 return(SOX_EOF);
298 free(nametext);
300 else if (strncmp(buf, "(c) ", (size_t)4) == 0) {
301 /* Copyright chunk */
302 rc = textChunk(&copyright, "Copyright:", ft);
303 if (rc) {
304 /* Fail already called in function */
305 return(SOX_EOF);
307 free(copyright);
309 else {
310 if (lsx_eof(ft))
311 break;
312 buf[4] = 0;
313 lsx_debug("AIFFstartread: ignoring `%s' chunk", buf);
314 lsx_readdw(ft, &chunksize);
315 if (lsx_eof(ft))
316 break;
317 /* account for padding after odd-sized chunks */
318 chunksize += chunksize & 1;
319 /* Skip the chunk using lsx_readb() so we may read
320 from a pipe */
321 while (chunksize-- > 0) {
322 if (lsx_readb(ft, &trash8) == SOX_EOF)
323 break;
326 if (lsx_eof(ft))
327 break;
331 * if a pipe, we lose all chunks after sound.
332 * Like, say, instrument loops.
334 if (ft->seekable) {
335 if (seekto > 0)
336 lsx_seeki(ft, seekto, SEEK_SET);
337 else {
338 lsx_fail_errno(ft,SOX_EOF,"AIFF: no sound data on input file");
339 return(SOX_EOF);
342 /* SSND chunk just read */
343 if (blocksize != 0)
344 lsx_warn("AIFF header has invalid blocksize. Ignoring but expect a premature EOF");
346 ssndsize -= offset;
347 while (offset-- > 0) {
348 if (lsx_readb(ft, &trash8) == SOX_EOF) {
349 lsx_fail_errno(ft,errno,"unexpected EOF while skipping AIFF offset");
350 return(SOX_EOF);
354 if (foundcomm) {
355 if (bits <= 8) bits = 8;
356 else if (bits <= 16) bits = 16;
357 else if (bits <= 24) bits = 24;
358 else if (bits <= 32) bits = 32;
359 else if (bits == 64 && enc == SOX_ENCODING_FLOAT) /* no-op */;
360 else {
361 lsx_fail_errno(ft,SOX_EFMT,"unsupported sample size in AIFF header: %d", bits);
362 return(SOX_EOF);
364 } else {
365 if ((ft->signal.channels == SOX_UNSPEC)
366 || (ft->signal.rate == SOX_UNSPEC)
367 || (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
368 || (ft->encoding.bits_per_sample == 0)) {
369 lsx_report("You must specify # channels, sample rate, signed/unsigned,");
370 lsx_report("and 8/16 on the command line.");
371 lsx_fail_errno(ft,SOX_EFMT,"Bogus AIFF file: no COMM section.");
372 return(SOX_EOF);
376 ssndsize /= bits >> 3;
378 /* Cope with 'sowt' CD tracks as read on Macs */
379 if (is_sowt)
380 ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes;
382 if (foundmark && !foundinstr) {
383 lsx_debug("Ignoring MARK chunk since no INSTR found.");
384 foundmark = 0;
386 if (!foundmark && foundinstr) {
387 lsx_debug("Ignoring INSTR chunk since no MARK found.");
388 foundinstr = 0;
390 if (foundmark && foundinstr) {
391 int i2;
392 int slbIndex = 0, sleIndex = 0;
393 int rlbIndex = 0, rleIndex = 0;
395 /* find our loop markers and save their marker indexes */
396 for(i2 = 0; i2 < nmarks; i2++) {
397 if(marks[i2].id == sustainLoopBegin)
398 slbIndex = i2;
399 if(marks[i2].id == sustainLoopEnd)
400 sleIndex = i2;
401 if(marks[i2].id == releaseLoopBegin)
402 rlbIndex = i2;
403 if(marks[i2].id == releaseLoopEnd)
404 rleIndex = i2;
407 ft->oob.instr.nloops = 0;
408 if (ft->oob.loops[0].type != 0) {
409 ft->oob.loops[0].start = marks[slbIndex].position;
410 ft->oob.loops[0].length =
411 marks[sleIndex].position - marks[slbIndex].position;
412 /* really the loop count should be infinite */
413 ft->oob.loops[0].count = 1;
414 ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[0].type;
415 ft->oob.instr.nloops++;
417 if (ft->oob.loops[1].type != 0) {
418 ft->oob.loops[1].start = marks[rlbIndex].position;
419 ft->oob.loops[1].length =
420 marks[rleIndex].position - marks[rlbIndex].position;
421 /* really the loop count should be infinite */
422 ft->oob.loops[1].count = 1;
423 ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[1].type;
424 ft->oob.instr.nloops++;
427 reportInstrument(ft);
429 return lsx_check_read_params(
430 ft, channels, rate, enc, bits, (uint64_t)ssndsize, sox_false);
433 /* print out the MIDI key allocations, loop points, directions etc */
434 static void reportInstrument(sox_format_t * ft)
436 unsigned loopNum;
438 if(ft->oob.instr.nloops > 0)
439 lsx_report("AIFF Loop markers:");
440 for(loopNum = 0; loopNum < ft->oob.instr.nloops; loopNum++) {
441 if (ft->oob.loops[loopNum].count) {
442 lsx_report("Loop %d: start: %6lu", loopNum, (unsigned long)ft->oob.loops[loopNum].start);
443 lsx_report(" end: %6lu",
444 (unsigned long)(ft->oob.loops[loopNum].start + ft->oob.loops[loopNum].length));
445 lsx_report(" count: %6d", ft->oob.loops[loopNum].count);
446 lsx_report(" type: ");
447 switch(ft->oob.loops[loopNum].type & ~SOX_LOOP_SUSTAIN_DECAY) {
448 case 0: lsx_report("off"); break;
449 case 1: lsx_report("forward"); break;
450 case 2: lsx_report("forward/backward"); break;
454 lsx_report("Unity MIDI Note: %d", ft->oob.instr.MIDInote);
455 lsx_report("Low MIDI Note: %d", ft->oob.instr.MIDIlow);
456 lsx_report("High MIDI Note: %d", ft->oob.instr.MIDIhi);
459 /* Process a text chunk, allocate memory, display it if verbose and return */
460 static int textChunk(char **text, char *chunkDescription, sox_format_t * ft)
462 uint32_t chunksize0;
463 size_t chunksize;
464 lsx_readdw(ft, &chunksize0);
465 chunksize = chunksize0;
467 /* allocate enough memory to hold the text including a terminating \0 */
468 if (chunksize != SOX_SIZE_MAX)
469 *text = lsx_malloc((size_t)chunksize+1);
470 else
471 *text = lsx_malloc((size_t)chunksize);
473 if (lsx_readbuf(ft, *text, (size_t) chunksize) != chunksize)
475 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
476 return(SOX_EOF);
478 if (chunksize != SOX_SIZE_MAX)
479 *(*text + chunksize) = '\0';
480 else
481 *(*text + chunksize-1) = '\0';
482 if (chunksize % 2)
484 /* Read past pad byte */
485 char c;
486 if (lsx_readbuf(ft, &c, (size_t)1) != 1)
488 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
489 return(SOX_EOF);
492 lsx_debug("%-10s \"%s\"", chunkDescription, *text);
493 return(SOX_SUCCESS);
496 /* Comment lengths are words, not double words, and we can have several, so
497 we use a special function, not textChunk().;
499 static int commentChunk(char **text, char *chunkDescription, sox_format_t * ft)
501 uint32_t chunksize;
502 unsigned short numComments;
503 uint32_t timeStamp;
504 unsigned short markerId;
505 unsigned short totalCommentLength = 0;
506 unsigned int totalReadLength = 0;
507 unsigned int commentIndex;
509 lsx_readdw(ft, &chunksize);
510 lsx_readw(ft, &numComments);
511 totalReadLength += 2; /* chunksize doesn't count */
512 for(commentIndex = 0; commentIndex < numComments; commentIndex++) {
513 unsigned short commentLength;
515 lsx_readdw(ft, &timeStamp);
516 lsx_readw(ft, &markerId);
517 lsx_readw(ft, &commentLength);
518 if (((size_t)totalCommentLength) + commentLength > USHRT_MAX) {
519 lsx_fail_errno(ft,SOX_EOF,"AIFF: Comment too long in %s header", chunkDescription);
520 return(SOX_EOF);
522 totalCommentLength += commentLength;
523 /* allocate enough memory to hold the text including a terminating \0 */
524 if(commentIndex == 0) {
525 *text = lsx_malloc((size_t) totalCommentLength + 1);
527 else {
528 *text = lsx_realloc(*text, (size_t) totalCommentLength + 1);
531 if (lsx_readbuf(ft, *text + totalCommentLength - commentLength, (size_t) commentLength) != commentLength) {
532 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
533 return(SOX_EOF);
535 *(*text + totalCommentLength) = '\0';
536 totalReadLength += totalCommentLength + 4 + 2 + 2; /* include header */
537 if (commentLength % 2) {
538 /* Read past pad byte */
539 char c;
540 if (lsx_readbuf(ft, &c, (size_t)1) != 1) {
541 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
542 return(SOX_EOF);
544 totalReadLength += 1;
547 lsx_debug("%-10s \"%s\"", chunkDescription, *text);
548 /* make sure we read the whole chunk */
549 if (totalReadLength < chunksize) {
550 size_t i;
551 char c;
552 for (i=0; i < chunksize - totalReadLength; i++ )
553 lsx_readbuf(ft, &c, (size_t)1);
555 return(SOX_SUCCESS);
558 int lsx_aiffstopread(sox_format_t * ft)
560 char buf[5];
561 uint32_t chunksize;
562 uint8_t trash;
564 if (!ft->seekable)
566 while (! lsx_eof(ft))
568 if (lsx_readbuf(ft, buf, (size_t)4) != 4)
569 break;
571 lsx_readdw(ft, &chunksize);
572 if (lsx_eof(ft))
573 break;
574 buf[4] = '\0';
575 lsx_warn("Ignoring AIFF tail chunk: `%s', %u bytes long",
576 buf, chunksize);
577 if (! strcmp(buf, "MARK") || ! strcmp(buf, "INST"))
578 lsx_warn(" You're stripping MIDI/loop info!");
579 while (chunksize-- > 0)
581 if (lsx_readb(ft, &trash) == SOX_EOF)
582 break;
586 return SOX_SUCCESS;
589 /* When writing, the header is supposed to contain the number of
590 samples and data bytes written.
591 Since we don't know how many samples there are until we're done,
592 we first write the header with an very large number,
593 and at the end we rewind the file and write the header again
594 with the right number. This only works if the file is seekable;
595 if it is not, the very large size remains in the header.
596 Strictly spoken this is not legal, but the playaiff utility
597 will still be able to play the resulting file. */
599 int lsx_aiffstartwrite(sox_format_t * ft)
601 int rc;
603 /* Needed because lsx_rawwrite() */
604 rc = lsx_rawstartwrite(ft);
605 if (rc)
606 return rc;
608 /* Compute the "very large number" so that a maximum number
609 of samples can be transmitted through a pipe without the
610 risk of causing overflow when calculating the number of bytes.
611 At 48 kHz, 16 bits stereo, this gives ~3 hours of audio.
612 Sorry, the AIFF format does not provide for an indefinite
613 number of samples. */
614 return(aiffwriteheader(ft, (uint64_t) 0x7f000000 / ((ft->encoding.bits_per_sample>>3)*ft->signal.channels)));
617 int lsx_aiffstopwrite(sox_format_t * ft)
619 /* If we've written an odd number of bytes, write a padding
620 NUL */
621 if (ft->olength % 2 == 1 && ft->encoding.bits_per_sample == 8 && ft->signal.channels == 1)
623 sox_sample_t buf = 0;
624 lsx_rawwrite(ft, &buf, (size_t) 1);
627 if (!ft->seekable)
629 lsx_fail_errno(ft,SOX_EOF,"Non-seekable file.");
630 return(SOX_EOF);
632 if (lsx_seeki(ft, (off_t)0, SEEK_SET) != 0)
634 lsx_fail_errno(ft,errno,"can't rewind output file to rewrite AIFF header");
635 return(SOX_EOF);
637 return(aiffwriteheader(ft, ft->olength / ft->signal.channels));
640 static int aiffwriteheader(sox_format_t * ft, uint64_t nframes)
642 int hsize =
643 8 /*COMM hdr*/ + 18 /*COMM chunk*/ +
644 8 /*SSND hdr*/ + 12 /*SSND chunk*/;
645 unsigned bits = 0;
646 unsigned i;
647 uint64_t size;
648 size_t padded_comment_size = 0, comment_size = 0;
649 size_t comment_chunk_size = 0;
650 char * comment = lsx_cat_comments(ft->oob.comments);
652 /* MARK and INST chunks */
653 if (ft->oob.instr.nloops) {
654 hsize += 8 /* MARK hdr */ + 2 + 16*ft->oob.instr.nloops;
655 hsize += 8 /* INST hdr */ + 20; /* INST chunk */
658 if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
659 ft->encoding.bits_per_sample == 8)
660 bits = 8;
661 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
662 ft->encoding.bits_per_sample == 16)
663 bits = 16;
664 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
665 ft->encoding.bits_per_sample == 24)
666 bits = 24;
667 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
668 ft->encoding.bits_per_sample == 32)
669 bits = 32;
670 else
672 lsx_fail_errno(ft,SOX_EFMT,"unsupported output encoding/size for AIFF header");
673 return(SOX_EOF);
676 /* COMT comment chunk -- holds comments text with a timestamp and marker id */
677 /* We calculate the comment_chunk_size if we will be writing a comment */
678 if (ft->oob.comments)
680 comment_size = strlen(comment);
681 /* Must put an even number of characters out.
682 * True 68k processors OS's seem to require this.
684 padded_comment_size = ((comment_size % 2) == 0) ?
685 comment_size : comment_size + 1;
686 /* one comment, timestamp, marker ID and text count */
687 comment_chunk_size = (2 + 4 + 2 + 2 + padded_comment_size);
688 hsize += 8 /* COMT hdr */ + comment_chunk_size;
691 lsx_writes(ft, "FORM"); /* IFF header */
692 /* file size */
693 size = hsize + nframes * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels;
694 if (size > UINT_MAX)
696 lsx_warn("file size too big for accurate AIFF header");
697 size = UINT_MAX;
699 lsx_writedw(ft, (unsigned)size);
700 lsx_writes(ft, "AIFF"); /* File type */
702 /* Now we write the COMT comment chunk using the precomputed sizes */
703 if (ft->oob.comments)
705 lsx_writes(ft, "COMT");
706 lsx_writedw(ft, (unsigned) comment_chunk_size);
708 /* one comment */
709 lsx_writew(ft, 1);
711 /* time stamp of comment, Unix knows of time from 1/1/1970,
712 Apple knows time from 1/1/1904 */
713 lsx_writedw(ft, (unsigned)((sox_globals.repeatable? 0 : time(NULL)) + 2082844800));
715 /* A marker ID of 0 indicates the comment is not associated
716 with a marker */
717 lsx_writew(ft, 0);
719 /* now write the count and the bytes of text */
720 lsx_writew(ft, (unsigned) padded_comment_size);
721 lsx_writes(ft, comment);
722 if (comment_size != padded_comment_size)
723 lsx_writes(ft, " ");
725 free(comment);
727 /* COMM chunk -- describes encoding (and #frames) */
728 lsx_writes(ft, "COMM");
729 lsx_writedw(ft, 18); /* COMM chunk size */
730 lsx_writew(ft, ft->signal.channels); /* nchannels */
731 lsx_writedw(ft, (unsigned) nframes); /* number of frames */
732 lsx_writew(ft, bits); /* sample width, in bits */
733 write_ieee_extended(ft, (double)ft->signal.rate);
735 /* MARK chunk -- set markers */
736 if (ft->oob.instr.nloops) {
737 lsx_writes(ft, "MARK");
738 if (ft->oob.instr.nloops > 2)
739 ft->oob.instr.nloops = 2;
740 lsx_writedw(ft, 2 + 16u*ft->oob.instr.nloops);
741 lsx_writew(ft, ft->oob.instr.nloops);
743 for(i = 0; i < ft->oob.instr.nloops; i++) {
744 unsigned start = ft->oob.loops[i].start > UINT_MAX
745 ? UINT_MAX
746 : ft->oob.loops[i].start;
747 unsigned end = ft->oob.loops[i].start + ft->oob.loops[i].length > UINT_MAX
748 ? UINT_MAX
749 : ft->oob.loops[i].start + ft->oob.loops[i].length;
750 lsx_writew(ft, i + 1);
751 lsx_writedw(ft, start);
752 lsx_writeb(ft, 0);
753 lsx_writeb(ft, 0);
754 lsx_writew(ft, i*2 + 1);
755 lsx_writedw(ft, end);
756 lsx_writeb(ft, 0);
757 lsx_writeb(ft, 0);
760 lsx_writes(ft, "INST");
761 lsx_writedw(ft, 20);
762 /* random MIDI shit that we default on */
763 lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDInote);
764 lsx_writeb(ft, 0); /* detune */
765 lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDIlow);
766 lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDIhi);
767 lsx_writeb(ft, 1); /* low velocity */
768 lsx_writeb(ft, 127); /* hi velocity */
769 lsx_writew(ft, 0); /* gain */
771 /* sustain loop */
772 lsx_writew(ft, ft->oob.loops[0].type);
773 lsx_writew(ft, 1); /* marker 1 */
774 lsx_writew(ft, 3); /* marker 3 */
775 /* release loop, if there */
776 if (ft->oob.instr.nloops == 2) {
777 lsx_writew(ft, ft->oob.loops[1].type);
778 lsx_writew(ft, 2); /* marker 2 */
779 lsx_writew(ft, 4); /* marker 4 */
780 } else {
781 lsx_writew(ft, 0); /* no release loop */
782 lsx_writew(ft, 0);
783 lsx_writew(ft, 0);
787 /* SSND chunk -- describes data */
788 lsx_writes(ft, "SSND");
789 /* chunk size */
790 lsx_writedw(ft, (unsigned) (8 + nframes * ft->signal.channels * (ft->encoding.bits_per_sample >> 3)));
791 lsx_writedw(ft, 0); /* offset */
792 lsx_writedw(ft, 0); /* block size */
793 return(SOX_SUCCESS);
796 int lsx_aifcstartwrite(sox_format_t * ft)
798 int rc;
800 /* Needed because lsx_rawwrite() */
801 rc = lsx_rawstartwrite(ft);
802 if (rc)
803 return rc;
805 /* Compute the "very large number" so that a maximum number
806 of samples can be transmitted through a pipe without the
807 risk of causing overflow when calculating the number of bytes.
808 At 48 kHz, 16 bits stereo, this gives ~3 hours of music.
809 Sorry, the AIFC format does not provide for an "infinite"
810 number of samples. */
811 return(aifcwriteheader(ft, (uint64_t) 0x7f000000 / ((ft->encoding.bits_per_sample >> 3)*ft->signal.channels)));
814 int lsx_aifcstopwrite(sox_format_t * ft)
816 /* If we've written an odd number of bytes, write a padding
817 NUL */
818 if (ft->olength % 2 == 1 && ft->encoding.bits_per_sample == 8 && ft->signal.channels == 1)
820 sox_sample_t buf = 0;
821 lsx_rawwrite(ft, &buf, (size_t) 1);
824 if (!ft->seekable)
826 lsx_fail_errno(ft,SOX_EOF,"Non-seekable file.");
827 return(SOX_EOF);
829 if (lsx_seeki(ft, (off_t)0, SEEK_SET) != 0)
831 lsx_fail_errno(ft,errno,"can't rewind output file to rewrite AIFC header");
832 return(SOX_EOF);
834 return(aifcwriteheader(ft, ft->olength / ft->signal.channels));
837 static int aifcwriteheader(sox_format_t * ft, uint64_t nframes)
839 unsigned hsize;
840 unsigned bits = 0;
841 uint64_t size;
842 char *ctype = NULL, *cname = NULL;
843 unsigned cname_len = 0, comm_len = 0, comm_padding = 0;
845 if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
846 ft->encoding.bits_per_sample == 8)
847 bits = 8;
848 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
849 ft->encoding.bits_per_sample == 16)
850 bits = 16;
851 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
852 ft->encoding.bits_per_sample == 24)
853 bits = 24;
854 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
855 ft->encoding.bits_per_sample == 32)
856 bits = 32;
857 else if (ft->encoding.encoding == SOX_ENCODING_FLOAT &&
858 ft->encoding.bits_per_sample == 32)
859 bits = 32;
860 else if (ft->encoding.encoding == SOX_ENCODING_FLOAT &&
861 ft->encoding.bits_per_sample == 64)
862 bits = 64;
863 else
865 lsx_fail_errno(ft,SOX_EFMT,"unsupported output encoding/size for AIFC header");
866 return(SOX_EOF);
869 /* calculate length of COMM chunk (without header) */
870 switch (ft->encoding.encoding) {
871 case SOX_ENCODING_SIGN2:
872 ctype = "NONE";
873 cname = "not compressed";
874 break;
875 case SOX_ENCODING_FLOAT:
876 if (bits == 32) {
877 ctype = "fl32";
878 cname = "32-bit floating point";
879 } else {
880 ctype = "fl64";
881 cname = "64-bit floating point";
883 break;
884 default: /* can't happen */
885 break;
887 cname_len = strlen(cname);
888 comm_len = 18+4+1+cname_len;
889 comm_padding = comm_len%2;
891 hsize = 12 /*FVER*/ + 8 /*COMM hdr*/ + comm_len+comm_padding /*COMM chunk*/ +
892 8 /*SSND hdr*/ + 12 /*SSND chunk*/;
894 lsx_writes(ft, "FORM"); /* IFF header */
895 /* file size */
896 size = hsize + nframes * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels;
897 if (size > UINT_MAX)
899 lsx_warn("file size too big for accurate AIFC header");
900 size = UINT_MAX;
902 lsx_writedw(ft, (unsigned)size);
903 lsx_writes(ft, "AIFC"); /* File type */
905 /* FVER chunk */
906 lsx_writes(ft, "FVER");
907 lsx_writedw(ft, 4); /* FVER chunk size */
908 lsx_writedw(ft, 0xa2805140); /* version_date(May23,1990,2:40pm) */
910 /* COMM chunk -- describes encoding (and #frames) */
911 lsx_writes(ft, "COMM");
912 lsx_writedw(ft, comm_len+comm_padding); /* COMM chunk size */
913 lsx_writew(ft, ft->signal.channels); /* nchannels */
914 lsx_writedw(ft, (unsigned) nframes); /* number of frames */
915 lsx_writew(ft, bits); /* sample width, in bits */
916 write_ieee_extended(ft, (double)ft->signal.rate);
918 lsx_writes(ft, ctype); /*compression_type*/
919 lsx_writeb(ft, cname_len);
920 lsx_writes(ft, cname);
921 if (comm_padding)
922 lsx_writeb(ft, 0);
924 /* SSND chunk -- describes data */
925 lsx_writes(ft, "SSND");
926 /* chunk size */
927 lsx_writedw(ft, (unsigned) (8 + nframes * ft->signal.channels * (ft->encoding.bits_per_sample >> 3)));
928 lsx_writedw(ft, 0); /* offset */
929 lsx_writedw(ft, 0); /* block size */
931 /* Any Private chunks shall appear after the required chunks (FORM,FVER,COMM,SSND) */
932 return(SOX_SUCCESS);
935 static double read_ieee_extended(sox_format_t * ft)
937 unsigned char buf[10];
938 if (lsx_readbuf(ft, buf, (size_t)10) != 10)
940 lsx_fail_errno(ft,SOX_EOF,"EOF while reading IEEE extended number");
941 return(SOX_EOF);
943 return ConvertFromIeeeExtended(buf);
946 static void write_ieee_extended(sox_format_t * ft, double x)
948 char buf[10];
949 ConvertToIeeeExtended(x, buf);
950 lsx_debug_more("converted %g to %o %o %o %o %o %o %o %o %o %o",
952 buf[0], buf[1], buf[2], buf[3], buf[4],
953 buf[5], buf[6], buf[7], buf[8], buf[9]);
954 (void)lsx_writebuf(ft, buf, (size_t) 10);
959 * C O N V E R T T O I E E E E X T E N D E D
962 /* Copyright (C) 1988-1991 Apple Computer, Inc.
964 * All rights reserved.
966 * Warranty Information
967 * Even though Apple has reviewed this software, Apple makes no warranty
968 * or representation, either express or implied, with respect to this
969 * software, its quality, accuracy, merchantability, or fitness for a
970 * particular purpose. As a result, this software is provided "as is,"
971 * and you, its user, are assuming the entire risk as to its quality
972 * and accuracy.
974 * Machine-independent I/O routines for IEEE floating-point numbers.
976 * NaN's and infinities are converted to HUGE_VAL, which
977 * happens to be infinity on IEEE machines. Unfortunately, it is
978 * impossible to preserve NaN's in a machine-independent way.
979 * Infinities are, however, preserved on IEEE machines.
981 * These routines have been tested on the following machines:
982 * Apple Macintosh, MPW 3.1 C compiler
983 * Apple Macintosh, THINK C compiler
984 * Silicon Graphics IRIS, MIPS compiler
985 * Cray X/MP and Y/MP
986 * Digital Equipment VAX
989 * Implemented by Malcolm Slaney and Ken Turkowski.
991 * Malcolm Slaney contributions during 1988-1990 include big- and little-
992 * endian file I/O, conversion to and from Motorola's extended 80-bit
993 * floating-point format, and conversions to and from IEEE single-
994 * precision floating-point format.
996 * In 1991, Ken Turkowski implemented the conversions to and from
997 * IEEE double-precision format, added more precision to the extended
998 * conversions, and accommodated conversions involving +/- infinity,
999 * NaN's, and denormalized numbers.
1002 #define FloatToUnsigned(f) ((uint32_t)(((int32_t)(f - 2147483648.0)) + 2147483647) + 1)
1004 static void ConvertToIeeeExtended(double num, char *bytes)
1006 int sign;
1007 int expon;
1008 double fMant, fsMant;
1009 uint32_t hiMant, loMant;
1011 if (num < 0) {
1012 sign = 0x8000;
1013 num *= -1;
1014 } else {
1015 sign = 0;
1018 if (num == 0) {
1019 expon = 0; hiMant = 0; loMant = 0;
1021 else {
1022 fMant = frexp(num, &expon);
1023 if ((expon > 16384) || !(fMant < 1)) { /* Infinity or NaN */
1024 expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */
1026 else { /* Finite */
1027 expon += 16382;
1028 if (expon < 0) { /* denormalized */
1029 fMant = ldexp(fMant, expon);
1030 expon = 0;
1032 expon |= sign;
1033 fMant = ldexp(fMant, 32);
1034 fsMant = floor(fMant);
1035 hiMant = FloatToUnsigned(fsMant);
1036 fMant = ldexp(fMant - fsMant, 32);
1037 fsMant = floor(fMant);
1038 loMant = FloatToUnsigned(fsMant);
1042 bytes[0] = expon >> 8;
1043 bytes[1] = expon;
1044 bytes[2] = hiMant >> 24;
1045 bytes[3] = hiMant >> 16;
1046 bytes[4] = hiMant >> 8;
1047 bytes[5] = hiMant;
1048 bytes[6] = loMant >> 24;
1049 bytes[7] = loMant >> 16;
1050 bytes[8] = loMant >> 8;
1051 bytes[9] = loMant;
1056 * C O N V E R T F R O M I E E E E X T E N D E D
1060 * Copyright (C) 1988-1991 Apple Computer, Inc.
1062 * All rights reserved.
1064 * Warranty Information
1065 * Even though Apple has reviewed this software, Apple makes no warranty
1066 * or representation, either express or implied, with respect to this
1067 * software, its quality, accuracy, merchantability, or fitness for a
1068 * particular purpose. As a result, this software is provided "as is,"
1069 * and you, its user, are assuming the entire risk as to its quality
1070 * and accuracy.
1072 * This code may be used and freely distributed as long as it includes
1073 * this copyright notice and the above warranty information.
1075 * Machine-independent I/O routines for IEEE floating-point numbers.
1077 * NaN's and infinities are converted to HUGE_VAL, which
1078 * happens to be infinity on IEEE machines. Unfortunately, it is
1079 * impossible to preserve NaN's in a machine-independent way.
1080 * Infinities are, however, preserved on IEEE machines.
1082 * These routines have been tested on the following machines:
1083 * Apple Macintosh, MPW 3.1 C compiler
1084 * Apple Macintosh, THINK C compiler
1085 * Silicon Graphics IRIS, MIPS compiler
1086 * Cray X/MP and Y/MP
1087 * Digital Equipment VAX
1090 * Implemented by Malcolm Slaney and Ken Turkowski.
1092 * Malcolm Slaney contributions during 1988-1990 include big- and little-
1093 * endian file I/O, conversion to and from Motorola's extended 80-bit
1094 * floating-point format, and conversions to and from IEEE single-
1095 * precision floating-point format.
1097 * In 1991, Ken Turkowski implemented the conversions to and from
1098 * IEEE double-precision format, added more precision to the extended
1099 * conversions, and accommodated conversions involving +/- infinity,
1100 * NaN's, and denormalized numbers.
1103 #define UnsignedToFloat(u) (((double)((int32_t)(u - 2147483647 - 1))) + 2147483648.0)
1105 /****************************************************************
1106 * Extended precision IEEE floating-point conversion routine.
1107 ****************************************************************/
1109 static double ConvertFromIeeeExtended(unsigned char *bytes)
1111 double f;
1112 int expon;
1113 uint32_t hiMant, loMant;
1115 expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
1116 hiMant = ((uint32_t)(bytes[2] & 0xFF) << 24)
1117 | ((uint32_t)(bytes[3] & 0xFF) << 16)
1118 | ((uint32_t)(bytes[4] & 0xFF) << 8)
1119 | ((uint32_t)(bytes[5] & 0xFF));
1120 loMant = ((uint32_t)(bytes[6] & 0xFF) << 24)
1121 | ((uint32_t)(bytes[7] & 0xFF) << 16)
1122 | ((uint32_t)(bytes[8] & 0xFF) << 8)
1123 | ((uint32_t)(bytes[9] & 0xFF));
1125 if (expon == 0 && hiMant == 0 && loMant == 0) {
1126 f = 0;
1128 else {
1129 if (expon == 0x7FFF) { /* Infinity or NaN */
1130 f = HUGE_VAL;
1132 else {
1133 expon -= 16383;
1134 f = ldexp(UnsignedToFloat(hiMant), expon-=31);
1135 f += ldexp(UnsignedToFloat(loMant), expon-=32);
1139 if (bytes[0] & 0x80)
1140 return -f;
1141 else
1142 return f;