Merge branch 'mr/build' into pu
[sox/ew.git] / src / aiff.c
blob240d2e1fdf63ce5dfbf3f0e373fb6940788788fd
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 *comment = NULL;
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 (ssndsize > 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 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 /* Skip the chunk using lsx_readb() so we may read
318 from a pipe */
319 while (chunksize-- > 0) {
320 if (lsx_readb(ft, &trash8) == SOX_EOF)
321 break;
324 if (lsx_eof(ft))
325 break;
329 * if a pipe, we lose all chunks after sound.
330 * Like, say, instrument loops.
332 if (ft->seekable) {
333 if (seekto > 0)
334 lsx_seeki(ft, seekto, SEEK_SET);
335 else {
336 lsx_fail_errno(ft,SOX_EOF,"AIFF: no sound data on input file");
337 return(SOX_EOF);
340 /* SSND chunk just read */
341 if (blocksize != 0)
342 lsx_warn("AIFF header has invalid blocksize. Ignoring but expect a premature EOF");
344 ssndsize -= offset;
345 while (offset-- > 0) {
346 if (lsx_readb(ft, &trash8) == SOX_EOF) {
347 lsx_fail_errno(ft,errno,"unexpected EOF while skipping AIFF offset");
348 return(SOX_EOF);
352 if (foundcomm) {
353 if (bits <= 8) bits = 8;
354 else if (bits <= 16) bits = 16;
355 else if (bits <= 24) bits = 24;
356 else if (bits <= 32) bits = 32;
357 else if (bits == 64 && enc == SOX_ENCODING_FLOAT) /* no-op */;
358 else {
359 lsx_fail_errno(ft,SOX_EFMT,"unsupported sample size in AIFF header: %d", bits);
360 return(SOX_EOF);
362 } else {
363 if ((ft->signal.channels == SOX_UNSPEC)
364 || (ft->signal.rate == SOX_UNSPEC)
365 || (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
366 || (ft->encoding.bits_per_sample == 0)) {
367 lsx_report("You must specify # channels, sample rate, signed/unsigned,");
368 lsx_report("and 8/16 on the command line.");
369 lsx_fail_errno(ft,SOX_EFMT,"Bogus AIFF file: no COMM section.");
370 return(SOX_EOF);
374 ssndsize /= bits >> 3;
376 /* Cope with 'sowt' CD tracks as read on Macs */
377 if (is_sowt)
378 ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes;
380 if (foundmark && !foundinstr) {
381 lsx_debug("Ignoring MARK chunk since no INSTR found.");
382 foundmark = 0;
384 if (!foundmark && foundinstr) {
385 lsx_debug("Ignoring INSTR chunk since no MARK found.");
386 foundinstr = 0;
388 if (foundmark && foundinstr) {
389 int i2;
390 int slbIndex = 0, sleIndex = 0;
391 int rlbIndex = 0, rleIndex = 0;
393 /* find our loop markers and save their marker indexes */
394 for(i2 = 0; i2 < nmarks; i2++) {
395 if(marks[i2].id == sustainLoopBegin)
396 slbIndex = i2;
397 if(marks[i2].id == sustainLoopEnd)
398 sleIndex = i2;
399 if(marks[i2].id == releaseLoopBegin)
400 rlbIndex = i2;
401 if(marks[i2].id == releaseLoopEnd)
402 rleIndex = i2;
405 ft->oob.instr.nloops = 0;
406 if (ft->oob.loops[0].type != 0) {
407 ft->oob.loops[0].start = marks[slbIndex].position;
408 ft->oob.loops[0].length =
409 marks[sleIndex].position - marks[slbIndex].position;
410 /* really the loop count should be infinite */
411 ft->oob.loops[0].count = 1;
412 ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[0].type;
413 ft->oob.instr.nloops++;
415 if (ft->oob.loops[1].type != 0) {
416 ft->oob.loops[1].start = marks[rlbIndex].position;
417 ft->oob.loops[1].length =
418 marks[rleIndex].position - marks[rlbIndex].position;
419 /* really the loop count should be infinite */
420 ft->oob.loops[1].count = 1;
421 ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[1].type;
422 ft->oob.instr.nloops++;
425 reportInstrument(ft);
427 return lsx_check_read_params(
428 ft, channels, rate, enc, bits, (uint64_t)ssndsize, sox_false);
431 /* print out the MIDI key allocations, loop points, directions etc */
432 static void reportInstrument(sox_format_t * ft)
434 unsigned loopNum;
436 if(ft->oob.instr.nloops > 0)
437 lsx_report("AIFF Loop markers:");
438 for(loopNum = 0; loopNum < ft->oob.instr.nloops; loopNum++) {
439 if (ft->oob.loops[loopNum].count) {
440 lsx_report("Loop %d: start: %6lu", loopNum, (unsigned long)ft->oob.loops[loopNum].start);
441 lsx_report(" end: %6lu",
442 (unsigned long)(ft->oob.loops[loopNum].start + ft->oob.loops[loopNum].length));
443 lsx_report(" count: %6d", ft->oob.loops[loopNum].count);
444 lsx_report(" type: ");
445 switch(ft->oob.loops[loopNum].type & ~SOX_LOOP_SUSTAIN_DECAY) {
446 case 0: lsx_report("off"); break;
447 case 1: lsx_report("forward"); break;
448 case 2: lsx_report("forward/backward"); break;
452 lsx_report("Unity MIDI Note: %d", ft->oob.instr.MIDInote);
453 lsx_report("Low MIDI Note: %d", ft->oob.instr.MIDIlow);
454 lsx_report("High MIDI Note: %d", ft->oob.instr.MIDIhi);
457 /* Process a text chunk, allocate memory, display it if verbose and return */
458 static int textChunk(char **text, char *chunkDescription, sox_format_t * ft)
460 uint32_t chunksize0;
461 size_t chunksize;
462 lsx_readdw(ft, &chunksize0);
463 chunksize = chunksize0;
465 /* allocate enough memory to hold the text including a terminating \0 */
466 if (chunksize != SOX_SIZE_MAX)
467 *text = lsx_malloc((size_t)chunksize+1);
468 else
469 *text = lsx_malloc((size_t)chunksize);
471 if (lsx_readbuf(ft, *text, (size_t) chunksize) != chunksize)
473 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
474 return(SOX_EOF);
476 if (chunksize != SOX_SIZE_MAX)
477 *(*text + chunksize) = '\0';
478 else
479 *(*text + chunksize-1) = '\0';
480 if (chunksize % 2)
482 /* Read past pad byte */
483 char c;
484 if (lsx_readbuf(ft, &c, (size_t)1) != 1)
486 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
487 return(SOX_EOF);
490 lsx_debug("%-10s \"%s\"", chunkDescription, *text);
491 return(SOX_SUCCESS);
494 /* Comment lengths are words, not double words, and we can have several, so
495 we use a special function, not textChunk().;
497 static int commentChunk(char **text, char *chunkDescription, sox_format_t * ft)
499 uint32_t chunksize;
500 unsigned short numComments;
501 uint32_t timeStamp;
502 unsigned short markerId;
503 unsigned short totalCommentLength = 0;
504 unsigned int totalReadLength = 0;
505 unsigned int commentIndex;
507 lsx_readdw(ft, &chunksize);
508 lsx_readw(ft, &numComments);
509 totalReadLength += 2; /* chunksize doesn't count */
510 for(commentIndex = 0; commentIndex < numComments; commentIndex++) {
511 unsigned short commentLength;
513 lsx_readdw(ft, &timeStamp);
514 lsx_readw(ft, &markerId);
515 lsx_readw(ft, &commentLength);
516 if (((size_t)totalCommentLength) + commentLength > USHRT_MAX) {
517 lsx_fail_errno(ft,SOX_EOF,"AIFF: Comment too long in %s header", chunkDescription);
518 return(SOX_EOF);
520 totalCommentLength += commentLength;
521 /* allocate enough memory to hold the text including a terminating \0 */
522 if(commentIndex == 0) {
523 *text = lsx_malloc((size_t) totalCommentLength + 1);
525 else {
526 *text = lsx_realloc(*text, (size_t) totalCommentLength + 1);
529 if (lsx_readbuf(ft, *text + totalCommentLength - commentLength, (size_t) commentLength) != commentLength) {
530 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
531 return(SOX_EOF);
533 *(*text + totalCommentLength) = '\0';
534 totalReadLength += totalCommentLength + 4 + 2 + 2; /* include header */
535 if (commentLength % 2) {
536 /* Read past pad byte */
537 char c;
538 if (lsx_readbuf(ft, &c, (size_t)1) != 1) {
539 lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
540 return(SOX_EOF);
542 totalReadLength += 1;
545 lsx_debug("%-10s \"%s\"", chunkDescription, *text);
546 /* make sure we read the whole chunk */
547 if (totalReadLength < chunksize) {
548 size_t i;
549 char c;
550 for (i=0; i < chunksize - totalReadLength; i++ )
551 lsx_readbuf(ft, &c, (size_t)1);
553 return(SOX_SUCCESS);
556 int lsx_aiffstopread(sox_format_t * ft)
558 char buf[5];
559 uint32_t chunksize;
560 uint8_t trash;
562 if (!ft->seekable)
564 while (! lsx_eof(ft))
566 if (lsx_readbuf(ft, buf, (size_t)4) != 4)
567 break;
569 lsx_readdw(ft, &chunksize);
570 if (lsx_eof(ft))
571 break;
572 buf[4] = '\0';
573 lsx_warn("Ignoring AIFF tail chunk: `%s', %u bytes long",
574 buf, chunksize);
575 if (! strcmp(buf, "MARK") || ! strcmp(buf, "INST"))
576 lsx_warn(" You're stripping MIDI/loop info!");
577 while (chunksize-- > 0)
579 if (lsx_readb(ft, &trash) == SOX_EOF)
580 break;
584 return SOX_SUCCESS;
587 /* When writing, the header is supposed to contain the number of
588 samples and data bytes written.
589 Since we don't know how many samples there are until we're done,
590 we first write the header with an very large number,
591 and at the end we rewind the file and write the header again
592 with the right number. This only works if the file is seekable;
593 if it is not, the very large size remains in the header.
594 Strictly spoken this is not legal, but the playaiff utility
595 will still be able to play the resulting file. */
597 int lsx_aiffstartwrite(sox_format_t * ft)
599 int rc;
601 /* Needed because lsx_rawwrite() */
602 rc = lsx_rawstartwrite(ft);
603 if (rc)
604 return rc;
606 /* Compute the "very large number" so that a maximum number
607 of samples can be transmitted through a pipe without the
608 risk of causing overflow when calculating the number of bytes.
609 At 48 kHz, 16 bits stereo, this gives ~3 hours of audio.
610 Sorry, the AIFF format does not provide for an indefinite
611 number of samples. */
612 return(aiffwriteheader(ft, (uint64_t) 0x7f000000 / ((ft->encoding.bits_per_sample>>3)*ft->signal.channels)));
615 int lsx_aiffstopwrite(sox_format_t * ft)
617 /* If we've written an odd number of bytes, write a padding
618 NUL */
619 if (ft->olength % 2 == 1 && ft->encoding.bits_per_sample == 8 && ft->signal.channels == 1)
621 sox_sample_t buf = 0;
622 lsx_rawwrite(ft, &buf, (size_t) 1);
625 if (!ft->seekable)
627 lsx_fail_errno(ft,SOX_EOF,"Non-seekable file.");
628 return(SOX_EOF);
630 if (lsx_seeki(ft, (off_t)0, SEEK_SET) != 0)
632 lsx_fail_errno(ft,errno,"can't rewind output file to rewrite AIFF header");
633 return(SOX_EOF);
635 return(aiffwriteheader(ft, ft->olength / ft->signal.channels));
638 static int aiffwriteheader(sox_format_t * ft, uint64_t nframes)
640 int hsize =
641 8 /*COMM hdr*/ + 18 /*COMM chunk*/ +
642 8 /*SSND hdr*/ + 12 /*SSND chunk*/;
643 unsigned bits = 0;
644 unsigned i;
645 uint64_t size;
646 size_t padded_comment_size = 0, comment_size = 0;
647 size_t comment_chunk_size = 0;
648 char * comment = lsx_cat_comments(ft->oob.comments);
650 /* MARK and INST chunks */
651 if (ft->oob.instr.nloops) {
652 hsize += 8 /* MARK hdr */ + 2 + 16*ft->oob.instr.nloops;
653 hsize += 8 /* INST hdr */ + 20; /* INST chunk */
656 if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
657 ft->encoding.bits_per_sample == 8)
658 bits = 8;
659 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
660 ft->encoding.bits_per_sample == 16)
661 bits = 16;
662 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
663 ft->encoding.bits_per_sample == 24)
664 bits = 24;
665 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
666 ft->encoding.bits_per_sample == 32)
667 bits = 32;
668 else
670 lsx_fail_errno(ft,SOX_EFMT,"unsupported output encoding/size for AIFF header");
671 return(SOX_EOF);
674 /* COMT comment chunk -- holds comments text with a timestamp and marker id */
675 /* We calculate the comment_chunk_size if we will be writing a comment */
676 if (ft->oob.comments)
678 comment_size = strlen(comment);
679 /* Must put an even number of characters out.
680 * True 68k processors OS's seem to require this.
682 padded_comment_size = ((comment_size % 2) == 0) ?
683 comment_size : comment_size + 1;
684 /* one comment, timestamp, marker ID and text count */
685 comment_chunk_size = (2 + 4 + 2 + 2 + padded_comment_size);
686 hsize += 8 /* COMT hdr */ + comment_chunk_size;
689 lsx_writes(ft, "FORM"); /* IFF header */
690 /* file size */
691 size = hsize + nframes * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels;
692 if (size > UINT_MAX)
694 lsx_warn("file size too big for accurate AIFF header");
695 size = UINT_MAX;
697 lsx_writedw(ft, (unsigned)size);
698 lsx_writes(ft, "AIFF"); /* File type */
700 /* Now we write the COMT comment chunk using the precomputed sizes */
701 if (ft->oob.comments)
703 lsx_writes(ft, "COMT");
704 lsx_writedw(ft, (unsigned) comment_chunk_size);
706 /* one comment */
707 lsx_writew(ft, 1);
709 /* time stamp of comment, Unix knows of time from 1/1/1970,
710 Apple knows time from 1/1/1904 */
711 lsx_writedw(ft, (unsigned)((sox_globals.repeatable? 0 : time(NULL)) + 2082844800));
713 /* A marker ID of 0 indicates the comment is not associated
714 with a marker */
715 lsx_writew(ft, 0);
717 /* now write the count and the bytes of text */
718 lsx_writew(ft, (unsigned) padded_comment_size);
719 lsx_writes(ft, comment);
720 if (comment_size != padded_comment_size)
721 lsx_writes(ft, " ");
723 free(comment);
725 /* COMM chunk -- describes encoding (and #frames) */
726 lsx_writes(ft, "COMM");
727 lsx_writedw(ft, 18); /* COMM chunk size */
728 lsx_writew(ft, ft->signal.channels); /* nchannels */
729 lsx_writedw(ft, (unsigned) nframes); /* number of frames */
730 lsx_writew(ft, bits); /* sample width, in bits */
731 write_ieee_extended(ft, (double)ft->signal.rate);
733 /* MARK chunk -- set markers */
734 if (ft->oob.instr.nloops) {
735 lsx_writes(ft, "MARK");
736 if (ft->oob.instr.nloops > 2)
737 ft->oob.instr.nloops = 2;
738 lsx_writedw(ft, 2 + 16u*ft->oob.instr.nloops);
739 lsx_writew(ft, ft->oob.instr.nloops);
741 for(i = 0; i < ft->oob.instr.nloops; i++) {
742 unsigned start = ft->oob.loops[i].start > UINT_MAX
743 ? UINT_MAX
744 : ft->oob.loops[i].start;
745 unsigned end = ft->oob.loops[i].start + ft->oob.loops[i].length > UINT_MAX
746 ? UINT_MAX
747 : ft->oob.loops[i].start + ft->oob.loops[i].length;
748 lsx_writew(ft, i + 1);
749 lsx_writedw(ft, start);
750 lsx_writeb(ft, 0);
751 lsx_writeb(ft, 0);
752 lsx_writew(ft, i*2 + 1);
753 lsx_writedw(ft, end);
754 lsx_writeb(ft, 0);
755 lsx_writeb(ft, 0);
758 lsx_writes(ft, "INST");
759 lsx_writedw(ft, 20);
760 /* random MIDI shit that we default on */
761 lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDInote);
762 lsx_writeb(ft, 0); /* detune */
763 lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDIlow);
764 lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDIhi);
765 lsx_writeb(ft, 1); /* low velocity */
766 lsx_writeb(ft, 127); /* hi velocity */
767 lsx_writew(ft, 0); /* gain */
769 /* sustain loop */
770 lsx_writew(ft, ft->oob.loops[0].type);
771 lsx_writew(ft, 1); /* marker 1 */
772 lsx_writew(ft, 3); /* marker 3 */
773 /* release loop, if there */
774 if (ft->oob.instr.nloops == 2) {
775 lsx_writew(ft, ft->oob.loops[1].type);
776 lsx_writew(ft, 2); /* marker 2 */
777 lsx_writew(ft, 4); /* marker 4 */
778 } else {
779 lsx_writew(ft, 0); /* no release loop */
780 lsx_writew(ft, 0);
781 lsx_writew(ft, 0);
785 /* SSND chunk -- describes data */
786 lsx_writes(ft, "SSND");
787 /* chunk size */
788 lsx_writedw(ft, (unsigned) (8 + nframes * ft->signal.channels * (ft->encoding.bits_per_sample >> 3)));
789 lsx_writedw(ft, 0); /* offset */
790 lsx_writedw(ft, 0); /* block size */
791 return(SOX_SUCCESS);
794 int lsx_aifcstartwrite(sox_format_t * ft)
796 int rc;
798 /* Needed because lsx_rawwrite() */
799 rc = lsx_rawstartwrite(ft);
800 if (rc)
801 return rc;
803 /* Compute the "very large number" so that a maximum number
804 of samples can be transmitted through a pipe without the
805 risk of causing overflow when calculating the number of bytes.
806 At 48 kHz, 16 bits stereo, this gives ~3 hours of music.
807 Sorry, the AIFC format does not provide for an "infinite"
808 number of samples. */
809 return(aifcwriteheader(ft, (uint64_t) 0x7f000000 / ((ft->encoding.bits_per_sample >> 3)*ft->signal.channels)));
812 int lsx_aifcstopwrite(sox_format_t * ft)
814 /* If we've written an odd number of bytes, write a padding
815 NUL */
816 if (ft->olength % 2 == 1 && ft->encoding.bits_per_sample == 8 && ft->signal.channels == 1)
818 sox_sample_t buf = 0;
819 lsx_rawwrite(ft, &buf, (size_t) 1);
822 if (!ft->seekable)
824 lsx_fail_errno(ft,SOX_EOF,"Non-seekable file.");
825 return(SOX_EOF);
827 if (lsx_seeki(ft, (off_t)0, SEEK_SET) != 0)
829 lsx_fail_errno(ft,errno,"can't rewind output file to rewrite AIFC header");
830 return(SOX_EOF);
832 return(aifcwriteheader(ft, ft->olength / ft->signal.channels));
835 static int aifcwriteheader(sox_format_t * ft, uint64_t nframes)
837 unsigned hsize;
838 unsigned bits = 0;
839 uint64_t size;
840 char *ctype = NULL, *cname = NULL;
841 unsigned cname_len = 0, comm_len = 0, comm_padding = 0;
843 if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
844 ft->encoding.bits_per_sample == 8)
845 bits = 8;
846 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
847 ft->encoding.bits_per_sample == 16)
848 bits = 16;
849 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
850 ft->encoding.bits_per_sample == 24)
851 bits = 24;
852 else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 &&
853 ft->encoding.bits_per_sample == 32)
854 bits = 32;
855 else if (ft->encoding.encoding == SOX_ENCODING_FLOAT &&
856 ft->encoding.bits_per_sample == 32)
857 bits = 32;
858 else if (ft->encoding.encoding == SOX_ENCODING_FLOAT &&
859 ft->encoding.bits_per_sample == 64)
860 bits = 64;
861 else
863 lsx_fail_errno(ft,SOX_EFMT,"unsupported output encoding/size for AIFC header");
864 return(SOX_EOF);
867 /* calculate length of COMM chunk (without header) */
868 switch (ft->encoding.encoding) {
869 case SOX_ENCODING_SIGN2:
870 ctype = "NONE";
871 cname = "not compressed";
872 break;
873 case SOX_ENCODING_FLOAT:
874 if (bits == 32) {
875 ctype = "fl32";
876 cname = "32-bit floating point";
877 } else {
878 ctype = "fl64";
879 cname = "64-bit floating point";
881 break;
882 default: /* can't happen */
883 break;
885 cname_len = strlen(cname);
886 comm_len = 18+4+1+cname_len;
887 comm_padding = comm_len%2;
889 hsize = 12 /*FVER*/ + 8 /*COMM hdr*/ + comm_len+comm_padding /*COMM chunk*/ +
890 8 /*SSND hdr*/ + 12 /*SSND chunk*/;
892 lsx_writes(ft, "FORM"); /* IFF header */
893 /* file size */
894 size = hsize + nframes * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels;
895 if (size > UINT_MAX)
897 lsx_warn("file size too big for accurate AIFC header");
898 size = UINT_MAX;
900 lsx_writedw(ft, (unsigned)size);
901 lsx_writes(ft, "AIFC"); /* File type */
903 /* FVER chunk */
904 lsx_writes(ft, "FVER");
905 lsx_writedw(ft, 4); /* FVER chunk size */
906 lsx_writedw(ft, 0xa2805140); /* version_date(May23,1990,2:40pm) */
908 /* COMM chunk -- describes encoding (and #frames) */
909 lsx_writes(ft, "COMM");
910 lsx_writedw(ft, comm_len+comm_padding); /* COMM chunk size */
911 lsx_writew(ft, ft->signal.channels); /* nchannels */
912 lsx_writedw(ft, (unsigned) nframes); /* number of frames */
913 lsx_writew(ft, bits); /* sample width, in bits */
914 write_ieee_extended(ft, (double)ft->signal.rate);
916 lsx_writes(ft, ctype); /*compression_type*/
917 lsx_writeb(ft, cname_len);
918 lsx_writes(ft, cname);
919 if (comm_padding)
920 lsx_writeb(ft, 0);
922 /* SSND chunk -- describes data */
923 lsx_writes(ft, "SSND");
924 /* chunk size */
925 lsx_writedw(ft, (unsigned) (8 + nframes * ft->signal.channels * (ft->encoding.bits_per_sample >> 3)));
926 lsx_writedw(ft, 0); /* offset */
927 lsx_writedw(ft, 0); /* block size */
929 /* Any Private chunks shall appear after the required chunks (FORM,FVER,COMM,SSND) */
930 return(SOX_SUCCESS);
933 static double read_ieee_extended(sox_format_t * ft)
935 unsigned char buf[10];
936 if (lsx_readbuf(ft, buf, (size_t)10) != 10)
938 lsx_fail_errno(ft,SOX_EOF,"EOF while reading IEEE extended number");
939 return(SOX_EOF);
941 return ConvertFromIeeeExtended(buf);
944 static void write_ieee_extended(sox_format_t * ft, double x)
946 char buf[10];
947 ConvertToIeeeExtended(x, buf);
948 lsx_debug_more("converted %g to %o %o %o %o %o %o %o %o %o %o",
950 buf[0], buf[1], buf[2], buf[3], buf[4],
951 buf[5], buf[6], buf[7], buf[8], buf[9]);
952 (void)lsx_writebuf(ft, buf, (size_t) 10);
957 * C O N V E R T T O I E E E E X T E N D E D
960 /* Copyright (C) 1988-1991 Apple Computer, Inc.
962 * All rights reserved.
964 * Warranty Information
965 * Even though Apple has reviewed this software, Apple makes no warranty
966 * or representation, either express or implied, with respect to this
967 * software, its quality, accuracy, merchantability, or fitness for a
968 * particular purpose. As a result, this software is provided "as is,"
969 * and you, its user, are assuming the entire risk as to its quality
970 * and accuracy.
972 * Machine-independent I/O routines for IEEE floating-point numbers.
974 * NaN's and infinities are converted to HUGE_VAL, which
975 * happens to be infinity on IEEE machines. Unfortunately, it is
976 * impossible to preserve NaN's in a machine-independent way.
977 * Infinities are, however, preserved on IEEE machines.
979 * These routines have been tested on the following machines:
980 * Apple Macintosh, MPW 3.1 C compiler
981 * Apple Macintosh, THINK C compiler
982 * Silicon Graphics IRIS, MIPS compiler
983 * Cray X/MP and Y/MP
984 * Digital Equipment VAX
987 * Implemented by Malcolm Slaney and Ken Turkowski.
989 * Malcolm Slaney contributions during 1988-1990 include big- and little-
990 * endian file I/O, conversion to and from Motorola's extended 80-bit
991 * floating-point format, and conversions to and from IEEE single-
992 * precision floating-point format.
994 * In 1991, Ken Turkowski implemented the conversions to and from
995 * IEEE double-precision format, added more precision to the extended
996 * conversions, and accommodated conversions involving +/- infinity,
997 * NaN's, and denormalized numbers.
1000 #define FloatToUnsigned(f) ((uint32_t)(((int32_t)(f - 2147483648.0)) + 2147483647) + 1)
1002 static void ConvertToIeeeExtended(double num, char *bytes)
1004 int sign;
1005 int expon;
1006 double fMant, fsMant;
1007 uint32_t hiMant, loMant;
1009 if (num < 0) {
1010 sign = 0x8000;
1011 num *= -1;
1012 } else {
1013 sign = 0;
1016 if (num == 0) {
1017 expon = 0; hiMant = 0; loMant = 0;
1019 else {
1020 fMant = frexp(num, &expon);
1021 if ((expon > 16384) || !(fMant < 1)) { /* Infinity or NaN */
1022 expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */
1024 else { /* Finite */
1025 expon += 16382;
1026 if (expon < 0) { /* denormalized */
1027 fMant = ldexp(fMant, expon);
1028 expon = 0;
1030 expon |= sign;
1031 fMant = ldexp(fMant, 32);
1032 fsMant = floor(fMant);
1033 hiMant = FloatToUnsigned(fsMant);
1034 fMant = ldexp(fMant - fsMant, 32);
1035 fsMant = floor(fMant);
1036 loMant = FloatToUnsigned(fsMant);
1040 bytes[0] = expon >> 8;
1041 bytes[1] = expon;
1042 bytes[2] = hiMant >> 24;
1043 bytes[3] = hiMant >> 16;
1044 bytes[4] = hiMant >> 8;
1045 bytes[5] = hiMant;
1046 bytes[6] = loMant >> 24;
1047 bytes[7] = loMant >> 16;
1048 bytes[8] = loMant >> 8;
1049 bytes[9] = loMant;
1054 * C O N V E R T F R O M I E E E E X T E N D E D
1058 * Copyright (C) 1988-1991 Apple Computer, Inc.
1060 * All rights reserved.
1062 * Warranty Information
1063 * Even though Apple has reviewed this software, Apple makes no warranty
1064 * or representation, either express or implied, with respect to this
1065 * software, its quality, accuracy, merchantability, or fitness for a
1066 * particular purpose. As a result, this software is provided "as is,"
1067 * and you, its user, are assuming the entire risk as to its quality
1068 * and accuracy.
1070 * This code may be used and freely distributed as long as it includes
1071 * this copyright notice and the above warranty information.
1073 * Machine-independent I/O routines for IEEE floating-point numbers.
1075 * NaN's and infinities are converted to HUGE_VAL, which
1076 * happens to be infinity on IEEE machines. Unfortunately, it is
1077 * impossible to preserve NaN's in a machine-independent way.
1078 * Infinities are, however, preserved on IEEE machines.
1080 * These routines have been tested on the following machines:
1081 * Apple Macintosh, MPW 3.1 C compiler
1082 * Apple Macintosh, THINK C compiler
1083 * Silicon Graphics IRIS, MIPS compiler
1084 * Cray X/MP and Y/MP
1085 * Digital Equipment VAX
1088 * Implemented by Malcolm Slaney and Ken Turkowski.
1090 * Malcolm Slaney contributions during 1988-1990 include big- and little-
1091 * endian file I/O, conversion to and from Motorola's extended 80-bit
1092 * floating-point format, and conversions to and from IEEE single-
1093 * precision floating-point format.
1095 * In 1991, Ken Turkowski implemented the conversions to and from
1096 * IEEE double-precision format, added more precision to the extended
1097 * conversions, and accommodated conversions involving +/- infinity,
1098 * NaN's, and denormalized numbers.
1101 #define UnsignedToFloat(u) (((double)((int32_t)(u - 2147483647 - 1))) + 2147483648.0)
1103 /****************************************************************
1104 * Extended precision IEEE floating-point conversion routine.
1105 ****************************************************************/
1107 static double ConvertFromIeeeExtended(unsigned char *bytes)
1109 double f;
1110 int expon;
1111 uint32_t hiMant, loMant;
1113 expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
1114 hiMant = ((uint32_t)(bytes[2] & 0xFF) << 24)
1115 | ((uint32_t)(bytes[3] & 0xFF) << 16)
1116 | ((uint32_t)(bytes[4] & 0xFF) << 8)
1117 | ((uint32_t)(bytes[5] & 0xFF));
1118 loMant = ((uint32_t)(bytes[6] & 0xFF) << 24)
1119 | ((uint32_t)(bytes[7] & 0xFF) << 16)
1120 | ((uint32_t)(bytes[8] & 0xFF) << 8)
1121 | ((uint32_t)(bytes[9] & 0xFF));
1123 if (expon == 0 && hiMant == 0 && loMant == 0) {
1124 f = 0;
1126 else {
1127 if (expon == 0x7FFF) { /* Infinity or NaN */
1128 f = HUGE_VAL;
1130 else {
1131 expon -= 16383;
1132 f = ldexp(UnsignedToFloat(hiMant), expon-=31);
1133 f += ldexp(UnsignedToFloat(loMant), expon-=32);
1137 if (bytes[0] & 0x80)
1138 return -f;
1139 else
1140 return f;