README.osx wasn't easily readable in Finder. Revert back to
[sox.git] / src / aiff.c
blobbcccd8264d46f185deb5cb5ddc54fbc609c3385f
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 *, size_t);
30 static int aifcwriteheader(sox_format_t *, size_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 uint32_t frames;
45 unsigned short bits = 0;
46 double rate = 0.0;
47 uint32_t offset = 0;
48 uint32_t blocksize = 0;
49 int foundcomm = 0, foundmark = 0, foundinstr = 0, is_sowt = 0;
50 struct mark {
51 unsigned short id;
52 uint32_t position;
53 char name[40];
54 } marks[32];
55 unsigned short looptype;
56 int i, j;
57 unsigned short nmarks = 0;
58 unsigned short sustainLoopBegin = 0, sustainLoopEnd = 0,
59 releaseLoopBegin = 0, releaseLoopEnd = 0;
60 off_t seekto = 0;
61 size_t ssndsize = 0;
62 char *annotation;
63 char *author;
64 char *comment = NULL;
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 (ssndsize > 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, "NONE", (size_t)4) != 0 &&
115 strncmp(buf, "twos", (size_t)4) != 0) {
116 buf[4] = 0;
117 lsx_fail_errno(ft,SOX_EHDR,"AIFC files that contain compressed data are not supported: %s",buf);
118 return(SOX_EOF);
121 while(chunksize-- > 0)
122 lsx_readb(ft, &trash8);
123 foundcomm = 1;
125 else if (strncmp(buf, "SSND", (size_t)4) == 0) {
126 /* SSND chunk */
127 lsx_readdw(ft, &chunksize);
128 lsx_readdw(ft, &offset);
129 lsx_readdw(ft, &blocksize);
130 chunksize -= 8;
131 ssndsize = chunksize;
132 /* word-align chunksize in case it wasn't
133 * done by writing application already.
135 chunksize += (chunksize % 2);
136 /* if can't seek, just do sound now */
137 if (!ft->seekable)
138 break;
139 /* else, seek to end of sound and hunt for more */
140 seekto = lsx_tell(ft);
141 lsx_seeki(ft, (off_t)chunksize, SEEK_CUR);
143 else if (strncmp(buf, "MARK", (size_t)4) == 0) {
144 /* MARK chunk */
145 lsx_readdw(ft, &chunksize);
146 if (chunksize >= sizeof(nmarks)) {
147 lsx_readw(ft, &nmarks);
148 chunksize -= sizeof(nmarks);
150 else nmarks = 0;
152 /* Some programs like to always have a MARK chunk
153 * but will set number of marks to 0 and force
154 * software to detect and ignore it.
156 if (nmarks == 0)
157 foundmark = 0;
158 else
159 foundmark = 1;
161 /* Make sure its not larger then we support */
162 if (nmarks > 32)
163 nmarks = 32;
165 for(i = 0; i < nmarks && chunksize; i++) {
166 unsigned char len, read_len, tmp_c;
168 if (chunksize < 6)
169 break;
170 lsx_readw(ft, &(marks[i].id));
171 lsx_readdw(ft, &(marks[i].position));
172 chunksize -= 6;
173 /* If error reading length then
174 * don't try to read more bytes
175 * based on that value.
177 if (lsx_readb(ft, &len) != SOX_SUCCESS)
178 break;
179 --chunksize;
180 if (len > chunksize)
181 len = chunksize;
182 read_len = len;
183 if (read_len > 39)
184 read_len = 39;
185 for(j = 0; j < len && chunksize; j++) {
186 lsx_readb(ft, &tmp_c);
187 if (j < read_len)
188 marks[i].name[j] = tmp_c;
189 chunksize--;
191 marks[i].name[read_len] = 0;
192 if ((len & 1) == 0 && chunksize) {
193 chunksize--;
194 lsx_readb(ft, &trash8);
197 /* HA HA! Sound Designer (and others) makes */
198 /* bogus files. It spits out bogus chunksize */
199 /* for MARK field */
200 while(chunksize-- > 0)
201 lsx_readb(ft, &trash8);
203 else if (strncmp(buf, "INST", (size_t)4) == 0) {
204 /* INST chunk */
205 lsx_readdw(ft, &chunksize);
206 lsx_readsb(ft, &(ft->oob.instr.MIDInote));
207 lsx_readb(ft, &trash8);
208 lsx_readsb(ft, &(ft->oob.instr.MIDIlow));
209 lsx_readsb(ft, &(ft->oob.instr.MIDIhi));
210 /* Low velocity */
211 lsx_readb(ft, &trash8);
212 /* Hi velocity */
213 lsx_readb(ft, &trash8);
214 lsx_readw(ft, &trash16);/* gain */
215 lsx_readw(ft, &looptype); /* sustain loop */
216 ft->oob.loops[0].type = looptype;
217 lsx_readw(ft, &sustainLoopBegin); /* begin marker */
218 lsx_readw(ft, &sustainLoopEnd); /* end marker */
219 lsx_readw(ft, &looptype); /* release loop */
220 ft->oob.loops[1].type = looptype;
221 lsx_readw(ft, &releaseLoopBegin); /* begin marker */
222 lsx_readw(ft, &releaseLoopEnd); /* end marker */
224 foundinstr = 1;
226 else if (strncmp(buf, "APPL", (size_t)4) == 0) {
227 lsx_readdw(ft, &chunksize);
228 /* word-align chunksize in case it wasn't
229 * done by writing application already.
231 chunksize += (chunksize % 2);
232 while(chunksize-- > 0)
233 lsx_readb(ft, &trash8);
235 else if (strncmp(buf, "ALCH", (size_t)4) == 0) {
236 /* I think this is bogus and gets grabbed by APPL */
237 /* INST chunk */
238 lsx_readdw(ft, &trash32); /* ENVS - jeez! */
239 lsx_readdw(ft, &chunksize);
240 while(chunksize-- > 0)
241 lsx_readb(ft, &trash8);
243 else if (strncmp(buf, "ANNO", (size_t)4) == 0) {
244 rc = textChunk(&annotation, "Annotation:", ft);
245 if (rc) {
246 /* Fail already called in function */
247 return(SOX_EOF);
249 if (annotation)
250 sox_append_comments(&ft->oob.comments, annotation);
251 free(annotation);
253 else if (strncmp(buf, "COMT", (size_t)4) == 0) {
254 rc = commentChunk(&comment, "Comment:", ft);
255 if (rc) {
256 /* Fail already called in function */
257 return(SOX_EOF);
259 if (comment)
260 sox_append_comments(&ft->oob.comments, comment);
261 free(comment);
263 else if (strncmp(buf, "AUTH", (size_t)4) == 0) {
264 /* Author chunk */
265 rc = textChunk(&author, "Author:", ft);
266 if (rc) {
267 /* Fail already called in function */
268 return(SOX_EOF);
270 free(author);
272 else if (strncmp(buf, "NAME", (size_t)4) == 0) {
273 /* Name chunk */
274 rc = textChunk(&nametext, "Name:", ft);
275 if (rc) {
276 /* Fail already called in function */
277 return(SOX_EOF);
279 free(nametext);
281 else if (strncmp(buf, "(c) ", (size_t)4) == 0) {
282 /* Copyright chunk */
283 rc = textChunk(&copyright, "Copyright:", ft);
284 if (rc) {
285 /* Fail already called in function */
286 return(SOX_EOF);
288 free(copyright);
290 else {
291 if (lsx_eof(ft))
292 break;
293 buf[4] = 0;
294 lsx_debug("AIFFstartread: ignoring `%s' chunk", buf);
295 lsx_readdw(ft, &chunksize);
296 if (lsx_eof(ft))
297 break;
298 /* Skip the chunk using lsx_readb() so we may read
299 from a pipe */
300 while (chunksize-- > 0) {
301 if (lsx_readb(ft, &trash8) == SOX_EOF)
302 break;
305 if (lsx_eof(ft))
306 break;
310 * if a pipe, we lose all chunks after sound.
311 * Like, say, instrument loops.
313 if (ft->seekable) {
314 if (seekto > 0)
315 lsx_seeki(ft, seekto, SEEK_SET);
316 else {
317 lsx_fail_errno(ft,SOX_EOF,"AIFF: no sound data on input file");
318 return(SOX_EOF);
321 /* SSND chunk just read */
322 if (blocksize != 0)
323 lsx_warn("AIFF header has invalid blocksize. Ignoring but expect a premature EOF");
325 ssndsize -= offset;
326 while (offset-- > 0) {
327 if (lsx_readb(ft, &trash8) == SOX_EOF) {
328 lsx_fail_errno(ft,errno,"unexpected EOF while skipping AIFF offset");
329 return(SOX_EOF);
333 if (foundcomm) {
334 if (ft->encoding.encoding != SOX_ENCODING_UNKNOWN && ft->encoding.encoding != SOX_ENCODING_SIGN2)
335 lsx_report("AIFF only supports signed data. Forcing to signed.");
336 ft->encoding.encoding = SOX_ENCODING_SIGN2;
337 if (bits <= 8) bits = 8;
338 else if (bits <= 16) bits = 16;
339 else if (bits <= 24) bits = 24;
340 else if (bits <= 32) bits = 32;
341 else {
342 lsx_fail_errno(ft,SOX_EFMT,"unsupported sample size in AIFF header: %d", bits);
343 return(SOX_EOF);
345 } else {
346 if ((ft->signal.channels == SOX_UNSPEC)
347 || (ft->signal.rate == SOX_UNSPEC)
348 || (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
349 || (ft->encoding.bits_per_sample == 0)) {
350 lsx_report("You must specify # channels, sample rate, signed/unsigned,");
351 lsx_report("and 8/16 on the command line.");
352 lsx_fail_errno(ft,SOX_EFMT,"Bogus AIFF file: no COMM section.");
353 return(SOX_EOF);
357 ssndsize /= bits >> 3;
359 /* Cope with 'sowt' CD tracks as read on Macs */
360 if (is_sowt)
361 ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes;
363 if (foundmark && !foundinstr) {
364 lsx_debug("Ignoring MARK chunk since no INSTR found.");
365 foundmark = 0;
367 if (!foundmark && foundinstr) {
368 lsx_debug("Ignoring INSTR chunk since no MARK found.");
369 foundinstr = 0;
371 if (foundmark && foundinstr) {
372 int i;
373 int slbIndex = 0, sleIndex = 0;
374 int rlbIndex = 0, rleIndex = 0;
376 /* find our loop markers and save their marker indexes */
377 for(i = 0; i < nmarks; i++) {
378 if(marks[i].id == sustainLoopBegin)
379 slbIndex = i;
380 if(marks[i].id == sustainLoopEnd)
381 sleIndex = i;
382 if(marks[i].id == releaseLoopBegin)
383 rlbIndex = i;
384 if(marks[i].id == releaseLoopEnd)
385 rleIndex = i;
388 ft->oob.instr.nloops = 0;
389 if (ft->oob.loops[0].type != 0) {
390 ft->oob.loops[0].start = marks[slbIndex].position;
391 ft->oob.loops[0].length =
392 marks[sleIndex].position - marks[slbIndex].position;
393 /* really the loop count should be infinite */
394 ft->oob.loops[0].count = 1;
395 ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[0].type;
396 ft->oob.instr.nloops++;
398 if (ft->oob.loops[1].type != 0) {
399 ft->oob.loops[1].start = marks[rlbIndex].position;
400 ft->oob.loops[1].length =
401 marks[rleIndex].position - marks[rlbIndex].position;
402 /* really the loop count should be infinite */
403 ft->oob.loops[1].count = 1;
404 ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[1].type;
405 ft->oob.instr.nloops++;
408 reportInstrument(ft);
410 return lsx_check_read_params(
411 ft, channels, rate, SOX_ENCODING_SIGN2, bits, (off_t)ssndsize, sox_false);
414 /* print out the MIDI key allocations, loop points, directions etc */
415 static void reportInstrument(sox_format_t * ft)
417 unsigned loopNum;
419 if(ft->oob.instr.nloops > 0)
420 lsx_report("AIFF Loop markers:");
421 for(loopNum = 0; loopNum < ft->oob.instr.nloops; loopNum++) {
422 if (ft->oob.loops[loopNum].count) {
423 lsx_report("Loop %d: start: %6lu", loopNum, (unsigned long)ft->oob.loops[loopNum].start);
424 lsx_report(" end: %6lu",
425 (unsigned long)(ft->oob.loops[loopNum].start + ft->oob.loops[loopNum].length));
426 lsx_report(" count: %6d", ft->oob.loops[loopNum].count);
427 lsx_report(" type: ");
428 switch(ft->oob.loops[loopNum].type & ~SOX_LOOP_SUSTAIN_DECAY) {
429 case 0: lsx_report("off"); break;
430 case 1: lsx_report("forward"); break;
431 case 2: lsx_report("forward/backward"); break;
435 lsx_report("Unity MIDI Note: %d", ft->oob.instr.MIDInote);
436 lsx_report("Low MIDI Note: %d", ft->oob.instr.MIDIlow);
437 lsx_report("High MIDI Note: %d", ft->oob.instr.MIDIhi);
440 /* Process a text chunk, allocate memory, display it if verbose and return */
441 static int textChunk(char **text, char *chunkDescription, sox_format_t * ft)
443 uint32_t chunksize;
444 lsx_readdw(ft, &chunksize);
445 /* allocate enough memory to hold the text including a terminating \0 */
446 *text = lsx_malloc((size_t) chunksize + 1);
447 if (lsx_readbuf(ft, *text, (size_t) chunksize) != chunksize)
449 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
450 return(SOX_EOF);
452 *(*text + chunksize) = '\0';
453 if (chunksize % 2)
455 /* Read past pad byte */
456 char c;
457 if (lsx_readbuf(ft, &c, (size_t)1) != 1)
459 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
460 return(SOX_EOF);
463 lsx_debug("%-10s \"%s\"", chunkDescription, *text);
464 return(SOX_SUCCESS);
467 /* Comment lengths are words, not double words, and we can have several, so
468 we use a special function, not textChunk().;
470 static int commentChunk(char **text, char *chunkDescription, sox_format_t * ft)
472 uint32_t chunksize;
473 unsigned short numComments;
474 uint32_t timeStamp;
475 unsigned short markerId;
476 unsigned short totalCommentLength = 0;
477 unsigned int totalReadLength = 0;
478 unsigned int commentIndex;
480 lsx_readdw(ft, &chunksize);
481 lsx_readw(ft, &numComments);
482 totalReadLength += 2; /* chunksize doesn't count */
483 for(commentIndex = 0; commentIndex < numComments; commentIndex++) {
484 unsigned short commentLength;
486 lsx_readdw(ft, &timeStamp);
487 lsx_readw(ft, &markerId);
488 lsx_readw(ft, &commentLength);
489 if (((size_t)totalCommentLength) + commentLength > USHRT_MAX) {
490 lsx_fail_errno(ft,SOX_EOF,"AIFF: Comment too long in %s header", chunkDescription);
491 return(SOX_EOF);
493 totalCommentLength += commentLength;
494 /* allocate enough memory to hold the text including a terminating \0 */
495 if(commentIndex == 0) {
496 *text = lsx_malloc((size_t) totalCommentLength + 1);
498 else {
499 *text = lsx_realloc(*text, (size_t) totalCommentLength + 1);
502 if (lsx_readbuf(ft, *text + totalCommentLength - commentLength, (size_t) commentLength) != commentLength) {
503 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
504 return(SOX_EOF);
506 *(*text + totalCommentLength) = '\0';
507 totalReadLength += totalCommentLength + 4 + 2 + 2; /* include header */
508 if (commentLength % 2) {
509 /* Read past pad byte */
510 char c;
511 if (lsx_readbuf(ft, &c, (size_t)1) != 1) {
512 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
513 return(SOX_EOF);
515 totalReadLength += 1;
518 lsx_debug("%-10s \"%s\"", chunkDescription, *text);
519 /* make sure we read the whole chunk */
520 if (totalReadLength < chunksize) {
521 size_t i;
522 char c;
523 for (i=0; i < chunksize - totalReadLength; i++ )
524 lsx_readbuf(ft, &c, (size_t)1);
526 return(SOX_SUCCESS);
529 int lsx_aiffstopread(sox_format_t * ft)
531 char buf[5];
532 uint32_t chunksize;
533 uint8_t trash;
535 if (!ft->seekable)
537 while (! lsx_eof(ft))
539 if (lsx_readbuf(ft, buf, (size_t)4) != 4)
540 break;
542 lsx_readdw(ft, &chunksize);
543 if (lsx_eof(ft))
544 break;
545 buf[4] = '\0';
546 lsx_warn("Ignoring AIFF tail chunk: `%s', %u bytes long",
547 buf, chunksize);
548 if (! strcmp(buf, "MARK") || ! strcmp(buf, "INST"))
549 lsx_warn(" You're stripping MIDI/loop info!");
550 while (chunksize-- > 0)
552 if (lsx_readb(ft, &trash) == SOX_EOF)
553 break;
557 return SOX_SUCCESS;
560 /* When writing, the header is supposed to contain the number of
561 samples and data bytes written.
562 Since we don't know how many samples there are until we're done,
563 we first write the header with an very large number,
564 and at the end we rewind the file and write the header again
565 with the right number. This only works if the file is seekable;
566 if it is not, the very large size remains in the header.
567 Strictly spoken this is not legal, but the playaiff utility
568 will still be able to play the resulting file. */
570 int lsx_aiffstartwrite(sox_format_t * ft)
572 int rc;
574 /* Needed because lsx_rawwrite() */
575 rc = lsx_rawstartwrite(ft);
576 if (rc)
577 return rc;
579 /* Compute the "very large number" so that a maximum number
580 of samples can be transmitted through a pipe without the
581 risk of causing overflow when calculating the number of bytes.
582 At 48 kHz, 16 bits stereo, this gives ~3 hours of audio.
583 Sorry, the AIFF format does not provide for an indefinite
584 number of samples. */
585 return(aiffwriteheader(ft, (size_t) 0x7f000000 / ((ft->encoding.bits_per_sample>>3)*ft->signal.channels)));
588 int lsx_aiffstopwrite(sox_format_t * ft)
590 /* If we've written an odd number of bytes, write a padding
591 NUL */
592 if (ft->olength % 2 == 1 && ft->encoding.bits_per_sample == 8 && ft->signal.channels == 1)
594 sox_sample_t buf = 0;
595 lsx_rawwrite(ft, &buf, (size_t) 1);
598 if (!ft->seekable)
600 lsx_fail_errno(ft,SOX_EOF,"Non-seekable file.");
601 return(SOX_EOF);
603 if (lsx_seeki(ft, (off_t)0, SEEK_SET) != 0)
605 lsx_fail_errno(ft,errno,"can't rewind output file to rewrite AIFF header");
606 return(SOX_EOF);
608 return(aiffwriteheader(ft, ft->olength / ft->signal.channels));
611 static int aiffwriteheader(sox_format_t * ft, size_t nframes)
613 int hsize =
614 8 /*COMM hdr*/ + 18 /*COMM chunk*/ +
615 8 /*SSND hdr*/ + 12 /*SSND chunk*/;
616 unsigned bits = 0;
617 unsigned i;
618 size_t padded_comment_size = 0, comment_size = 0;
619 size_t comment_chunk_size = 0;
620 char * comment = lsx_cat_comments(ft->oob.comments);
622 /* MARK and INST chunks */
623 if (ft->oob.instr.nloops) {
624 hsize += 8 /* MARK hdr */ + 2 + 16*ft->oob.instr.nloops;
625 hsize += 8 /* INST hdr */ + 20; /* INST chunk */
628 if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
629 ft->encoding.bits_per_sample == 8)
630 bits = 8;
631 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
632 ft->encoding.bits_per_sample == 16)
633 bits = 16;
634 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
635 ft->encoding.bits_per_sample == 24)
636 bits = 24;
637 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
638 ft->encoding.bits_per_sample == 32)
639 bits = 32;
640 else
642 lsx_fail_errno(ft,SOX_EFMT,"unsupported output encoding/size for AIFF header");
643 return(SOX_EOF);
646 /* COMT comment chunk -- holds comments text with a timestamp and marker id */
647 /* We calculate the comment_chunk_size if we will be writing a comment */
648 if (ft->oob.comments)
650 comment_size = strlen(comment);
651 /* Must put an even number of characters out.
652 * True 68k processors OS's seem to require this.
654 padded_comment_size = ((comment_size % 2) == 0) ?
655 comment_size : comment_size + 1;
656 /* one comment, timestamp, marker ID and text count */
657 comment_chunk_size = (2 + 4 + 2 + 2 + padded_comment_size);
658 hsize += 8 /* COMT hdr */ + comment_chunk_size;
661 lsx_writes(ft, "FORM"); /* IFF header */
662 /* file size */
663 lsx_writedw(ft, (unsigned) (hsize + nframes * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels));
664 lsx_writes(ft, "AIFF"); /* File type */
666 /* Now we write the COMT comment chunk using the precomputed sizes */
667 if (ft->oob.comments)
669 lsx_writes(ft, "COMT");
670 lsx_writedw(ft, (unsigned) comment_chunk_size);
672 /* one comment */
673 lsx_writew(ft, 1);
675 /* time stamp of comment, Unix knows of time from 1/1/1970,
676 Apple knows time from 1/1/1904 */
677 lsx_writedw(ft, (unsigned)((sox_globals.repeatable? 0 : time(NULL)) + 2082844800));
679 /* A marker ID of 0 indicates the comment is not associated
680 with a marker */
681 lsx_writew(ft, 0);
683 /* now write the count and the bytes of text */
684 lsx_writew(ft, (unsigned) padded_comment_size);
685 lsx_writes(ft, comment);
686 if (comment_size != padded_comment_size)
687 lsx_writes(ft, " ");
689 free(comment);
691 /* COMM chunk -- describes encoding (and #frames) */
692 lsx_writes(ft, "COMM");
693 lsx_writedw(ft, 18); /* COMM chunk size */
694 lsx_writew(ft, ft->signal.channels); /* nchannels */
695 lsx_writedw(ft, (unsigned) nframes); /* number of frames */
696 lsx_writew(ft, bits); /* sample width, in bits */
697 write_ieee_extended(ft, (double)ft->signal.rate);
699 /* MARK chunk -- set markers */
700 if (ft->oob.instr.nloops) {
701 lsx_writes(ft, "MARK");
702 if (ft->oob.instr.nloops > 2)
703 ft->oob.instr.nloops = 2;
704 lsx_writedw(ft, 2 + 16u*ft->oob.instr.nloops);
705 lsx_writew(ft, ft->oob.instr.nloops);
707 for(i = 0; i < ft->oob.instr.nloops; i++) {
708 lsx_writew(ft, i + 1);
709 lsx_writedw(ft, (unsigned) ft->oob.loops[i].start);
710 lsx_writeb(ft, 0);
711 lsx_writeb(ft, 0);
712 lsx_writew(ft, i*2 + 1);
713 lsx_writedw(ft, (unsigned) (ft->oob.loops[i].start + ft->oob.loops[i].length));
714 lsx_writeb(ft, 0);
715 lsx_writeb(ft, 0);
718 lsx_writes(ft, "INST");
719 lsx_writedw(ft, 20);
720 /* random MIDI shit that we default on */
721 lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDInote);
722 lsx_writeb(ft, 0); /* detune */
723 lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDIlow);
724 lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDIhi);
725 lsx_writeb(ft, 1); /* low velocity */
726 lsx_writeb(ft, 127); /* hi velocity */
727 lsx_writew(ft, 0); /* gain */
729 /* sustain loop */
730 lsx_writew(ft, ft->oob.loops[0].type);
731 lsx_writew(ft, 1); /* marker 1 */
732 lsx_writew(ft, 3); /* marker 3 */
733 /* release loop, if there */
734 if (ft->oob.instr.nloops == 2) {
735 lsx_writew(ft, ft->oob.loops[1].type);
736 lsx_writew(ft, 2); /* marker 2 */
737 lsx_writew(ft, 4); /* marker 4 */
738 } else {
739 lsx_writew(ft, 0); /* no release loop */
740 lsx_writew(ft, 0);
741 lsx_writew(ft, 0);
745 /* SSND chunk -- describes data */
746 lsx_writes(ft, "SSND");
747 /* chunk size */
748 lsx_writedw(ft, (unsigned) (8 + nframes * ft->signal.channels * (ft->encoding.bits_per_sample >> 3)));
749 lsx_writedw(ft, 0); /* offset */
750 lsx_writedw(ft, 0); /* block size */
751 return(SOX_SUCCESS);
754 int lsx_aifcstartwrite(sox_format_t * ft)
756 int rc;
758 /* Needed because lsx_rawwrite() */
759 rc = lsx_rawstartwrite(ft);
760 if (rc)
761 return rc;
763 /* Compute the "very large number" so that a maximum number
764 of samples can be transmitted through a pipe without the
765 risk of causing overflow when calculating the number of bytes.
766 At 48 kHz, 16 bits stereo, this gives ~3 hours of music.
767 Sorry, the AIFC format does not provide for an "infinite"
768 number of samples. */
769 return(aifcwriteheader(ft, (size_t) 0x7f000000 / ((ft->encoding.bits_per_sample >> 3)*ft->signal.channels)));
772 int lsx_aifcstopwrite(sox_format_t * ft)
774 /* If we've written an odd number of bytes, write a padding
775 NUL */
776 if (ft->olength % 2 == 1 && ft->encoding.bits_per_sample == 8 && ft->signal.channels == 1)
778 sox_sample_t buf = 0;
779 lsx_rawwrite(ft, &buf, (size_t) 1);
782 if (!ft->seekable)
784 lsx_fail_errno(ft,SOX_EOF,"Non-seekable file.");
785 return(SOX_EOF);
787 if (lsx_seeki(ft, (off_t)0, SEEK_SET) != 0)
789 lsx_fail_errno(ft,errno,"can't rewind output file to rewrite AIFC header");
790 return(SOX_EOF);
792 return(aifcwriteheader(ft, ft->olength / ft->signal.channels));
795 static int aifcwriteheader(sox_format_t * ft, size_t nframes)
797 unsigned hsize =
798 12 /*FVER*/ + 8 /*COMM hdr*/ + 18+4+1+15 /*COMM chunk*/ +
799 8 /*SSND hdr*/ + 12 /*SSND chunk*/;
800 unsigned bits = 0;
802 if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
803 ft->encoding.bits_per_sample == 8)
804 bits = 8;
805 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
806 ft->encoding.bits_per_sample == 16)
807 bits = 16;
808 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
809 ft->encoding.bits_per_sample == 24)
810 bits = 24;
811 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
812 ft->encoding.bits_per_sample == 32)
813 bits = 32;
814 else
816 lsx_fail_errno(ft,SOX_EFMT,"unsupported output encoding/size for AIFC header");
817 return(SOX_EOF);
820 lsx_writes(ft, "FORM"); /* IFF header */
821 /* file size */
822 lsx_writedw(ft, (unsigned) (hsize + nframes * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels));
823 lsx_writes(ft, "AIFC"); /* File type */
825 /* FVER chunk */
826 lsx_writes(ft, "FVER");
827 lsx_writedw(ft, 4); /* FVER chunk size */
828 lsx_writedw(ft, 0xa2805140); /* version_date(May23,1990,2:40pm) */
830 /* COMM chunk -- describes encoding (and #frames) */
831 lsx_writes(ft, "COMM");
832 lsx_writedw(ft, 18+4+1+15); /* COMM chunk size */
833 lsx_writew(ft, ft->signal.channels); /* nchannels */
834 lsx_writedw(ft, (unsigned) nframes); /* number of frames */
835 lsx_writew(ft, bits); /* sample width, in bits */
836 write_ieee_extended(ft, (double)ft->signal.rate);
838 lsx_writes(ft, "NONE"); /*compression_type*/
839 lsx_writeb(ft, 14);
840 lsx_writes(ft, "not compressed");
841 lsx_writeb(ft, 0);
843 /* SSND chunk -- describes data */
844 lsx_writes(ft, "SSND");
845 /* chunk size */
846 lsx_writedw(ft, (unsigned) (8 + nframes * ft->signal.channels * (ft->encoding.bits_per_sample >> 3)));
847 lsx_writedw(ft, 0); /* offset */
848 lsx_writedw(ft, 0); /* block size */
850 /* Any Private chunks shall appear after the required chunks (FORM,FVER,COMM,SSND) */
851 return(SOX_SUCCESS);
854 static double read_ieee_extended(sox_format_t * ft)
856 unsigned char buf[10];
857 if (lsx_readbuf(ft, buf, (size_t)10) != 10)
859 lsx_fail_errno(ft,SOX_EOF,"EOF while reading IEEE extended number");
860 return(SOX_EOF);
862 return ConvertFromIeeeExtended(buf);
865 static void write_ieee_extended(sox_format_t * ft, double x)
867 char buf[10];
868 ConvertToIeeeExtended(x, buf);
869 lsx_debug_more("converted %g to %o %o %o %o %o %o %o %o %o %o",
871 buf[0], buf[1], buf[2], buf[3], buf[4],
872 buf[5], buf[6], buf[7], buf[8], buf[9]);
873 (void)lsx_writebuf(ft, buf, (size_t) 10);
878 * C O N V E R T T O I E E E E X T E N D E D
881 /* Copyright (C) 1988-1991 Apple Computer, Inc.
882 * All rights reserved.
884 * Machine-independent I/O routines for IEEE floating-point numbers.
886 * NaN's and infinities are converted to HUGE_VAL, which
887 * happens to be infinity on IEEE machines. Unfortunately, it is
888 * impossible to preserve NaN's in a machine-independent way.
889 * Infinities are, however, preserved on IEEE machines.
891 * These routines have been tested on the following machines:
892 * Apple Macintosh, MPW 3.1 C compiler
893 * Apple Macintosh, THINK C compiler
894 * Silicon Graphics IRIS, MIPS compiler
895 * Cray X/MP and Y/MP
896 * Digital Equipment VAX
899 * Implemented by Malcolm Slaney and Ken Turkowski.
901 * Malcolm Slaney contributions during 1988-1990 include big- and little-
902 * endian file I/O, conversion to and from Motorola's extended 80-bit
903 * floating-point format, and conversions to and from IEEE single-
904 * precision floating-point format.
906 * In 1991, Ken Turkowski implemented the conversions to and from
907 * IEEE double-precision format, added more precision to the extended
908 * conversions, and accommodated conversions involving +/- infinity,
909 * NaN's, and denormalized numbers.
912 #define FloatToUnsigned(f) ((uint32_t)(((int32_t)(f - 2147483648.0)) + 2147483647) + 1)
914 static void ConvertToIeeeExtended(double num, char *bytes)
916 int sign;
917 int expon;
918 double fMant, fsMant;
919 uint32_t hiMant, loMant;
921 if (num < 0) {
922 sign = 0x8000;
923 num *= -1;
924 } else {
925 sign = 0;
928 if (num == 0) {
929 expon = 0; hiMant = 0; loMant = 0;
931 else {
932 fMant = frexp(num, &expon);
933 if ((expon > 16384) || !(fMant < 1)) { /* Infinity or NaN */
934 expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */
936 else { /* Finite */
937 expon += 16382;
938 if (expon < 0) { /* denormalized */
939 fMant = ldexp(fMant, expon);
940 expon = 0;
942 expon |= sign;
943 fMant = ldexp(fMant, 32);
944 fsMant = floor(fMant);
945 hiMant = FloatToUnsigned(fsMant);
946 fMant = ldexp(fMant - fsMant, 32);
947 fsMant = floor(fMant);
948 loMant = FloatToUnsigned(fsMant);
952 bytes[0] = expon >> 8;
953 bytes[1] = expon;
954 bytes[2] = hiMant >> 24;
955 bytes[3] = hiMant >> 16;
956 bytes[4] = hiMant >> 8;
957 bytes[5] = hiMant;
958 bytes[6] = loMant >> 24;
959 bytes[7] = loMant >> 16;
960 bytes[8] = loMant >> 8;
961 bytes[9] = loMant;
966 * C O N V E R T F R O M I E E E E X T E N D E D
970 * Copyright (C) 1988-1991 Apple Computer, Inc.
971 * All rights reserved.
973 * Machine-independent I/O routines for IEEE floating-point numbers.
975 * NaN's and infinities are converted to HUGE_VAL, which
976 * happens to be infinity on IEEE machines. Unfortunately, it is
977 * impossible to preserve NaN's in a machine-independent way.
978 * Infinities are, however, preserved on IEEE machines.
980 * These routines have been tested on the following machines:
981 * Apple Macintosh, MPW 3.1 C compiler
982 * Apple Macintosh, THINK C compiler
983 * Silicon Graphics IRIS, MIPS compiler
984 * Cray X/MP and Y/MP
985 * Digital Equipment VAX
988 * Implemented by Malcolm Slaney and Ken Turkowski.
990 * Malcolm Slaney contributions during 1988-1990 include big- and little-
991 * endian file I/O, conversion to and from Motorola's extended 80-bit
992 * floating-point format, and conversions to and from IEEE single-
993 * precision floating-point format.
995 * In 1991, Ken Turkowski implemented the conversions to and from
996 * IEEE double-precision format, added more precision to the extended
997 * conversions, and accommodated conversions involving +/- infinity,
998 * NaN's, and denormalized numbers.
1001 #define UnsignedToFloat(u) (((double)((int32_t)(u - 2147483647 - 1))) + 2147483648.0)
1003 /****************************************************************
1004 * Extended precision IEEE floating-point conversion routine.
1005 ****************************************************************/
1007 static double ConvertFromIeeeExtended(unsigned char *bytes)
1009 double f;
1010 int expon;
1011 uint32_t hiMant, loMant;
1013 expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
1014 hiMant = ((uint32_t)(bytes[2] & 0xFF) << 24)
1015 | ((uint32_t)(bytes[3] & 0xFF) << 16)
1016 | ((uint32_t)(bytes[4] & 0xFF) << 8)
1017 | ((uint32_t)(bytes[5] & 0xFF));
1018 loMant = ((uint32_t)(bytes[6] & 0xFF) << 24)
1019 | ((uint32_t)(bytes[7] & 0xFF) << 16)
1020 | ((uint32_t)(bytes[8] & 0xFF) << 8)
1021 | ((uint32_t)(bytes[9] & 0xFF));
1023 if (expon == 0 && hiMant == 0 && loMant == 0) {
1024 f = 0;
1026 else {
1027 if (expon == 0x7FFF) { /* Infinity or NaN */
1028 f = HUGE_VAL;
1030 else {
1031 expon -= 16383;
1032 f = ldexp(UnsignedToFloat(hiMant), expon-=31);
1033 f += ldexp(UnsignedToFloat(loMant), expon-=32);
1037 if (bytes[0] & 0x80)
1038 return -f;
1039 else
1040 return f;