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.)
21 #include <time.h> /* for time stamping comments */
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
)
44 unsigned short channels
= 0;
45 sox_encoding_t enc
= SOX_ENCODING_SIGN2
;
47 unsigned short bits
= 0;
50 uint32_t blocksize
= 0;
51 int foundcomm
= 0, foundmark
= 0, foundinstr
= 0, is_sowt
= 0;
57 unsigned short looptype
;
59 unsigned short nmarks
= 0;
60 unsigned short sustainLoopBegin
= 0, sustainLoopEnd
= 0,
61 releaseLoopBegin
= 0, releaseLoopEnd
= 0;
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'");
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");
88 /* Skip everything but the COMM chunk and the SSND chunk */
89 /* The SSND chunk must be the last in the file */
91 if (lsx_reads(ft
, buf
, (size_t)4) == SOX_EOF
) {
95 lsx_fail_errno(ft
,SOX_EHDR
,"Missing SSND chunk in AIFF file");
99 if (strncmp(buf
, "COMM", (size_t)4) == 0) {
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
);
108 lsx_reads(ft
, buf
, (size_t)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 */
115 else if (strncmp(buf
, "fl32", (size_t)4) == 0 ||
116 strncmp(buf
, "FL32", (size_t)4) == 0) {
117 enc
= SOX_ENCODING_FLOAT
;
119 lsx_fail_errno(ft
, SOX_EHDR
,
120 "Sample size of %u is not consistent with `fl32' compression type", bits
);
124 else if (strncmp(buf
, "fl64", (size_t)4) == 0 ||
125 strncmp(buf
, "FL64", (size_t)4) == 0) {
126 enc
= SOX_ENCODING_FLOAT
;
128 lsx_fail_errno(ft
, SOX_EHDR
,
129 "Sample size of %u is not consistent with `fl64' compression type", bits
);
133 else if (strncmp(buf
, "NONE", (size_t)4) != 0 &&
134 strncmp(buf
, "twos", (size_t)4) != 0) {
136 lsx_fail_errno(ft
, SOX_EHDR
, "Unsupported AIFC compression type `%s'", buf
);
140 while(chunksize
-- > 0)
141 lsx_readb(ft
, &trash8
);
144 else if (strncmp(buf
, "SSND", (size_t)4) == 0) {
146 lsx_readdw(ft
, &chunksize
);
147 lsx_readdw(ft
, &offset
);
148 lsx_readdw(ft
, &blocksize
);
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 */
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) {
164 lsx_readdw(ft
, &chunksize
);
165 if (chunksize
>= sizeof(nmarks
)) {
166 lsx_readw(ft
, &nmarks
);
167 chunksize
-= sizeof(nmarks
);
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.
180 /* Make sure its not larger then we support */
184 for(i
= 0; i
< nmarks
&& chunksize
; i
++) {
185 unsigned char len
, read_len
, tmp_c
;
189 lsx_readw(ft
, &(marks
[i
].id
));
190 lsx_readdw(ft
, &(marks
[i
].position
));
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
)
204 for(j
= 0; j
< len
&& chunksize
; j
++) {
205 lsx_readb(ft
, &tmp_c
);
207 marks
[i
].name
[j
] = tmp_c
;
210 marks
[i
].name
[read_len
] = 0;
211 if ((len
& 1) == 0 && chunksize
) {
213 lsx_readb(ft
, &trash8
);
216 /* HA HA! Sound Designer (and others) makes */
217 /* bogus files. It spits out bogus chunksize */
219 while(chunksize
-- > 0)
220 lsx_readb(ft
, &trash8
);
222 else if (strncmp(buf
, "INST", (size_t)4) == 0) {
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
));
230 lsx_readb(ft
, &trash8
);
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 */
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 */
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
);
265 /* Fail already called in function */
269 sox_append_comments(&ft
->oob
.comments
, annotation
);
272 else if (strncmp(buf
, "COMT", (size_t)4) == 0) {
273 char *comment
= NULL
;
274 rc
= commentChunk(&comment
, "Comment:", ft
);
276 /* Fail already called in function */
280 sox_append_comments(&ft
->oob
.comments
, comment
);
283 else if (strncmp(buf
, "AUTH", (size_t)4) == 0) {
285 rc
= textChunk(&author
, "Author:", ft
);
287 /* Fail already called in function */
292 else if (strncmp(buf
, "NAME", (size_t)4) == 0) {
294 rc
= textChunk(&nametext
, "Name:", ft
);
296 /* Fail already called in function */
301 else if (strncmp(buf
, "(c) ", (size_t)4) == 0) {
302 /* Copyright chunk */
303 rc
= textChunk(©right
, "Copyright:", ft
);
305 /* Fail already called in function */
310 else if (strncmp(buf
, "ID3 ", 4) == 0) {
312 lsx_readdw(ft
, &chunksize
);
314 lsx_id3_read_tag(ft
, 0);
315 lsx_seeki(ft
, offs
+ chunksize
, SEEK_SET
);
321 lsx_debug("AIFFstartread: ignoring `%s' chunk", buf
);
322 lsx_readdw(ft
, &chunksize
);
325 /* account for padding after odd-sized chunks */
326 chunksize
+= chunksize
& 1;
327 /* Skip the chunk using lsx_readb() so we may read
329 while (chunksize
-- > 0) {
330 if (lsx_readb(ft
, &trash8
) == SOX_EOF
)
339 * if a pipe, we lose all chunks after sound.
340 * Like, say, instrument loops.
344 lsx_seeki(ft
, seekto
, SEEK_SET
);
346 lsx_fail_errno(ft
,SOX_EOF
,"AIFF: no sound data on input file");
350 /* SSND chunk just read */
352 lsx_warn("AIFF header has invalid blocksize. Ignoring but expect a premature EOF");
355 while (offset
-- > 0) {
356 if (lsx_readb(ft
, &trash8
) == SOX_EOF
) {
357 lsx_fail_errno(ft
,errno
,"unexpected EOF while skipping AIFF offset");
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 */;
369 lsx_fail_errno(ft
,SOX_EFMT
,"unsupported sample size in AIFF header: %d", bits
);
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.");
384 ssndsize
/= bits
>> 3;
386 /* Cope with 'sowt' CD tracks as read on Macs */
388 ft
->encoding
.reverse_bytes
= !ft
->encoding
.reverse_bytes
;
390 if (foundmark
&& !foundinstr
) {
391 lsx_debug("Ignoring MARK chunk since no INSTR found.");
394 if (!foundmark
&& foundinstr
) {
395 lsx_debug("Ignoring INSTR chunk since no MARK found.");
398 if (foundmark
&& foundinstr
) {
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
)
407 if(marks
[i2
].id
== sustainLoopEnd
)
409 if(marks
[i2
].id
== releaseLoopBegin
)
411 if(marks
[i2
].id
== releaseLoopEnd
)
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
)
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
)
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);
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
);
486 if (chunksize
!= SOX_SIZE_MAX
)
487 *(*text
+ chunksize
) = '\0';
489 *(*text
+ chunksize
-1) = '\0';
492 /* Read past pad byte */
494 if (lsx_readbuf(ft
, &c
, (size_t)1) != 1)
496 lsx_fail_errno(ft
,SOX_EOF
,"AIFF: Unexpected EOF in %s header", chunkDescription
);
500 lsx_debug("%-10s \"%s\"", chunkDescription
, *text
);
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
)
510 unsigned short numComments
;
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
);
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);
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
);
543 *(*text
+ totalCommentLength
) = '\0';
544 totalReadLength
+= totalCommentLength
+ 4 + 2 + 2; /* include header */
545 if (commentLength
% 2) {
546 /* Read past pad byte */
548 if (lsx_readbuf(ft
, &c
, (size_t)1) != 1) {
549 lsx_fail_errno(ft
,SOX_EOF
,"AIFF: Unexpected EOF in %s header", chunkDescription
);
552 totalReadLength
+= 1;
555 lsx_debug("%-10s \"%s\"", chunkDescription
, *text
);
556 /* make sure we read the whole chunk */
557 if (totalReadLength
< chunksize
) {
560 for (i
=0; i
< chunksize
- totalReadLength
; i
++ )
561 lsx_readbuf(ft
, &c
, (size_t)1);
566 int lsx_aiffstopread(sox_format_t
* ft
)
574 while (! lsx_eof(ft
))
576 if (lsx_readbuf(ft
, buf
, (size_t)4) != 4)
579 lsx_readdw(ft
, &chunksize
);
583 lsx_warn("Ignoring AIFF tail chunk: `%s', %u bytes long",
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
)
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
)
611 /* Needed because lsx_rawwrite() */
612 rc
= lsx_rawstartwrite(ft
);
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
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);
637 lsx_fail_errno(ft
,SOX_EOF
,"Non-seekable file.");
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");
645 return(aiffwriteheader(ft
, ft
->olength
/ ft
->signal
.channels
));
648 static int aiffwriteheader(sox_format_t
* ft
, uint64_t nframes
)
651 8 /*COMM hdr*/ + 18 /*COMM chunk*/ +
652 8 /*SSND hdr*/ + 12 /*SSND chunk*/;
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)
669 else if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
670 ft
->encoding
.bits_per_sample
== 16)
672 else if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
673 ft
->encoding
.bits_per_sample
== 24)
675 else if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
676 ft
->encoding
.bits_per_sample
== 32)
680 lsx_fail_errno(ft
,SOX_EFMT
,"unsupported output encoding/size for AIFF header");
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 */
701 size
= hsize
+ nframes
* (ft
->encoding
.bits_per_sample
>> 3) * ft
->signal
.channels
;
704 lsx_warn("file size too big for accurate AIFF header");
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
);
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
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
)
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
754 : ft
->oob
.loops
[i
].start
;
755 unsigned end
= ft
->oob
.loops
[i
].start
+ ft
->oob
.loops
[i
].length
> UINT_MAX
757 : ft
->oob
.loops
[i
].start
+ ft
->oob
.loops
[i
].length
;
758 lsx_writew(ft
, i
+ 1);
759 lsx_writedw(ft
, start
);
762 lsx_writew(ft
, i
*2 + 1);
763 lsx_writedw(ft
, end
);
768 lsx_writes(ft
, "INST");
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 */
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 */
789 lsx_writew(ft
, 0); /* no release loop */
795 /* SSND chunk -- describes data */
796 lsx_writes(ft
, "SSND");
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 */
804 int lsx_aifcstartwrite(sox_format_t
* ft
)
808 /* Needed because lsx_rawwrite() */
809 rc
= lsx_rawstartwrite(ft
);
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
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);
834 lsx_fail_errno(ft
,SOX_EOF
,"Non-seekable file.");
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");
842 return(aifcwriteheader(ft
, ft
->olength
/ ft
->signal
.channels
));
845 static int aifcwriteheader(sox_format_t
* ft
, uint64_t nframes
)
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)
856 else if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
857 ft
->encoding
.bits_per_sample
== 16)
859 else if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
860 ft
->encoding
.bits_per_sample
== 24)
862 else if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
863 ft
->encoding
.bits_per_sample
== 32)
865 else if (ft
->encoding
.encoding
== SOX_ENCODING_FLOAT
&&
866 ft
->encoding
.bits_per_sample
== 32)
868 else if (ft
->encoding
.encoding
== SOX_ENCODING_FLOAT
&&
869 ft
->encoding
.bits_per_sample
== 64)
873 lsx_fail_errno(ft
,SOX_EFMT
,"unsupported output encoding/size for AIFC header");
877 /* calculate length of COMM chunk (without header) */
878 switch (ft
->encoding
.encoding
) {
879 case SOX_ENCODING_SIGN2
:
881 cname
= "not compressed";
883 case SOX_ENCODING_FLOAT
:
886 cname
= "32-bit floating point";
889 cname
= "64-bit floating point";
892 default: /* can't happen */
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 */
904 size
= hsize
+ nframes
* (ft
->encoding
.bits_per_sample
>> 3) * ft
->signal
.channels
;
907 lsx_warn("file size too big for accurate AIFC header");
910 lsx_writedw(ft
, (unsigned)size
);
911 lsx_writes(ft
, "AIFC"); /* File type */
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
);
932 /* SSND chunk -- describes data */
933 lsx_writes(ft
, "SSND");
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) */
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");
951 return ConvertFromIeeeExtended(buf
);
954 static void write_ieee_extended(sox_format_t
* ft
, double x
)
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
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
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
)
1016 double fMant
, fsMant
;
1017 uint32_t hiMant
, loMant
;
1027 expon
= 0; hiMant
= 0; loMant
= 0;
1030 fMant
= frexp(num
, &expon
);
1031 if ((expon
> 16384) || !(fMant
< 1)) { /* Infinity or NaN */
1032 expon
= sign
|0x7FFF; hiMant
= 0; loMant
= 0; /* infinity */
1036 if (expon
< 0) { /* denormalized */
1037 fMant
= ldexp(fMant
, expon
);
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;
1052 bytes
[2] = hiMant
>> 24;
1053 bytes
[3] = hiMant
>> 16;
1054 bytes
[4] = hiMant
>> 8;
1056 bytes
[6] = loMant
>> 24;
1057 bytes
[7] = loMant
>> 16;
1058 bytes
[8] = loMant
>> 8;
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
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
)
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) {
1137 if (expon
== 0x7FFF) { /* Infinity or NaN */
1142 f
= ldexp(UnsignedToFloat(hiMant
), expon
-=31);
1143 f
+= ldexp(UnsignedToFloat(loMant
), expon
-=32);
1147 if (bytes
[0] & 0x80)