aiff: handle id3 tags
[sox.git] / src / aiff.c
blob3a152c588cbacdcc254694cd6449ab867dc0d63c
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"
19 #include "id3.h"
21 #include <time.h> /* for time stamping comments */
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <limits.h>
28 /* forward declarations */
29 static double read_ieee_extended(sox_format_t *);
30 static int aiffwriteheader(sox_format_t *, uint64_t);
31 static int aifcwriteheader(sox_format_t *, uint64_t);
32 static void write_ieee_extended(sox_format_t *, double);
33 static double ConvertFromIeeeExtended(unsigned char*);
34 static void ConvertToIeeeExtended(double, char *);
35 static int textChunk(char **text, char *chunkDescription, sox_format_t * ft);
36 static int commentChunk(char **text, char *chunkDescription, sox_format_t * ft);
37 static void reportInstrument(sox_format_t * ft);
39 int lsx_aiffstartread(sox_format_t * ft)
41 char buf[5];
42 uint32_t totalsize;
43 uint32_t chunksize;
44 unsigned short channels = 0;
45 sox_encoding_t enc = SOX_ENCODING_SIGN2;
46 uint32_t frames;
47 unsigned short bits = 0;
48 double rate = 0.0;
49 uint32_t offset = 0;
50 uint32_t blocksize = 0;
51 int foundcomm = 0, foundmark = 0, foundinstr = 0, is_sowt = 0;
52 struct mark {
53 unsigned short id;
54 uint32_t position;
55 char name[40];
56 } marks[32];
57 unsigned short looptype;
58 int i, j;
59 unsigned short nmarks = 0;
60 unsigned short sustainLoopBegin = 0, sustainLoopEnd = 0,
61 releaseLoopBegin = 0, releaseLoopEnd = 0;
62 off_t seekto = 0;
63 size_t ssndsize = 0;
64 char *annotation;
65 char *author;
66 char *copyright;
67 char *nametext;
69 uint8_t trash8;
70 uint16_t trash16;
71 uint32_t trash32;
73 int rc;
75 /* FORM chunk */
76 if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "FORM", (size_t)4) != 0) {
77 lsx_fail_errno(ft,SOX_EHDR,"AIFF header does not begin with magic word `FORM'");
78 return(SOX_EOF);
80 lsx_readdw(ft, &totalsize);
81 if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || (strncmp(buf, "AIFF", (size_t)4) != 0 &&
82 strncmp(buf, "AIFC", (size_t)4) != 0)) {
83 lsx_fail_errno(ft,SOX_EHDR,"AIFF `FORM' chunk does not specify `AIFF' or `AIFC' as type");
84 return(SOX_EOF);
88 /* Skip everything but the COMM chunk and the SSND chunk */
89 /* The SSND chunk must be the last in the file */
90 while (1) {
91 if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF) {
92 if (seekto > 0)
93 break;
94 else {
95 lsx_fail_errno(ft,SOX_EHDR,"Missing SSND chunk in AIFF file");
96 return(SOX_EOF);
99 if (strncmp(buf, "COMM", (size_t)4) == 0) {
100 /* COMM chunk */
101 lsx_readdw(ft, &chunksize);
102 lsx_readw(ft, &channels);
103 lsx_readdw(ft, &frames);
104 lsx_readw(ft, &bits);
105 rate = read_ieee_extended(ft);
106 chunksize -= 18;
107 if (chunksize > 0) {
108 lsx_reads(ft, buf, (size_t)4);
109 chunksize -= 4;
110 if (strncmp(buf, "sowt", (size_t)4) == 0) {
111 /* CD audio as read on Mac OS machines */
112 /* Need to endian swap all the data */
113 is_sowt = 1;
115 else if (strncmp(buf, "fl32", (size_t)4) == 0 ||
116 strncmp(buf, "FL32", (size_t)4) == 0) {
117 enc = SOX_ENCODING_FLOAT;
118 if (bits != 32) {
119 lsx_fail_errno(ft, SOX_EHDR,
120 "Sample size of %u is not consistent with `fl32' compression type", bits);
121 return SOX_EOF;
124 else if (strncmp(buf, "fl64", (size_t)4) == 0 ||
125 strncmp(buf, "FL64", (size_t)4) == 0) {
126 enc = SOX_ENCODING_FLOAT;
127 if (bits != 64) {
128 lsx_fail_errno(ft, SOX_EHDR,
129 "Sample size of %u is not consistent with `fl64' compression type", bits);
130 return SOX_EOF;
133 else if (strncmp(buf, "NONE", (size_t)4) != 0 &&
134 strncmp(buf, "twos", (size_t)4) != 0) {
135 buf[4] = 0;
136 lsx_fail_errno(ft, SOX_EHDR, "Unsupported AIFC compression type `%s'", buf);
137 return(SOX_EOF);
140 while(chunksize-- > 0)
141 lsx_readb(ft, &trash8);
142 foundcomm = 1;
144 else if (strncmp(buf, "SSND", (size_t)4) == 0) {
145 /* SSND chunk */
146 lsx_readdw(ft, &chunksize);
147 lsx_readdw(ft, &offset);
148 lsx_readdw(ft, &blocksize);
149 chunksize -= 8;
150 ssndsize = chunksize;
151 /* word-align chunksize in case it wasn't
152 * done by writing application already.
154 chunksize += (chunksize % 2);
155 /* if can't seek, just do sound now */
156 if (!ft->seekable)
157 break;
158 /* else, seek to end of sound and hunt for more */
159 seekto = lsx_tell(ft);
160 lsx_seeki(ft, (off_t)chunksize, SEEK_CUR);
162 else if (strncmp(buf, "MARK", (size_t)4) == 0) {
163 /* MARK chunk */
164 lsx_readdw(ft, &chunksize);
165 if (chunksize >= sizeof(nmarks)) {
166 lsx_readw(ft, &nmarks);
167 chunksize -= sizeof(nmarks);
169 else nmarks = 0;
171 /* Some programs like to always have a MARK chunk
172 * but will set number of marks to 0 and force
173 * software to detect and ignore it.
175 if (nmarks == 0)
176 foundmark = 0;
177 else
178 foundmark = 1;
180 /* Make sure its not larger then we support */
181 if (nmarks > 32)
182 nmarks = 32;
184 for(i = 0; i < nmarks && chunksize; i++) {
185 unsigned char len, read_len, tmp_c;
187 if (chunksize < 6)
188 break;
189 lsx_readw(ft, &(marks[i].id));
190 lsx_readdw(ft, &(marks[i].position));
191 chunksize -= 6;
192 /* If error reading length then
193 * don't try to read more bytes
194 * based on that value.
196 if (lsx_readb(ft, &len) != SOX_SUCCESS)
197 break;
198 --chunksize;
199 if (len > chunksize)
200 len = chunksize;
201 read_len = len;
202 if (read_len > 39)
203 read_len = 39;
204 for(j = 0; j < len && chunksize; j++) {
205 lsx_readb(ft, &tmp_c);
206 if (j < read_len)
207 marks[i].name[j] = tmp_c;
208 chunksize--;
210 marks[i].name[read_len] = 0;
211 if ((len & 1) == 0 && chunksize) {
212 chunksize--;
213 lsx_readb(ft, &trash8);
216 /* HA HA! Sound Designer (and others) makes */
217 /* bogus files. It spits out bogus chunksize */
218 /* for MARK field */
219 while(chunksize-- > 0)
220 lsx_readb(ft, &trash8);
222 else if (strncmp(buf, "INST", (size_t)4) == 0) {
223 /* INST chunk */
224 lsx_readdw(ft, &chunksize);
225 lsx_readsb(ft, &(ft->oob.instr.MIDInote));
226 lsx_readb(ft, &trash8);
227 lsx_readsb(ft, &(ft->oob.instr.MIDIlow));
228 lsx_readsb(ft, &(ft->oob.instr.MIDIhi));
229 /* Low velocity */
230 lsx_readb(ft, &trash8);
231 /* Hi velocity */
232 lsx_readb(ft, &trash8);
233 lsx_readw(ft, &trash16);/* gain */
234 lsx_readw(ft, &looptype); /* sustain loop */
235 ft->oob.loops[0].type = looptype;
236 lsx_readw(ft, &sustainLoopBegin); /* begin marker */
237 lsx_readw(ft, &sustainLoopEnd); /* end marker */
238 lsx_readw(ft, &looptype); /* release loop */
239 ft->oob.loops[1].type = looptype;
240 lsx_readw(ft, &releaseLoopBegin); /* begin marker */
241 lsx_readw(ft, &releaseLoopEnd); /* end marker */
243 foundinstr = 1;
245 else if (strncmp(buf, "APPL", (size_t)4) == 0) {
246 lsx_readdw(ft, &chunksize);
247 /* word-align chunksize in case it wasn't
248 * done by writing application already.
250 chunksize += (chunksize % 2);
251 while(chunksize-- > 0)
252 lsx_readb(ft, &trash8);
254 else if (strncmp(buf, "ALCH", (size_t)4) == 0) {
255 /* I think this is bogus and gets grabbed by APPL */
256 /* INST chunk */
257 lsx_readdw(ft, &trash32); /* ENVS - jeez! */
258 lsx_readdw(ft, &chunksize);
259 while(chunksize-- > 0)
260 lsx_readb(ft, &trash8);
262 else if (strncmp(buf, "ANNO", (size_t)4) == 0) {
263 rc = textChunk(&annotation, "Annotation:", ft);
264 if (rc) {
265 /* Fail already called in function */
266 return(SOX_EOF);
268 if (annotation)
269 sox_append_comments(&ft->oob.comments, annotation);
270 free(annotation);
272 else if (strncmp(buf, "COMT", (size_t)4) == 0) {
273 char *comment = NULL;
274 rc = commentChunk(&comment, "Comment:", ft);
275 if (rc) {
276 /* Fail already called in function */
277 return(SOX_EOF);
279 if (comment)
280 sox_append_comments(&ft->oob.comments, comment);
281 free(comment);
283 else if (strncmp(buf, "AUTH", (size_t)4) == 0) {
284 /* Author chunk */
285 rc = textChunk(&author, "Author:", ft);
286 if (rc) {
287 /* Fail already called in function */
288 return(SOX_EOF);
290 free(author);
292 else if (strncmp(buf, "NAME", (size_t)4) == 0) {
293 /* Name chunk */
294 rc = textChunk(&nametext, "Name:", ft);
295 if (rc) {
296 /* Fail already called in function */
297 return(SOX_EOF);
299 free(nametext);
301 else if (strncmp(buf, "(c) ", (size_t)4) == 0) {
302 /* Copyright chunk */
303 rc = textChunk(&copyright, "Copyright:", ft);
304 if (rc) {
305 /* Fail already called in function */
306 return(SOX_EOF);
308 free(copyright);
310 else if (strncmp(buf, "ID3 ", 4) == 0) {
311 off_t offs;
312 lsx_readdw(ft, &chunksize);
313 offs = lsx_tell(ft);
314 lsx_id3_read_tag(ft, 0);
315 lsx_seeki(ft, offs + chunksize, SEEK_SET);
317 else {
318 if (lsx_eof(ft))
319 break;
320 buf[4] = 0;
321 lsx_debug("AIFFstartread: ignoring `%s' chunk", buf);
322 lsx_readdw(ft, &chunksize);
323 if (lsx_eof(ft))
324 break;
325 /* account for padding after odd-sized chunks */
326 chunksize += chunksize & 1;
327 /* Skip the chunk using lsx_readb() so we may read
328 from a pipe */
329 while (chunksize-- > 0) {
330 if (lsx_readb(ft, &trash8) == SOX_EOF)
331 break;
334 if (lsx_eof(ft))
335 break;
339 * if a pipe, we lose all chunks after sound.
340 * Like, say, instrument loops.
342 if (ft->seekable) {
343 if (seekto > 0)
344 lsx_seeki(ft, seekto, SEEK_SET);
345 else {
346 lsx_fail_errno(ft,SOX_EOF,"AIFF: no sound data on input file");
347 return(SOX_EOF);
350 /* SSND chunk just read */
351 if (blocksize != 0)
352 lsx_warn("AIFF header has invalid blocksize. Ignoring but expect a premature EOF");
354 ssndsize -= offset;
355 while (offset-- > 0) {
356 if (lsx_readb(ft, &trash8) == SOX_EOF) {
357 lsx_fail_errno(ft,errno,"unexpected EOF while skipping AIFF offset");
358 return(SOX_EOF);
362 if (foundcomm) {
363 if (bits <= 8) bits = 8;
364 else if (bits <= 16) bits = 16;
365 else if (bits <= 24) bits = 24;
366 else if (bits <= 32) bits = 32;
367 else if (bits == 64 && enc == SOX_ENCODING_FLOAT) /* no-op */;
368 else {
369 lsx_fail_errno(ft,SOX_EFMT,"unsupported sample size in AIFF header: %d", bits);
370 return(SOX_EOF);
372 } else {
373 if ((ft->signal.channels == SOX_UNSPEC)
374 || (ft->signal.rate == SOX_UNSPEC)
375 || (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
376 || (ft->encoding.bits_per_sample == 0)) {
377 lsx_report("You must specify # channels, sample rate, signed/unsigned,");
378 lsx_report("and 8/16 on the command line.");
379 lsx_fail_errno(ft,SOX_EFMT,"Bogus AIFF file: no COMM section.");
380 return(SOX_EOF);
384 ssndsize /= bits >> 3;
386 /* Cope with 'sowt' CD tracks as read on Macs */
387 if (is_sowt)
388 ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes;
390 if (foundmark && !foundinstr) {
391 lsx_debug("Ignoring MARK chunk since no INSTR found.");
392 foundmark = 0;
394 if (!foundmark && foundinstr) {
395 lsx_debug("Ignoring INSTR chunk since no MARK found.");
396 foundinstr = 0;
398 if (foundmark && foundinstr) {
399 int i2;
400 int slbIndex = 0, sleIndex = 0;
401 int rlbIndex = 0, rleIndex = 0;
403 /* find our loop markers and save their marker indexes */
404 for(i2 = 0; i2 < nmarks; i2++) {
405 if(marks[i2].id == sustainLoopBegin)
406 slbIndex = i2;
407 if(marks[i2].id == sustainLoopEnd)
408 sleIndex = i2;
409 if(marks[i2].id == releaseLoopBegin)
410 rlbIndex = i2;
411 if(marks[i2].id == releaseLoopEnd)
412 rleIndex = i2;
415 ft->oob.instr.nloops = 0;
416 if (ft->oob.loops[0].type != 0) {
417 ft->oob.loops[0].start = marks[slbIndex].position;
418 ft->oob.loops[0].length =
419 marks[sleIndex].position - marks[slbIndex].position;
420 /* really the loop count should be infinite */
421 ft->oob.loops[0].count = 1;
422 ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[0].type;
423 ft->oob.instr.nloops++;
425 if (ft->oob.loops[1].type != 0) {
426 ft->oob.loops[1].start = marks[rlbIndex].position;
427 ft->oob.loops[1].length =
428 marks[rleIndex].position - marks[rlbIndex].position;
429 /* really the loop count should be infinite */
430 ft->oob.loops[1].count = 1;
431 ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[1].type;
432 ft->oob.instr.nloops++;
435 reportInstrument(ft);
437 return lsx_check_read_params(
438 ft, channels, rate, enc, bits, (uint64_t)ssndsize, sox_false);
441 /* print out the MIDI key allocations, loop points, directions etc */
442 static void reportInstrument(sox_format_t * ft)
444 unsigned loopNum;
446 if(ft->oob.instr.nloops > 0)
447 lsx_report("AIFF Loop markers:");
448 for(loopNum = 0; loopNum < ft->oob.instr.nloops; loopNum++) {
449 if (ft->oob.loops[loopNum].count) {
450 lsx_report("Loop %d: start: %6lu", loopNum, (unsigned long)ft->oob.loops[loopNum].start);
451 lsx_report(" end: %6lu",
452 (unsigned long)(ft->oob.loops[loopNum].start + ft->oob.loops[loopNum].length));
453 lsx_report(" count: %6d", ft->oob.loops[loopNum].count);
454 lsx_report(" type: ");
455 switch(ft->oob.loops[loopNum].type & ~SOX_LOOP_SUSTAIN_DECAY) {
456 case 0: lsx_report("off"); break;
457 case 1: lsx_report("forward"); break;
458 case 2: lsx_report("forward/backward"); break;
462 lsx_report("Unity MIDI Note: %d", ft->oob.instr.MIDInote);
463 lsx_report("Low MIDI Note: %d", ft->oob.instr.MIDIlow);
464 lsx_report("High MIDI Note: %d", ft->oob.instr.MIDIhi);
467 /* Process a text chunk, allocate memory, display it if verbose and return */
468 static int textChunk(char **text, char *chunkDescription, sox_format_t * ft)
470 uint32_t chunksize0;
471 size_t chunksize;
472 lsx_readdw(ft, &chunksize0);
473 chunksize = chunksize0;
475 /* allocate enough memory to hold the text including a terminating \0 */
476 if (chunksize != SOX_SIZE_MAX)
477 *text = lsx_malloc((size_t)chunksize+1);
478 else
479 *text = lsx_malloc((size_t)chunksize);
481 if (lsx_readbuf(ft, *text, (size_t) chunksize) != chunksize)
483 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
484 return(SOX_EOF);
486 if (chunksize != SOX_SIZE_MAX)
487 *(*text + chunksize) = '\0';
488 else
489 *(*text + chunksize-1) = '\0';
490 if (chunksize % 2)
492 /* Read past pad byte */
493 char c;
494 if (lsx_readbuf(ft, &c, (size_t)1) != 1)
496 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
497 return(SOX_EOF);
500 lsx_debug("%-10s \"%s\"", chunkDescription, *text);
501 return(SOX_SUCCESS);
504 /* Comment lengths are words, not double words, and we can have several, so
505 we use a special function, not textChunk().;
507 static int commentChunk(char **text, char *chunkDescription, sox_format_t * ft)
509 uint32_t chunksize;
510 unsigned short numComments;
511 uint32_t timeStamp;
512 unsigned short markerId;
513 unsigned short totalCommentLength = 0;
514 unsigned int totalReadLength = 0;
515 unsigned int commentIndex;
517 lsx_readdw(ft, &chunksize);
518 lsx_readw(ft, &numComments);
519 totalReadLength += 2; /* chunksize doesn't count */
520 for(commentIndex = 0; commentIndex < numComments; commentIndex++) {
521 unsigned short commentLength;
523 lsx_readdw(ft, &timeStamp);
524 lsx_readw(ft, &markerId);
525 lsx_readw(ft, &commentLength);
526 if (((size_t)totalCommentLength) + commentLength > USHRT_MAX) {
527 lsx_fail_errno(ft,SOX_EOF,"AIFF: Comment too long in %s header", chunkDescription);
528 return(SOX_EOF);
530 totalCommentLength += commentLength;
531 /* allocate enough memory to hold the text including a terminating \0 */
532 if(commentIndex == 0) {
533 *text = lsx_malloc((size_t) totalCommentLength + 1);
535 else {
536 *text = lsx_realloc(*text, (size_t) totalCommentLength + 1);
539 if (lsx_readbuf(ft, *text + totalCommentLength - commentLength, (size_t) commentLength) != commentLength) {
540 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
541 return(SOX_EOF);
543 *(*text + totalCommentLength) = '\0';
544 totalReadLength += totalCommentLength + 4 + 2 + 2; /* include header */
545 if (commentLength % 2) {
546 /* Read past pad byte */
547 char c;
548 if (lsx_readbuf(ft, &c, (size_t)1) != 1) {
549 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
550 return(SOX_EOF);
552 totalReadLength += 1;
555 lsx_debug("%-10s \"%s\"", chunkDescription, *text);
556 /* make sure we read the whole chunk */
557 if (totalReadLength < chunksize) {
558 size_t i;
559 char c;
560 for (i=0; i < chunksize - totalReadLength; i++ )
561 lsx_readbuf(ft, &c, (size_t)1);
563 return(SOX_SUCCESS);
566 int lsx_aiffstopread(sox_format_t * ft)
568 char buf[5];
569 uint32_t chunksize;
570 uint8_t trash;
572 if (!ft->seekable)
574 while (! lsx_eof(ft))
576 if (lsx_readbuf(ft, buf, (size_t)4) != 4)
577 break;
579 lsx_readdw(ft, &chunksize);
580 if (lsx_eof(ft))
581 break;
582 buf[4] = '\0';
583 lsx_warn("Ignoring AIFF tail chunk: `%s', %u bytes long",
584 buf, chunksize);
585 if (! strcmp(buf, "MARK") || ! strcmp(buf, "INST"))
586 lsx_warn(" You're stripping MIDI/loop info!");
587 while (chunksize-- > 0)
589 if (lsx_readb(ft, &trash) == SOX_EOF)
590 break;
594 return SOX_SUCCESS;
597 /* When writing, the header is supposed to contain the number of
598 samples and data bytes written.
599 Since we don't know how many samples there are until we're done,
600 we first write the header with an very large number,
601 and at the end we rewind the file and write the header again
602 with the right number. This only works if the file is seekable;
603 if it is not, the very large size remains in the header.
604 Strictly spoken this is not legal, but the playaiff utility
605 will still be able to play the resulting file. */
607 int lsx_aiffstartwrite(sox_format_t * ft)
609 int rc;
611 /* Needed because lsx_rawwrite() */
612 rc = lsx_rawstartwrite(ft);
613 if (rc)
614 return rc;
616 /* Compute the "very large number" so that a maximum number
617 of samples can be transmitted through a pipe without the
618 risk of causing overflow when calculating the number of bytes.
619 At 48 kHz, 16 bits stereo, this gives ~3 hours of audio.
620 Sorry, the AIFF format does not provide for an indefinite
621 number of samples. */
622 return(aiffwriteheader(ft, (uint64_t) 0x7f000000 / ((ft->encoding.bits_per_sample>>3)*ft->signal.channels)));
625 int lsx_aiffstopwrite(sox_format_t * ft)
627 /* If we've written an odd number of bytes, write a padding
628 NUL */
629 if (ft->olength % 2 == 1 && ft->encoding.bits_per_sample == 8 && ft->signal.channels == 1)
631 sox_sample_t buf = 0;
632 lsx_rawwrite(ft, &buf, (size_t) 1);
635 if (!ft->seekable)
637 lsx_fail_errno(ft,SOX_EOF,"Non-seekable file.");
638 return(SOX_EOF);
640 if (lsx_seeki(ft, (off_t)0, SEEK_SET) != 0)
642 lsx_fail_errno(ft,errno,"can't rewind output file to rewrite AIFF header");
643 return(SOX_EOF);
645 return(aiffwriteheader(ft, ft->olength / ft->signal.channels));
648 static int aiffwriteheader(sox_format_t * ft, uint64_t nframes)
650 int hsize =
651 8 /*COMM hdr*/ + 18 /*COMM chunk*/ +
652 8 /*SSND hdr*/ + 12 /*SSND chunk*/;
653 unsigned bits = 0;
654 unsigned i;
655 uint64_t size;
656 size_t padded_comment_size = 0, comment_size = 0;
657 size_t comment_chunk_size = 0;
658 char * comment = lsx_cat_comments(ft->oob.comments);
660 /* MARK and INST chunks */
661 if (ft->oob.instr.nloops) {
662 hsize += 8 /* MARK hdr */ + 2 + 16*ft->oob.instr.nloops;
663 hsize += 8 /* INST hdr */ + 20; /* INST chunk */
666 if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
667 ft->encoding.bits_per_sample == 8)
668 bits = 8;
669 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
670 ft->encoding.bits_per_sample == 16)
671 bits = 16;
672 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
673 ft->encoding.bits_per_sample == 24)
674 bits = 24;
675 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
676 ft->encoding.bits_per_sample == 32)
677 bits = 32;
678 else
680 lsx_fail_errno(ft,SOX_EFMT,"unsupported output encoding/size for AIFF header");
681 return(SOX_EOF);
684 /* COMT comment chunk -- holds comments text with a timestamp and marker id */
685 /* We calculate the comment_chunk_size if we will be writing a comment */
686 if (ft->oob.comments)
688 comment_size = strlen(comment);
689 /* Must put an even number of characters out.
690 * True 68k processors OS's seem to require this.
692 padded_comment_size = ((comment_size % 2) == 0) ?
693 comment_size : comment_size + 1;
694 /* one comment, timestamp, marker ID and text count */
695 comment_chunk_size = (2 + 4 + 2 + 2 + padded_comment_size);
696 hsize += 8 /* COMT hdr */ + comment_chunk_size;
699 lsx_writes(ft, "FORM"); /* IFF header */
700 /* file size */
701 size = hsize + nframes * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels;
702 if (size > UINT_MAX)
704 lsx_warn("file size too big for accurate AIFF header");
705 size = UINT_MAX;
707 lsx_writedw(ft, (unsigned)size);
708 lsx_writes(ft, "AIFF"); /* File type */
710 /* Now we write the COMT comment chunk using the precomputed sizes */
711 if (ft->oob.comments)
713 lsx_writes(ft, "COMT");
714 lsx_writedw(ft, (unsigned) comment_chunk_size);
716 /* one comment */
717 lsx_writew(ft, 1);
719 /* time stamp of comment, Unix knows of time from 1/1/1970,
720 Apple knows time from 1/1/1904 */
721 lsx_writedw(ft, (unsigned)((sox_globals.repeatable? 0 : time(NULL)) + 2082844800));
723 /* A marker ID of 0 indicates the comment is not associated
724 with a marker */
725 lsx_writew(ft, 0);
727 /* now write the count and the bytes of text */
728 lsx_writew(ft, (unsigned) padded_comment_size);
729 lsx_writes(ft, comment);
730 if (comment_size != padded_comment_size)
731 lsx_writes(ft, " ");
733 free(comment);
735 /* COMM chunk -- describes encoding (and #frames) */
736 lsx_writes(ft, "COMM");
737 lsx_writedw(ft, 18); /* COMM chunk size */
738 lsx_writew(ft, ft->signal.channels); /* nchannels */
739 lsx_writedw(ft, (unsigned) nframes); /* number of frames */
740 lsx_writew(ft, bits); /* sample width, in bits */
741 write_ieee_extended(ft, (double)ft->signal.rate);
743 /* MARK chunk -- set markers */
744 if (ft->oob.instr.nloops) {
745 lsx_writes(ft, "MARK");
746 if (ft->oob.instr.nloops > 2)
747 ft->oob.instr.nloops = 2;
748 lsx_writedw(ft, 2 + 16u*ft->oob.instr.nloops);
749 lsx_writew(ft, ft->oob.instr.nloops);
751 for(i = 0; i < ft->oob.instr.nloops; i++) {
752 unsigned start = ft->oob.loops[i].start > UINT_MAX
753 ? UINT_MAX
754 : ft->oob.loops[i].start;
755 unsigned end = ft->oob.loops[i].start + ft->oob.loops[i].length > UINT_MAX
756 ? UINT_MAX
757 : ft->oob.loops[i].start + ft->oob.loops[i].length;
758 lsx_writew(ft, i + 1);
759 lsx_writedw(ft, start);
760 lsx_writeb(ft, 0);
761 lsx_writeb(ft, 0);
762 lsx_writew(ft, i*2 + 1);
763 lsx_writedw(ft, end);
764 lsx_writeb(ft, 0);
765 lsx_writeb(ft, 0);
768 lsx_writes(ft, "INST");
769 lsx_writedw(ft, 20);
770 /* random MIDI shit that we default on */
771 lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDInote);
772 lsx_writeb(ft, 0); /* detune */
773 lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDIlow);
774 lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDIhi);
775 lsx_writeb(ft, 1); /* low velocity */
776 lsx_writeb(ft, 127); /* hi velocity */
777 lsx_writew(ft, 0); /* gain */
779 /* sustain loop */
780 lsx_writew(ft, ft->oob.loops[0].type);
781 lsx_writew(ft, 1); /* marker 1 */
782 lsx_writew(ft, 3); /* marker 3 */
783 /* release loop, if there */
784 if (ft->oob.instr.nloops == 2) {
785 lsx_writew(ft, ft->oob.loops[1].type);
786 lsx_writew(ft, 2); /* marker 2 */
787 lsx_writew(ft, 4); /* marker 4 */
788 } else {
789 lsx_writew(ft, 0); /* no release loop */
790 lsx_writew(ft, 0);
791 lsx_writew(ft, 0);
795 /* SSND chunk -- describes data */
796 lsx_writes(ft, "SSND");
797 /* chunk size */
798 lsx_writedw(ft, (unsigned) (8 + nframes * ft->signal.channels * (ft->encoding.bits_per_sample >> 3)));
799 lsx_writedw(ft, 0); /* offset */
800 lsx_writedw(ft, 0); /* block size */
801 return(SOX_SUCCESS);
804 int lsx_aifcstartwrite(sox_format_t * ft)
806 int rc;
808 /* Needed because lsx_rawwrite() */
809 rc = lsx_rawstartwrite(ft);
810 if (rc)
811 return rc;
813 /* Compute the "very large number" so that a maximum number
814 of samples can be transmitted through a pipe without the
815 risk of causing overflow when calculating the number of bytes.
816 At 48 kHz, 16 bits stereo, this gives ~3 hours of music.
817 Sorry, the AIFC format does not provide for an "infinite"
818 number of samples. */
819 return(aifcwriteheader(ft, (uint64_t) 0x7f000000 / ((ft->encoding.bits_per_sample >> 3)*ft->signal.channels)));
822 int lsx_aifcstopwrite(sox_format_t * ft)
824 /* If we've written an odd number of bytes, write a padding
825 NUL */
826 if (ft->olength % 2 == 1 && ft->encoding.bits_per_sample == 8 && ft->signal.channels == 1)
828 sox_sample_t buf = 0;
829 lsx_rawwrite(ft, &buf, (size_t) 1);
832 if (!ft->seekable)
834 lsx_fail_errno(ft,SOX_EOF,"Non-seekable file.");
835 return(SOX_EOF);
837 if (lsx_seeki(ft, (off_t)0, SEEK_SET) != 0)
839 lsx_fail_errno(ft,errno,"can't rewind output file to rewrite AIFC header");
840 return(SOX_EOF);
842 return(aifcwriteheader(ft, ft->olength / ft->signal.channels));
845 static int aifcwriteheader(sox_format_t * ft, uint64_t nframes)
847 unsigned hsize;
848 unsigned bits = 0;
849 uint64_t size;
850 char *ctype = NULL, *cname = NULL;
851 unsigned cname_len = 0, comm_len = 0, comm_padding = 0;
853 if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
854 ft->encoding.bits_per_sample == 8)
855 bits = 8;
856 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
857 ft->encoding.bits_per_sample == 16)
858 bits = 16;
859 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
860 ft->encoding.bits_per_sample == 24)
861 bits = 24;
862 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
863 ft->encoding.bits_per_sample == 32)
864 bits = 32;
865 else if (ft->encoding.encoding == SOX_ENCODING_FLOAT &&
866 ft->encoding.bits_per_sample == 32)
867 bits = 32;
868 else if (ft->encoding.encoding == SOX_ENCODING_FLOAT &&
869 ft->encoding.bits_per_sample == 64)
870 bits = 64;
871 else
873 lsx_fail_errno(ft,SOX_EFMT,"unsupported output encoding/size for AIFC header");
874 return(SOX_EOF);
877 /* calculate length of COMM chunk (without header) */
878 switch (ft->encoding.encoding) {
879 case SOX_ENCODING_SIGN2:
880 ctype = "NONE";
881 cname = "not compressed";
882 break;
883 case SOX_ENCODING_FLOAT:
884 if (bits == 32) {
885 ctype = "fl32";
886 cname = "32-bit floating point";
887 } else {
888 ctype = "fl64";
889 cname = "64-bit floating point";
891 break;
892 default: /* can't happen */
893 break;
895 cname_len = strlen(cname);
896 comm_len = 18+4+1+cname_len;
897 comm_padding = comm_len%2;
899 hsize = 12 /*FVER*/ + 8 /*COMM hdr*/ + comm_len+comm_padding /*COMM chunk*/ +
900 8 /*SSND hdr*/ + 12 /*SSND chunk*/;
902 lsx_writes(ft, "FORM"); /* IFF header */
903 /* file size */
904 size = hsize + nframes * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels;
905 if (size > UINT_MAX)
907 lsx_warn("file size too big for accurate AIFC header");
908 size = UINT_MAX;
910 lsx_writedw(ft, (unsigned)size);
911 lsx_writes(ft, "AIFC"); /* File type */
913 /* FVER chunk */
914 lsx_writes(ft, "FVER");
915 lsx_writedw(ft, 4); /* FVER chunk size */
916 lsx_writedw(ft, 0xa2805140); /* version_date(May23,1990,2:40pm) */
918 /* COMM chunk -- describes encoding (and #frames) */
919 lsx_writes(ft, "COMM");
920 lsx_writedw(ft, comm_len+comm_padding); /* COMM chunk size */
921 lsx_writew(ft, ft->signal.channels); /* nchannels */
922 lsx_writedw(ft, (unsigned) nframes); /* number of frames */
923 lsx_writew(ft, bits); /* sample width, in bits */
924 write_ieee_extended(ft, (double)ft->signal.rate);
926 lsx_writes(ft, ctype); /*compression_type*/
927 lsx_writeb(ft, cname_len);
928 lsx_writes(ft, cname);
929 if (comm_padding)
930 lsx_writeb(ft, 0);
932 /* SSND chunk -- describes data */
933 lsx_writes(ft, "SSND");
934 /* chunk size */
935 lsx_writedw(ft, (unsigned) (8 + nframes * ft->signal.channels * (ft->encoding.bits_per_sample >> 3)));
936 lsx_writedw(ft, 0); /* offset */
937 lsx_writedw(ft, 0); /* block size */
939 /* Any Private chunks shall appear after the required chunks (FORM,FVER,COMM,SSND) */
940 return(SOX_SUCCESS);
943 static double read_ieee_extended(sox_format_t * ft)
945 unsigned char buf[10];
946 if (lsx_readbuf(ft, buf, (size_t)10) != 10)
948 lsx_fail_errno(ft,SOX_EOF,"EOF while reading IEEE extended number");
949 return(SOX_EOF);
951 return ConvertFromIeeeExtended(buf);
954 static void write_ieee_extended(sox_format_t * ft, double x)
956 char buf[10];
957 ConvertToIeeeExtended(x, buf);
958 lsx_debug_more("converted %g to %o %o %o %o %o %o %o %o %o %o",
960 buf[0], buf[1], buf[2], buf[3], buf[4],
961 buf[5], buf[6], buf[7], buf[8], buf[9]);
962 (void)lsx_writebuf(ft, buf, (size_t) 10);
967 * C O N V E R T T O I E E E E X T E N D E D
970 /* Copyright (C) 1988-1991 Apple Computer, Inc.
972 * All rights reserved.
974 * Warranty Information
975 * Even though Apple has reviewed this software, Apple makes no warranty
976 * or representation, either express or implied, with respect to this
977 * software, its quality, accuracy, merchantability, or fitness for a
978 * particular purpose. As a result, this software is provided "as is,"
979 * and you, its user, are assuming the entire risk as to its quality
980 * and accuracy.
982 * Machine-independent I/O routines for IEEE floating-point numbers.
984 * NaN's and infinities are converted to HUGE_VAL, which
985 * happens to be infinity on IEEE machines. Unfortunately, it is
986 * impossible to preserve NaN's in a machine-independent way.
987 * Infinities are, however, preserved on IEEE machines.
989 * These routines have been tested on the following machines:
990 * Apple Macintosh, MPW 3.1 C compiler
991 * Apple Macintosh, THINK C compiler
992 * Silicon Graphics IRIS, MIPS compiler
993 * Cray X/MP and Y/MP
994 * Digital Equipment VAX
997 * Implemented by Malcolm Slaney and Ken Turkowski.
999 * Malcolm Slaney contributions during 1988-1990 include big- and little-
1000 * endian file I/O, conversion to and from Motorola's extended 80-bit
1001 * floating-point format, and conversions to and from IEEE single-
1002 * precision floating-point format.
1004 * In 1991, Ken Turkowski implemented the conversions to and from
1005 * IEEE double-precision format, added more precision to the extended
1006 * conversions, and accommodated conversions involving +/- infinity,
1007 * NaN's, and denormalized numbers.
1010 #define FloatToUnsigned(f) ((uint32_t)(((int32_t)(f - 2147483648.0)) + 2147483647) + 1)
1012 static void ConvertToIeeeExtended(double num, char *bytes)
1014 int sign;
1015 int expon;
1016 double fMant, fsMant;
1017 uint32_t hiMant, loMant;
1019 if (num < 0) {
1020 sign = 0x8000;
1021 num *= -1;
1022 } else {
1023 sign = 0;
1026 if (num == 0) {
1027 expon = 0; hiMant = 0; loMant = 0;
1029 else {
1030 fMant = frexp(num, &expon);
1031 if ((expon > 16384) || !(fMant < 1)) { /* Infinity or NaN */
1032 expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */
1034 else { /* Finite */
1035 expon += 16382;
1036 if (expon < 0) { /* denormalized */
1037 fMant = ldexp(fMant, expon);
1038 expon = 0;
1040 expon |= sign;
1041 fMant = ldexp(fMant, 32);
1042 fsMant = floor(fMant);
1043 hiMant = FloatToUnsigned(fsMant);
1044 fMant = ldexp(fMant - fsMant, 32);
1045 fsMant = floor(fMant);
1046 loMant = FloatToUnsigned(fsMant);
1050 bytes[0] = expon >> 8;
1051 bytes[1] = expon;
1052 bytes[2] = hiMant >> 24;
1053 bytes[3] = hiMant >> 16;
1054 bytes[4] = hiMant >> 8;
1055 bytes[5] = hiMant;
1056 bytes[6] = loMant >> 24;
1057 bytes[7] = loMant >> 16;
1058 bytes[8] = loMant >> 8;
1059 bytes[9] = loMant;
1064 * C O N V E R T F R O M I E E E E X T E N D E D
1068 * Copyright (C) 1988-1991 Apple Computer, Inc.
1070 * All rights reserved.
1072 * Warranty Information
1073 * Even though Apple has reviewed this software, Apple makes no warranty
1074 * or representation, either express or implied, with respect to this
1075 * software, its quality, accuracy, merchantability, or fitness for a
1076 * particular purpose. As a result, this software is provided "as is,"
1077 * and you, its user, are assuming the entire risk as to its quality
1078 * and accuracy.
1080 * This code may be used and freely distributed as long as it includes
1081 * this copyright notice and the above warranty information.
1083 * Machine-independent I/O routines for IEEE floating-point numbers.
1085 * NaN's and infinities are converted to HUGE_VAL, which
1086 * happens to be infinity on IEEE machines. Unfortunately, it is
1087 * impossible to preserve NaN's in a machine-independent way.
1088 * Infinities are, however, preserved on IEEE machines.
1090 * These routines have been tested on the following machines:
1091 * Apple Macintosh, MPW 3.1 C compiler
1092 * Apple Macintosh, THINK C compiler
1093 * Silicon Graphics IRIS, MIPS compiler
1094 * Cray X/MP and Y/MP
1095 * Digital Equipment VAX
1098 * Implemented by Malcolm Slaney and Ken Turkowski.
1100 * Malcolm Slaney contributions during 1988-1990 include big- and little-
1101 * endian file I/O, conversion to and from Motorola's extended 80-bit
1102 * floating-point format, and conversions to and from IEEE single-
1103 * precision floating-point format.
1105 * In 1991, Ken Turkowski implemented the conversions to and from
1106 * IEEE double-precision format, added more precision to the extended
1107 * conversions, and accommodated conversions involving +/- infinity,
1108 * NaN's, and denormalized numbers.
1111 #define UnsignedToFloat(u) (((double)((int32_t)(u - 2147483647 - 1))) + 2147483648.0)
1113 /****************************************************************
1114 * Extended precision IEEE floating-point conversion routine.
1115 ****************************************************************/
1117 static double ConvertFromIeeeExtended(unsigned char *bytes)
1119 double f;
1120 int expon;
1121 uint32_t hiMant, loMant;
1123 expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
1124 hiMant = ((uint32_t)(bytes[2] & 0xFF) << 24)
1125 | ((uint32_t)(bytes[3] & 0xFF) << 16)
1126 | ((uint32_t)(bytes[4] & 0xFF) << 8)
1127 | ((uint32_t)(bytes[5] & 0xFF));
1128 loMant = ((uint32_t)(bytes[6] & 0xFF) << 24)
1129 | ((uint32_t)(bytes[7] & 0xFF) << 16)
1130 | ((uint32_t)(bytes[8] & 0xFF) << 8)
1131 | ((uint32_t)(bytes[9] & 0xFF));
1133 if (expon == 0 && hiMant == 0 && loMant == 0) {
1134 f = 0;
1136 else {
1137 if (expon == 0x7FFF) { /* Infinity or NaN */
1138 f = HUGE_VAL;
1140 else {
1141 expon -= 16383;
1142 f = ldexp(UnsignedToFloat(hiMant), expon-=31);
1143 f += ldexp(UnsignedToFloat(loMant), expon-=32);
1147 if (bytes[0] & 0x80)
1148 return -f;
1149 else
1150 return f;