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.)
20 #include <time.h> /* for time stamping comments */
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
)
43 unsigned short channels
= 0;
44 sox_encoding_t enc
= SOX_ENCODING_SIGN2
;
46 unsigned short bits
= 0;
49 uint32_t blocksize
= 0;
50 int foundcomm
= 0, foundmark
= 0, foundinstr
= 0, is_sowt
= 0;
56 unsigned short looptype
;
58 unsigned short nmarks
= 0;
59 unsigned short sustainLoopBegin
= 0, sustainLoopEnd
= 0,
60 releaseLoopBegin
= 0, releaseLoopEnd
= 0;
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'");
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");
87 /* Skip everything but the COMM chunk and the SSND chunk */
88 /* The SSND chunk must be the last in the file */
90 if (lsx_reads(ft
, buf
, (size_t)4) == SOX_EOF
) {
94 lsx_fail_errno(ft
,SOX_EHDR
,"Missing SSND chunk in AIFF file");
98 if (strncmp(buf
, "COMM", (size_t)4) == 0) {
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
);
107 lsx_reads(ft
, buf
, (size_t)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 */
114 else if (strncmp(buf
, "fl32", (size_t)4) == 0 ||
115 strncmp(buf
, "FL32", (size_t)4) == 0) {
116 enc
= SOX_ENCODING_FLOAT
;
118 lsx_fail_errno(ft
, SOX_EHDR
,
119 "Sample size of %u is not consistent with `fl32' compression type", bits
);
123 else if (strncmp(buf
, "fl64", (size_t)4) == 0 ||
124 strncmp(buf
, "FL64", (size_t)4) == 0) {
125 enc
= SOX_ENCODING_FLOAT
;
127 lsx_fail_errno(ft
, SOX_EHDR
,
128 "Sample size of %u is not consistent with `fl64' compression type", bits
);
132 else if (strncmp(buf
, "NONE", (size_t)4) != 0 &&
133 strncmp(buf
, "twos", (size_t)4) != 0) {
135 lsx_fail_errno(ft
, SOX_EHDR
, "Unsupported AIFC compression type `%s'", buf
);
139 while(chunksize
-- > 0)
140 lsx_readb(ft
, &trash8
);
143 else if (strncmp(buf
, "SSND", (size_t)4) == 0) {
145 lsx_readdw(ft
, &chunksize
);
146 lsx_readdw(ft
, &offset
);
147 lsx_readdw(ft
, &blocksize
);
149 ssndsize
= chunksize
;
150 /* word-align chunksize in case it wasn't
151 * done by writing application already.
153 chunksize
+= (chunksize
% 2);
154 /* if can't seek, just do sound now */
157 /* else, seek to end of sound and hunt for more */
158 seekto
= lsx_tell(ft
);
159 lsx_seeki(ft
, (off_t
)chunksize
, SEEK_CUR
);
161 else if (strncmp(buf
, "MARK", (size_t)4) == 0) {
163 lsx_readdw(ft
, &chunksize
);
164 if (chunksize
>= sizeof(nmarks
)) {
165 lsx_readw(ft
, &nmarks
);
166 chunksize
-= sizeof(nmarks
);
170 /* Some programs like to always have a MARK chunk
171 * but will set number of marks to 0 and force
172 * software to detect and ignore it.
179 /* Make sure its not larger then we support */
183 for(i
= 0; i
< nmarks
&& chunksize
; i
++) {
184 unsigned char len
, read_len
, tmp_c
;
188 lsx_readw(ft
, &(marks
[i
].id
));
189 lsx_readdw(ft
, &(marks
[i
].position
));
191 /* If error reading length then
192 * don't try to read more bytes
193 * based on that value.
195 if (lsx_readb(ft
, &len
) != SOX_SUCCESS
)
203 for(j
= 0; j
< len
&& chunksize
; j
++) {
204 lsx_readb(ft
, &tmp_c
);
206 marks
[i
].name
[j
] = tmp_c
;
209 marks
[i
].name
[read_len
] = 0;
210 if ((len
& 1) == 0 && chunksize
) {
212 lsx_readb(ft
, &trash8
);
215 /* HA HA! Sound Designer (and others) makes */
216 /* bogus files. It spits out bogus chunksize */
218 while(chunksize
-- > 0)
219 lsx_readb(ft
, &trash8
);
221 else if (strncmp(buf
, "INST", (size_t)4) == 0) {
223 lsx_readdw(ft
, &chunksize
);
224 lsx_readsb(ft
, &(ft
->oob
.instr
.MIDInote
));
225 lsx_readb(ft
, &trash8
);
226 lsx_readsb(ft
, &(ft
->oob
.instr
.MIDIlow
));
227 lsx_readsb(ft
, &(ft
->oob
.instr
.MIDIhi
));
229 lsx_readb(ft
, &trash8
);
231 lsx_readb(ft
, &trash8
);
232 lsx_readw(ft
, &trash16
);/* gain */
233 lsx_readw(ft
, &looptype
); /* sustain loop */
234 ft
->oob
.loops
[0].type
= looptype
;
235 lsx_readw(ft
, &sustainLoopBegin
); /* begin marker */
236 lsx_readw(ft
, &sustainLoopEnd
); /* end marker */
237 lsx_readw(ft
, &looptype
); /* release loop */
238 ft
->oob
.loops
[1].type
= looptype
;
239 lsx_readw(ft
, &releaseLoopBegin
); /* begin marker */
240 lsx_readw(ft
, &releaseLoopEnd
); /* end marker */
244 else if (strncmp(buf
, "APPL", (size_t)4) == 0) {
245 lsx_readdw(ft
, &chunksize
);
246 /* word-align chunksize in case it wasn't
247 * done by writing application already.
249 chunksize
+= (chunksize
% 2);
250 while(chunksize
-- > 0)
251 lsx_readb(ft
, &trash8
);
253 else if (strncmp(buf
, "ALCH", (size_t)4) == 0) {
254 /* I think this is bogus and gets grabbed by APPL */
256 lsx_readdw(ft
, &trash32
); /* ENVS - jeez! */
257 lsx_readdw(ft
, &chunksize
);
258 while(chunksize
-- > 0)
259 lsx_readb(ft
, &trash8
);
261 else if (strncmp(buf
, "ANNO", (size_t)4) == 0) {
262 rc
= textChunk(&annotation
, "Annotation:", ft
);
264 /* Fail already called in function */
268 sox_append_comments(&ft
->oob
.comments
, annotation
);
271 else if (strncmp(buf
, "COMT", (size_t)4) == 0) {
272 char *comment
= NULL
;
273 rc
= commentChunk(&comment
, "Comment:", ft
);
275 /* Fail already called in function */
279 sox_append_comments(&ft
->oob
.comments
, comment
);
282 else if (strncmp(buf
, "AUTH", (size_t)4) == 0) {
284 rc
= textChunk(&author
, "Author:", ft
);
286 /* Fail already called in function */
291 else if (strncmp(buf
, "NAME", (size_t)4) == 0) {
293 rc
= textChunk(&nametext
, "Name:", ft
);
295 /* Fail already called in function */
300 else if (strncmp(buf
, "(c) ", (size_t)4) == 0) {
301 /* Copyright chunk */
302 rc
= textChunk(©right
, "Copyright:", ft
);
304 /* Fail already called in function */
313 lsx_debug("AIFFstartread: ignoring `%s' chunk", buf
);
314 lsx_readdw(ft
, &chunksize
);
317 /* account for padding after odd-sized chunks */
318 chunksize
+= chunksize
& 1;
319 /* Skip the chunk using lsx_readb() so we may read
321 while (chunksize
-- > 0) {
322 if (lsx_readb(ft
, &trash8
) == SOX_EOF
)
331 * if a pipe, we lose all chunks after sound.
332 * Like, say, instrument loops.
336 lsx_seeki(ft
, seekto
, SEEK_SET
);
338 lsx_fail_errno(ft
,SOX_EOF
,"AIFF: no sound data on input file");
342 /* SSND chunk just read */
344 lsx_warn("AIFF header has invalid blocksize. Ignoring but expect a premature EOF");
347 while (offset
-- > 0) {
348 if (lsx_readb(ft
, &trash8
) == SOX_EOF
) {
349 lsx_fail_errno(ft
,errno
,"unexpected EOF while skipping AIFF offset");
355 if (bits
<= 8) bits
= 8;
356 else if (bits
<= 16) bits
= 16;
357 else if (bits
<= 24) bits
= 24;
358 else if (bits
<= 32) bits
= 32;
359 else if (bits
== 64 && enc
== SOX_ENCODING_FLOAT
) /* no-op */;
361 lsx_fail_errno(ft
,SOX_EFMT
,"unsupported sample size in AIFF header: %d", bits
);
365 if ((ft
->signal
.channels
== SOX_UNSPEC
)
366 || (ft
->signal
.rate
== SOX_UNSPEC
)
367 || (ft
->encoding
.encoding
== SOX_ENCODING_UNKNOWN
)
368 || (ft
->encoding
.bits_per_sample
== 0)) {
369 lsx_report("You must specify # channels, sample rate, signed/unsigned,");
370 lsx_report("and 8/16 on the command line.");
371 lsx_fail_errno(ft
,SOX_EFMT
,"Bogus AIFF file: no COMM section.");
376 ssndsize
/= bits
>> 3;
378 /* Cope with 'sowt' CD tracks as read on Macs */
380 ft
->encoding
.reverse_bytes
= !ft
->encoding
.reverse_bytes
;
382 if (foundmark
&& !foundinstr
) {
383 lsx_debug("Ignoring MARK chunk since no INSTR found.");
386 if (!foundmark
&& foundinstr
) {
387 lsx_debug("Ignoring INSTR chunk since no MARK found.");
390 if (foundmark
&& foundinstr
) {
392 int slbIndex
= 0, sleIndex
= 0;
393 int rlbIndex
= 0, rleIndex
= 0;
395 /* find our loop markers and save their marker indexes */
396 for(i2
= 0; i2
< nmarks
; i2
++) {
397 if(marks
[i2
].id
== sustainLoopBegin
)
399 if(marks
[i2
].id
== sustainLoopEnd
)
401 if(marks
[i2
].id
== releaseLoopBegin
)
403 if(marks
[i2
].id
== releaseLoopEnd
)
407 ft
->oob
.instr
.nloops
= 0;
408 if (ft
->oob
.loops
[0].type
!= 0) {
409 ft
->oob
.loops
[0].start
= marks
[slbIndex
].position
;
410 ft
->oob
.loops
[0].length
=
411 marks
[sleIndex
].position
- marks
[slbIndex
].position
;
412 /* really the loop count should be infinite */
413 ft
->oob
.loops
[0].count
= 1;
414 ft
->oob
.instr
.loopmode
= SOX_LOOP_SUSTAIN_DECAY
| ft
->oob
.loops
[0].type
;
415 ft
->oob
.instr
.nloops
++;
417 if (ft
->oob
.loops
[1].type
!= 0) {
418 ft
->oob
.loops
[1].start
= marks
[rlbIndex
].position
;
419 ft
->oob
.loops
[1].length
=
420 marks
[rleIndex
].position
- marks
[rlbIndex
].position
;
421 /* really the loop count should be infinite */
422 ft
->oob
.loops
[1].count
= 1;
423 ft
->oob
.instr
.loopmode
= SOX_LOOP_SUSTAIN_DECAY
| ft
->oob
.loops
[1].type
;
424 ft
->oob
.instr
.nloops
++;
427 reportInstrument(ft
);
429 return lsx_check_read_params(
430 ft
, channels
, rate
, enc
, bits
, (uint64_t)ssndsize
, sox_false
);
433 /* print out the MIDI key allocations, loop points, directions etc */
434 static void reportInstrument(sox_format_t
* ft
)
438 if(ft
->oob
.instr
.nloops
> 0)
439 lsx_report("AIFF Loop markers:");
440 for(loopNum
= 0; loopNum
< ft
->oob
.instr
.nloops
; loopNum
++) {
441 if (ft
->oob
.loops
[loopNum
].count
) {
442 lsx_report("Loop %d: start: %6lu", loopNum
, (unsigned long)ft
->oob
.loops
[loopNum
].start
);
443 lsx_report(" end: %6lu",
444 (unsigned long)(ft
->oob
.loops
[loopNum
].start
+ ft
->oob
.loops
[loopNum
].length
));
445 lsx_report(" count: %6d", ft
->oob
.loops
[loopNum
].count
);
446 lsx_report(" type: ");
447 switch(ft
->oob
.loops
[loopNum
].type
& ~SOX_LOOP_SUSTAIN_DECAY
) {
448 case 0: lsx_report("off"); break;
449 case 1: lsx_report("forward"); break;
450 case 2: lsx_report("forward/backward"); break;
454 lsx_report("Unity MIDI Note: %d", ft
->oob
.instr
.MIDInote
);
455 lsx_report("Low MIDI Note: %d", ft
->oob
.instr
.MIDIlow
);
456 lsx_report("High MIDI Note: %d", ft
->oob
.instr
.MIDIhi
);
459 /* Process a text chunk, allocate memory, display it if verbose and return */
460 static int textChunk(char **text
, char *chunkDescription
, sox_format_t
* ft
)
464 lsx_readdw(ft
, &chunksize0
);
465 chunksize
= chunksize0
;
467 /* allocate enough memory to hold the text including a terminating \0 */
468 if (chunksize
!= SOX_SIZE_MAX
)
469 *text
= lsx_malloc((size_t)chunksize
+1);
471 *text
= lsx_malloc((size_t)chunksize
);
473 if (lsx_readbuf(ft
, *text
, (size_t) chunksize
) != chunksize
)
475 lsx_fail_errno(ft
,SOX_EOF
,"AIFF: Unexpected EOF in %s header", chunkDescription
);
478 if (chunksize
!= SOX_SIZE_MAX
)
479 *(*text
+ chunksize
) = '\0';
481 *(*text
+ chunksize
-1) = '\0';
484 /* Read past pad byte */
486 if (lsx_readbuf(ft
, &c
, (size_t)1) != 1)
488 lsx_fail_errno(ft
,SOX_EOF
,"AIFF: Unexpected EOF in %s header", chunkDescription
);
492 lsx_debug("%-10s \"%s\"", chunkDescription
, *text
);
496 /* Comment lengths are words, not double words, and we can have several, so
497 we use a special function, not textChunk().;
499 static int commentChunk(char **text
, char *chunkDescription
, sox_format_t
* ft
)
502 unsigned short numComments
;
504 unsigned short markerId
;
505 unsigned short totalCommentLength
= 0;
506 unsigned int totalReadLength
= 0;
507 unsigned int commentIndex
;
509 lsx_readdw(ft
, &chunksize
);
510 lsx_readw(ft
, &numComments
);
511 totalReadLength
+= 2; /* chunksize doesn't count */
512 for(commentIndex
= 0; commentIndex
< numComments
; commentIndex
++) {
513 unsigned short commentLength
;
515 lsx_readdw(ft
, &timeStamp
);
516 lsx_readw(ft
, &markerId
);
517 lsx_readw(ft
, &commentLength
);
518 if (((size_t)totalCommentLength
) + commentLength
> USHRT_MAX
) {
519 lsx_fail_errno(ft
,SOX_EOF
,"AIFF: Comment too long in %s header", chunkDescription
);
522 totalCommentLength
+= commentLength
;
523 /* allocate enough memory to hold the text including a terminating \0 */
524 if(commentIndex
== 0) {
525 *text
= lsx_malloc((size_t) totalCommentLength
+ 1);
528 *text
= lsx_realloc(*text
, (size_t) totalCommentLength
+ 1);
531 if (lsx_readbuf(ft
, *text
+ totalCommentLength
- commentLength
, (size_t) commentLength
) != commentLength
) {
532 lsx_fail_errno(ft
,SOX_EOF
,"AIFF: Unexpected EOF in %s header", chunkDescription
);
535 *(*text
+ totalCommentLength
) = '\0';
536 totalReadLength
+= totalCommentLength
+ 4 + 2 + 2; /* include header */
537 if (commentLength
% 2) {
538 /* Read past pad byte */
540 if (lsx_readbuf(ft
, &c
, (size_t)1) != 1) {
541 lsx_fail_errno(ft
,SOX_EOF
,"AIFF: Unexpected EOF in %s header", chunkDescription
);
544 totalReadLength
+= 1;
547 lsx_debug("%-10s \"%s\"", chunkDescription
, *text
);
548 /* make sure we read the whole chunk */
549 if (totalReadLength
< chunksize
) {
552 for (i
=0; i
< chunksize
- totalReadLength
; i
++ )
553 lsx_readbuf(ft
, &c
, (size_t)1);
558 int lsx_aiffstopread(sox_format_t
* ft
)
566 while (! lsx_eof(ft
))
568 if (lsx_readbuf(ft
, buf
, (size_t)4) != 4)
571 lsx_readdw(ft
, &chunksize
);
575 lsx_warn("Ignoring AIFF tail chunk: `%s', %u bytes long",
577 if (! strcmp(buf
, "MARK") || ! strcmp(buf
, "INST"))
578 lsx_warn(" You're stripping MIDI/loop info!");
579 while (chunksize
-- > 0)
581 if (lsx_readb(ft
, &trash
) == SOX_EOF
)
589 /* When writing, the header is supposed to contain the number of
590 samples and data bytes written.
591 Since we don't know how many samples there are until we're done,
592 we first write the header with an very large number,
593 and at the end we rewind the file and write the header again
594 with the right number. This only works if the file is seekable;
595 if it is not, the very large size remains in the header.
596 Strictly spoken this is not legal, but the playaiff utility
597 will still be able to play the resulting file. */
599 int lsx_aiffstartwrite(sox_format_t
* ft
)
603 /* Needed because lsx_rawwrite() */
604 rc
= lsx_rawstartwrite(ft
);
608 /* Compute the "very large number" so that a maximum number
609 of samples can be transmitted through a pipe without the
610 risk of causing overflow when calculating the number of bytes.
611 At 48 kHz, 16 bits stereo, this gives ~3 hours of audio.
612 Sorry, the AIFF format does not provide for an indefinite
613 number of samples. */
614 return(aiffwriteheader(ft
, (uint64_t) 0x7f000000 / ((ft
->encoding
.bits_per_sample
>>3)*ft
->signal
.channels
)));
617 int lsx_aiffstopwrite(sox_format_t
* ft
)
619 /* If we've written an odd number of bytes, write a padding
621 if (ft
->olength
% 2 == 1 && ft
->encoding
.bits_per_sample
== 8 && ft
->signal
.channels
== 1)
623 sox_sample_t buf
= 0;
624 lsx_rawwrite(ft
, &buf
, (size_t) 1);
629 lsx_fail_errno(ft
,SOX_EOF
,"Non-seekable file.");
632 if (lsx_seeki(ft
, (off_t
)0, SEEK_SET
) != 0)
634 lsx_fail_errno(ft
,errno
,"can't rewind output file to rewrite AIFF header");
637 return(aiffwriteheader(ft
, ft
->olength
/ ft
->signal
.channels
));
640 static int aiffwriteheader(sox_format_t
* ft
, uint64_t nframes
)
643 8 /*COMM hdr*/ + 18 /*COMM chunk*/ +
644 8 /*SSND hdr*/ + 12 /*SSND chunk*/;
648 size_t padded_comment_size
= 0, comment_size
= 0;
649 size_t comment_chunk_size
= 0;
650 char * comment
= lsx_cat_comments(ft
->oob
.comments
);
652 /* MARK and INST chunks */
653 if (ft
->oob
.instr
.nloops
) {
654 hsize
+= 8 /* MARK hdr */ + 2 + 16*ft
->oob
.instr
.nloops
;
655 hsize
+= 8 /* INST hdr */ + 20; /* INST chunk */
658 if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
659 ft
->encoding
.bits_per_sample
== 8)
661 else if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
662 ft
->encoding
.bits_per_sample
== 16)
664 else if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
665 ft
->encoding
.bits_per_sample
== 24)
667 else if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
668 ft
->encoding
.bits_per_sample
== 32)
672 lsx_fail_errno(ft
,SOX_EFMT
,"unsupported output encoding/size for AIFF header");
676 /* COMT comment chunk -- holds comments text with a timestamp and marker id */
677 /* We calculate the comment_chunk_size if we will be writing a comment */
678 if (ft
->oob
.comments
)
680 comment_size
= strlen(comment
);
681 /* Must put an even number of characters out.
682 * True 68k processors OS's seem to require this.
684 padded_comment_size
= ((comment_size
% 2) == 0) ?
685 comment_size
: comment_size
+ 1;
686 /* one comment, timestamp, marker ID and text count */
687 comment_chunk_size
= (2 + 4 + 2 + 2 + padded_comment_size
);
688 hsize
+= 8 /* COMT hdr */ + comment_chunk_size
;
691 lsx_writes(ft
, "FORM"); /* IFF header */
693 size
= hsize
+ nframes
* (ft
->encoding
.bits_per_sample
>> 3) * ft
->signal
.channels
;
696 lsx_warn("file size too big for accurate AIFF header");
699 lsx_writedw(ft
, (unsigned)size
);
700 lsx_writes(ft
, "AIFF"); /* File type */
702 /* Now we write the COMT comment chunk using the precomputed sizes */
703 if (ft
->oob
.comments
)
705 lsx_writes(ft
, "COMT");
706 lsx_writedw(ft
, (unsigned) comment_chunk_size
);
711 /* time stamp of comment, Unix knows of time from 1/1/1970,
712 Apple knows time from 1/1/1904 */
713 lsx_writedw(ft
, (unsigned)((sox_globals
.repeatable
? 0 : time(NULL
)) + 2082844800));
715 /* A marker ID of 0 indicates the comment is not associated
719 /* now write the count and the bytes of text */
720 lsx_writew(ft
, (unsigned) padded_comment_size
);
721 lsx_writes(ft
, comment
);
722 if (comment_size
!= padded_comment_size
)
727 /* COMM chunk -- describes encoding (and #frames) */
728 lsx_writes(ft
, "COMM");
729 lsx_writedw(ft
, 18); /* COMM chunk size */
730 lsx_writew(ft
, ft
->signal
.channels
); /* nchannels */
731 lsx_writedw(ft
, (unsigned) nframes
); /* number of frames */
732 lsx_writew(ft
, bits
); /* sample width, in bits */
733 write_ieee_extended(ft
, (double)ft
->signal
.rate
);
735 /* MARK chunk -- set markers */
736 if (ft
->oob
.instr
.nloops
) {
737 lsx_writes(ft
, "MARK");
738 if (ft
->oob
.instr
.nloops
> 2)
739 ft
->oob
.instr
.nloops
= 2;
740 lsx_writedw(ft
, 2 + 16u*ft
->oob
.instr
.nloops
);
741 lsx_writew(ft
, ft
->oob
.instr
.nloops
);
743 for(i
= 0; i
< ft
->oob
.instr
.nloops
; i
++) {
744 unsigned start
= ft
->oob
.loops
[i
].start
> UINT_MAX
746 : ft
->oob
.loops
[i
].start
;
747 unsigned end
= ft
->oob
.loops
[i
].start
+ ft
->oob
.loops
[i
].length
> UINT_MAX
749 : ft
->oob
.loops
[i
].start
+ ft
->oob
.loops
[i
].length
;
750 lsx_writew(ft
, i
+ 1);
751 lsx_writedw(ft
, start
);
754 lsx_writew(ft
, i
*2 + 1);
755 lsx_writedw(ft
, end
);
760 lsx_writes(ft
, "INST");
762 /* random MIDI shit that we default on */
763 lsx_writeb(ft
, (uint8_t)ft
->oob
.instr
.MIDInote
);
764 lsx_writeb(ft
, 0); /* detune */
765 lsx_writeb(ft
, (uint8_t)ft
->oob
.instr
.MIDIlow
);
766 lsx_writeb(ft
, (uint8_t)ft
->oob
.instr
.MIDIhi
);
767 lsx_writeb(ft
, 1); /* low velocity */
768 lsx_writeb(ft
, 127); /* hi velocity */
769 lsx_writew(ft
, 0); /* gain */
772 lsx_writew(ft
, ft
->oob
.loops
[0].type
);
773 lsx_writew(ft
, 1); /* marker 1 */
774 lsx_writew(ft
, 3); /* marker 3 */
775 /* release loop, if there */
776 if (ft
->oob
.instr
.nloops
== 2) {
777 lsx_writew(ft
, ft
->oob
.loops
[1].type
);
778 lsx_writew(ft
, 2); /* marker 2 */
779 lsx_writew(ft
, 4); /* marker 4 */
781 lsx_writew(ft
, 0); /* no release loop */
787 /* SSND chunk -- describes data */
788 lsx_writes(ft
, "SSND");
790 lsx_writedw(ft
, (unsigned) (8 + nframes
* ft
->signal
.channels
* (ft
->encoding
.bits_per_sample
>> 3)));
791 lsx_writedw(ft
, 0); /* offset */
792 lsx_writedw(ft
, 0); /* block size */
796 int lsx_aifcstartwrite(sox_format_t
* ft
)
800 /* Needed because lsx_rawwrite() */
801 rc
= lsx_rawstartwrite(ft
);
805 /* Compute the "very large number" so that a maximum number
806 of samples can be transmitted through a pipe without the
807 risk of causing overflow when calculating the number of bytes.
808 At 48 kHz, 16 bits stereo, this gives ~3 hours of music.
809 Sorry, the AIFC format does not provide for an "infinite"
810 number of samples. */
811 return(aifcwriteheader(ft
, (uint64_t) 0x7f000000 / ((ft
->encoding
.bits_per_sample
>> 3)*ft
->signal
.channels
)));
814 int lsx_aifcstopwrite(sox_format_t
* ft
)
816 /* If we've written an odd number of bytes, write a padding
818 if (ft
->olength
% 2 == 1 && ft
->encoding
.bits_per_sample
== 8 && ft
->signal
.channels
== 1)
820 sox_sample_t buf
= 0;
821 lsx_rawwrite(ft
, &buf
, (size_t) 1);
826 lsx_fail_errno(ft
,SOX_EOF
,"Non-seekable file.");
829 if (lsx_seeki(ft
, (off_t
)0, SEEK_SET
) != 0)
831 lsx_fail_errno(ft
,errno
,"can't rewind output file to rewrite AIFC header");
834 return(aifcwriteheader(ft
, ft
->olength
/ ft
->signal
.channels
));
837 static int aifcwriteheader(sox_format_t
* ft
, uint64_t nframes
)
842 char *ctype
= NULL
, *cname
= NULL
;
843 unsigned cname_len
= 0, comm_len
= 0, comm_padding
= 0;
845 if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
846 ft
->encoding
.bits_per_sample
== 8)
848 else if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
849 ft
->encoding
.bits_per_sample
== 16)
851 else if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
852 ft
->encoding
.bits_per_sample
== 24)
854 else if (ft
->encoding
.encoding
== SOX_ENCODING_SIGN2
&&
855 ft
->encoding
.bits_per_sample
== 32)
857 else if (ft
->encoding
.encoding
== SOX_ENCODING_FLOAT
&&
858 ft
->encoding
.bits_per_sample
== 32)
860 else if (ft
->encoding
.encoding
== SOX_ENCODING_FLOAT
&&
861 ft
->encoding
.bits_per_sample
== 64)
865 lsx_fail_errno(ft
,SOX_EFMT
,"unsupported output encoding/size for AIFC header");
869 /* calculate length of COMM chunk (without header) */
870 switch (ft
->encoding
.encoding
) {
871 case SOX_ENCODING_SIGN2
:
873 cname
= "not compressed";
875 case SOX_ENCODING_FLOAT
:
878 cname
= "32-bit floating point";
881 cname
= "64-bit floating point";
884 default: /* can't happen */
887 cname_len
= strlen(cname
);
888 comm_len
= 18+4+1+cname_len
;
889 comm_padding
= comm_len
%2;
891 hsize
= 12 /*FVER*/ + 8 /*COMM hdr*/ + comm_len
+comm_padding
/*COMM chunk*/ +
892 8 /*SSND hdr*/ + 12 /*SSND chunk*/;
894 lsx_writes(ft
, "FORM"); /* IFF header */
896 size
= hsize
+ nframes
* (ft
->encoding
.bits_per_sample
>> 3) * ft
->signal
.channels
;
899 lsx_warn("file size too big for accurate AIFC header");
902 lsx_writedw(ft
, (unsigned)size
);
903 lsx_writes(ft
, "AIFC"); /* File type */
906 lsx_writes(ft
, "FVER");
907 lsx_writedw(ft
, 4); /* FVER chunk size */
908 lsx_writedw(ft
, 0xa2805140); /* version_date(May23,1990,2:40pm) */
910 /* COMM chunk -- describes encoding (and #frames) */
911 lsx_writes(ft
, "COMM");
912 lsx_writedw(ft
, comm_len
+comm_padding
); /* COMM chunk size */
913 lsx_writew(ft
, ft
->signal
.channels
); /* nchannels */
914 lsx_writedw(ft
, (unsigned) nframes
); /* number of frames */
915 lsx_writew(ft
, bits
); /* sample width, in bits */
916 write_ieee_extended(ft
, (double)ft
->signal
.rate
);
918 lsx_writes(ft
, ctype
); /*compression_type*/
919 lsx_writeb(ft
, cname_len
);
920 lsx_writes(ft
, cname
);
924 /* SSND chunk -- describes data */
925 lsx_writes(ft
, "SSND");
927 lsx_writedw(ft
, (unsigned) (8 + nframes
* ft
->signal
.channels
* (ft
->encoding
.bits_per_sample
>> 3)));
928 lsx_writedw(ft
, 0); /* offset */
929 lsx_writedw(ft
, 0); /* block size */
931 /* Any Private chunks shall appear after the required chunks (FORM,FVER,COMM,SSND) */
935 static double read_ieee_extended(sox_format_t
* ft
)
937 unsigned char buf
[10];
938 if (lsx_readbuf(ft
, buf
, (size_t)10) != 10)
940 lsx_fail_errno(ft
,SOX_EOF
,"EOF while reading IEEE extended number");
943 return ConvertFromIeeeExtended(buf
);
946 static void write_ieee_extended(sox_format_t
* ft
, double x
)
949 ConvertToIeeeExtended(x
, buf
);
950 lsx_debug_more("converted %g to %o %o %o %o %o %o %o %o %o %o",
952 buf
[0], buf
[1], buf
[2], buf
[3], buf
[4],
953 buf
[5], buf
[6], buf
[7], buf
[8], buf
[9]);
954 (void)lsx_writebuf(ft
, buf
, (size_t) 10);
959 * C O N V E R T T O I E E E E X T E N D E D
962 /* Copyright (C) 1988-1991 Apple Computer, Inc.
964 * All rights reserved.
966 * Warranty Information
967 * Even though Apple has reviewed this software, Apple makes no warranty
968 * or representation, either express or implied, with respect to this
969 * software, its quality, accuracy, merchantability, or fitness for a
970 * particular purpose. As a result, this software is provided "as is,"
971 * and you, its user, are assuming the entire risk as to its quality
974 * Machine-independent I/O routines for IEEE floating-point numbers.
976 * NaN's and infinities are converted to HUGE_VAL, which
977 * happens to be infinity on IEEE machines. Unfortunately, it is
978 * impossible to preserve NaN's in a machine-independent way.
979 * Infinities are, however, preserved on IEEE machines.
981 * These routines have been tested on the following machines:
982 * Apple Macintosh, MPW 3.1 C compiler
983 * Apple Macintosh, THINK C compiler
984 * Silicon Graphics IRIS, MIPS compiler
986 * Digital Equipment VAX
989 * Implemented by Malcolm Slaney and Ken Turkowski.
991 * Malcolm Slaney contributions during 1988-1990 include big- and little-
992 * endian file I/O, conversion to and from Motorola's extended 80-bit
993 * floating-point format, and conversions to and from IEEE single-
994 * precision floating-point format.
996 * In 1991, Ken Turkowski implemented the conversions to and from
997 * IEEE double-precision format, added more precision to the extended
998 * conversions, and accommodated conversions involving +/- infinity,
999 * NaN's, and denormalized numbers.
1002 #define FloatToUnsigned(f) ((uint32_t)(((int32_t)(f - 2147483648.0)) + 2147483647) + 1)
1004 static void ConvertToIeeeExtended(double num
, char *bytes
)
1008 double fMant
, fsMant
;
1009 uint32_t hiMant
, loMant
;
1019 expon
= 0; hiMant
= 0; loMant
= 0;
1022 fMant
= frexp(num
, &expon
);
1023 if ((expon
> 16384) || !(fMant
< 1)) { /* Infinity or NaN */
1024 expon
= sign
|0x7FFF; hiMant
= 0; loMant
= 0; /* infinity */
1028 if (expon
< 0) { /* denormalized */
1029 fMant
= ldexp(fMant
, expon
);
1033 fMant
= ldexp(fMant
, 32);
1034 fsMant
= floor(fMant
);
1035 hiMant
= FloatToUnsigned(fsMant
);
1036 fMant
= ldexp(fMant
- fsMant
, 32);
1037 fsMant
= floor(fMant
);
1038 loMant
= FloatToUnsigned(fsMant
);
1042 bytes
[0] = expon
>> 8;
1044 bytes
[2] = hiMant
>> 24;
1045 bytes
[3] = hiMant
>> 16;
1046 bytes
[4] = hiMant
>> 8;
1048 bytes
[6] = loMant
>> 24;
1049 bytes
[7] = loMant
>> 16;
1050 bytes
[8] = loMant
>> 8;
1056 * C O N V E R T F R O M I E E E E X T E N D E D
1060 * Copyright (C) 1988-1991 Apple Computer, Inc.
1062 * All rights reserved.
1064 * Warranty Information
1065 * Even though Apple has reviewed this software, Apple makes no warranty
1066 * or representation, either express or implied, with respect to this
1067 * software, its quality, accuracy, merchantability, or fitness for a
1068 * particular purpose. As a result, this software is provided "as is,"
1069 * and you, its user, are assuming the entire risk as to its quality
1072 * This code may be used and freely distributed as long as it includes
1073 * this copyright notice and the above warranty information.
1075 * Machine-independent I/O routines for IEEE floating-point numbers.
1077 * NaN's and infinities are converted to HUGE_VAL, which
1078 * happens to be infinity on IEEE machines. Unfortunately, it is
1079 * impossible to preserve NaN's in a machine-independent way.
1080 * Infinities are, however, preserved on IEEE machines.
1082 * These routines have been tested on the following machines:
1083 * Apple Macintosh, MPW 3.1 C compiler
1084 * Apple Macintosh, THINK C compiler
1085 * Silicon Graphics IRIS, MIPS compiler
1086 * Cray X/MP and Y/MP
1087 * Digital Equipment VAX
1090 * Implemented by Malcolm Slaney and Ken Turkowski.
1092 * Malcolm Slaney contributions during 1988-1990 include big- and little-
1093 * endian file I/O, conversion to and from Motorola's extended 80-bit
1094 * floating-point format, and conversions to and from IEEE single-
1095 * precision floating-point format.
1097 * In 1991, Ken Turkowski implemented the conversions to and from
1098 * IEEE double-precision format, added more precision to the extended
1099 * conversions, and accommodated conversions involving +/- infinity,
1100 * NaN's, and denormalized numbers.
1103 #define UnsignedToFloat(u) (((double)((int32_t)(u - 2147483647 - 1))) + 2147483648.0)
1105 /****************************************************************
1106 * Extended precision IEEE floating-point conversion routine.
1107 ****************************************************************/
1109 static double ConvertFromIeeeExtended(unsigned char *bytes
)
1113 uint32_t hiMant
, loMant
;
1115 expon
= ((bytes
[0] & 0x7F) << 8) | (bytes
[1] & 0xFF);
1116 hiMant
= ((uint32_t)(bytes
[2] & 0xFF) << 24)
1117 | ((uint32_t)(bytes
[3] & 0xFF) << 16)
1118 | ((uint32_t)(bytes
[4] & 0xFF) << 8)
1119 | ((uint32_t)(bytes
[5] & 0xFF));
1120 loMant
= ((uint32_t)(bytes
[6] & 0xFF) << 24)
1121 | ((uint32_t)(bytes
[7] & 0xFF) << 16)
1122 | ((uint32_t)(bytes
[8] & 0xFF) << 8)
1123 | ((uint32_t)(bytes
[9] & 0xFF));
1125 if (expon
== 0 && hiMant
== 0 && loMant
== 0) {
1129 if (expon
== 0x7FFF) { /* Infinity or NaN */
1134 f
= ldexp(UnsignedToFloat(hiMant
), expon
-=31);
1135 f
+= ldexp(UnsignedToFloat(loMant
), expon
-=32);
1139 if (bytes
[0] & 0x80)