4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This file contains a set of Very Paranoid routines to convert
31 * audio file headers to in-core audio headers and vice versa.
33 * They are robust enough to handle any random file input without
34 * crashing miserably. Of course, bad audio headers coming from
35 * the calling program can cause significant problems.
41 #include <errno.h> /* needed for large file error checking */
43 #include <sys/types.h>
49 #include <libaudio_impl.h> /* include other audio hdr's */
51 /* Round up to a double boundary */
52 #define ROUND_DBL(x) (((x) + 7) & ~7)
54 #define HEADER_BUFFER 100
56 #define _MGET_(str) (char *)dgettext(TEXT_DOMAIN, str)
58 static int audio_encode_aiff(Audio_hdr
*, unsigned char *, unsigned int *);
59 static int audio_encode_au(Audio_hdr
*, char *, unsigned int,
60 unsigned char *, unsigned int *);
61 static int audio_encode_wav(Audio_hdr
*, unsigned char *, unsigned int *);
62 static double convert_from_ieee_extended(unsigned char *);
63 static void convert_to_ieee_extended(double, unsigned char *);
66 * Write an audio file header to an output stream.
68 * The file header is encoded from the supplied Audio_hdr structure.
69 * If 'infop' is not NULL, it is the address of a buffer containing 'info'
70 * data. 'ilen' specifies the size of this buffer.
71 * The entire file header will be zero-padded to a double-word boundary.
73 * Note that the file header is stored on-disk in big-endian format,
74 * regardless of the machine type.
76 * Note also that the output file descriptor must not have been set up
77 * non-blocking i/o. If non-blocking behavior is desired, set this
78 * flag after writing the file header.
81 audio_write_filehdr(int fd
, Audio_hdr
*hdrp
, int file_type
, char *infop
,
85 /* audio header type */
86 /* info buffer pointer */
91 unsigned char *buf
; /* temporary buffer */
93 /* create tmp buf for the encoding routines to work with */
94 blen
= HEADER_BUFFER
+ (infop
? ilen
: 0) + 4;
95 blen
= ROUND_DBL(blen
);
97 if (!(buf
= (unsigned char *)calloc(1, blen
))) {
98 return (AUDIO_UNIXERROR
);
103 err
= audio_encode_au(hdrp
, infop
, ilen
, buf
, &blen
);
106 err
= audio_encode_wav(hdrp
, buf
, &blen
);
109 err
= audio_encode_aiff(hdrp
, buf
, &blen
);
112 return (AUDIO_ERR_BADFILETYPE
);
115 if (err
!= AUDIO_SUCCESS
) {
119 /* Write and free the holding buffer */
120 err
= write(fd
, (char *)buf
, (int)blen
);
121 (void) free((char *)buf
);
124 return ((err
< 0) ? AUDIO_UNIXERROR
: AUDIO_ERR_BADFILEHDR
);
126 return (AUDIO_SUCCESS
);
131 * Rewrite the aiff header chunk length and the data chunk length fields.
134 audio_rewrite_aiff_filesize(int fd
, unsigned int size
, unsigned int channels
,
135 unsigned int bytes_per_sample
)
138 unsigned int tmp_uint
;
139 unsigned int tmp_uint2
;
140 unsigned int total_size
;
142 /* first fix aiff_hdr_size */
143 total_size
= size
+ sizeof (aiff_hdr_chunk_t
) +
144 AUDIO_AIFF_COMM_CHUNK_SIZE
+ sizeof (aiff_ssnd_chunk_t
);
145 tmp_uint
= total_size
- (2 * sizeof (int));
146 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint
, &tmp_uint2
);
147 offset
= sizeof (int);
148 if (lseek(fd
, offset
, SEEK_SET
) < 0) {
149 return (AUDIO_ERR_NOEFFECT
);
151 if (write(fd
, &tmp_uint2
, sizeof (tmp_uint2
)) != sizeof (tmp_uint2
)) {
152 return (AUDIO_ERR_NOEFFECT
);
155 /* fix the frame count */
156 tmp_uint
= size
/ channels
/ bytes_per_sample
;
157 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint
, &tmp_uint2
);
158 offset
= sizeof (aiff_hdr_chunk_t
) + (2 * sizeof (int)) +
160 if (lseek(fd
, offset
, SEEK_SET
) < 0) {
161 return (AUDIO_ERR_NOEFFECT
);
163 if (write(fd
, &tmp_uint2
, sizeof (tmp_uint2
)) != sizeof (tmp_uint2
)) {
164 return (AUDIO_ERR_NOEFFECT
);
167 /* fix the data size */
168 tmp_uint
= size
+ sizeof (aiff_ssnd_chunk_t
) - (2 * sizeof (int));
169 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint
, &tmp_uint2
);
170 offset
= sizeof (aiff_hdr_chunk_t
) + AUDIO_AIFF_COMM_CHUNK_SIZE
+
172 if (lseek(fd
, offset
, SEEK_SET
) < 0) {
173 return (AUDIO_ERR_NOEFFECT
);
175 if (write(fd
, &tmp_uint2
, sizeof (tmp_uint2
)) != sizeof (tmp_uint2
)) {
176 return (AUDIO_ERR_NOEFFECT
);
179 return (AUDIO_SUCCESS
);
184 * Rewrite the data size field for the .au file format. Rewrite the audio
185 * file header au_data_size field with the supplied value. Otherwise,
186 * return AUDIO_ERR_NOEFFECT.
189 audio_rewrite_au_filesize(int fd
, unsigned int size
)
196 /* seek to the position of the au_data_size member */
197 offset
= (char *)&fhdr
.au_data_size
- (char *)&fhdr
;
198 if (lseek(fd
, offset
, SEEK_SET
) < 0) {
199 return (AUDIO_ERR_NOEFFECT
);
202 /* Encode the 32-bit integer header field */
203 AUDIO_AU_HOST2FILE(&size
, &data
);
206 err
= write(fd
, (char *)&data
, sizeof (fhdr
.au_data_size
));
207 if (err
!= sizeof (fhdr
.au_data_size
))
208 return ((err
< 0) ? AUDIO_UNIXERROR
: AUDIO_ERR_BADFILEHDR
);
210 return (AUDIO_SUCCESS
);
215 * Rewrite the riff header chunk length and the data chunk length fields.
218 audio_rewrite_wav_filesize(int fd
, unsigned int size
)
226 /* seek to the position of the riff header chunk length */
227 calc_size
= size
+ sizeof (fhdr
) - sizeof (fhdr
.wav_riff_ID
) -
228 sizeof (fhdr
.wav_riff_size
);
229 AUDIO_WAV_HOST2FILE_INT(&calc_size
, &data
);
230 offset
= (char *)&fhdr
.wav_riff_size
- (char *)&fhdr
;
231 if (lseek(fd
, offset
, SEEK_SET
) < 0) {
232 return (AUDIO_ERR_NOEFFECT
);
236 err
= write(fd
, (char *)&data
, sizeof (fhdr
.wav_riff_size
));
237 if (err
!= sizeof (fhdr
.wav_riff_size
))
238 return ((err
< 0) ? AUDIO_UNIXERROR
: AUDIO_ERR_BADFILEHDR
);
240 /* now seek to the position of the data chunk length */
241 AUDIO_WAV_HOST2FILE_INT(&size
, &data
);
242 offset
= (char *)&fhdr
.wav_data_size
- (char *)&fhdr
;
243 if (lseek(fd
, offset
, SEEK_SET
) < 0) {
244 return (AUDIO_ERR_NOEFFECT
);
248 err
= write(fd
, (char *)&data
, sizeof (fhdr
.wav_data_size
));
249 if (err
!= sizeof (fhdr
.wav_data_size
))
250 return ((err
< 0) ? AUDIO_UNIXERROR
: AUDIO_ERR_BADFILEHDR
);
252 return (AUDIO_SUCCESS
);
257 * Rewrite the data size field of an audio header to the output stream if
258 * the output file is capable of seeking.
261 audio_rewrite_filesize(int fd
, int file_type
, unsigned int size
,
262 unsigned int channels
, unsigned int bytes_per_sample
)
263 /* file descriptor */
264 /* audio file type */
266 /* number of channels */
267 /* number of bytes per sample */
271 /* Can we seek back in this file and write without appending? */
272 fcntl_err
= fcntl(fd
, F_GETFL
, 0);
273 if ((fcntl_err
< 0) && ((errno
== EOVERFLOW
) || (errno
== EINVAL
))) {
274 /* Large file encountered (probably) */
277 } else if ((lseek(fd
, (off_t
)0, SEEK_SET
) < 0) ||
278 (fcntl_err
& O_APPEND
)) {
279 return (AUDIO_ERR_NOEFFECT
);
284 return (audio_rewrite_au_filesize(fd
, size
));
286 return (audio_rewrite_wav_filesize(fd
, size
));
288 return (audio_rewrite_aiff_filesize(fd
, size
, channels
,
291 return (AUDIO_ERR_BADFILETYPE
);
297 * Decode an audio file header from an input stream.
299 * The file header is decoded into the supplied Audio_hdr structure, regardless
300 * of the file format. Thus .wav and .aiff files look like .au files once the
303 * If 'infop' is not NULL, it is the address of a buffer to which the
304 * 'info' portion of the file header will be copied. 'ilen' specifies
305 * the maximum number of bytes to copy. The buffer will be NULL-terminated,
306 * even if it means over-writing the last byte.
308 * Note that the .au file header is stored on-disk in big-endian format,
309 * regardless of the machine type. This may not have been true if
310 * the file was written on a non-Sun machine. For now, such
311 * files will appear invalid.
313 * Note also that the input file descriptor must not have been set up
314 * non-blocking i/o. If non-blocking behavior is desired, set this
315 * flag after reading the file header.
318 audio_read_filehdr(int fd
, Audio_hdr
*hdrp
, int *file_type
, char *infop
,
320 /* input file descriptor */
321 /* output audio header */
322 /* audio file type */
323 /* info buffer pointer */
330 unsigned char buf
[HEADER_BUFFER
];
333 /* decode the file header and fill in the hdrp structure */
334 if ((err
= audio_decode_filehdr(fd
, buf
, file_type
, hdrp
, &isize
)) !=
339 /* Stat the file, to determine if it is a regular file. */
340 err
= fstat(fd
, &st
);
342 return (AUDIO_UNIXERROR
);
346 * If au_data_size is not indeterminate (i.e., this isn't a pipe),
347 * try to validate the au_offset and au_data_size.
349 if (*file_type
== FILE_AU
&& hdrp
->data_size
!= AUDIO_UNKNOWN_SIZE
) {
350 /* Only trust the size for regular files */
351 if (S_ISREG(st
.st_mode
)) {
352 dsize
= isize
+ hdrp
->data_size
+ sizeof (au_filehdr_t
);
353 if (st
.st_size
< dsize
) {
354 (void) fprintf(stderr
,
355 _MGET_("Warning: More audio data "
356 "than the file header specifies\n"));
357 } else if (st
.st_size
> dsize
) {
358 (void) fprintf(stderr
,
359 _MGET_("Warning: Less audio data "
360 "than the file header specifies\n"));
367 * Deal with extra header data.
369 if ((infop
!= NULL
) && (ilen
!= 0)) {
371 * If infop is non-NULL, try to read in the info data
375 err
= read(fd
, infop
, (int)isize
);
379 /* Zero any residual bytes in the text buffer */
381 (void) memset(&infop
[isize
], '\0',
382 (int)(ilen
- isize
));
384 infop
[ilen
- 1] = '\0'; /* zero-terminate */
386 resid
-= err
; /* subtract the amount read */
390 * If we truncated the info, seek or read data until info size
391 * is satisfied. If regular file, seek nearly to end and check
395 if (S_ISREG(st
.st_mode
)) {
396 err
= lseek(fd
, (off_t
)(resid
- 1), SEEK_CUR
);
398 ((err
= read(fd
, (char *)buf
, 1)) != 1))
400 } else while (resid
!= 0) {
401 char junk
[8192]; /* temporary buffer */
403 isize
= (resid
> sizeof (junk
)) ?
404 sizeof (junk
) : resid
;
405 err
= read(fd
, junk
, isize
);
412 return (AUDIO_SUCCESS
);
415 if ((err
< 0) && (errno
== EOVERFLOW
)) {
419 return ((err
< 0) ? AUDIO_UNIXERROR
: AUDIO_ERR_BADFILEHDR
);
421 return (AUDIO_SUCCESS
);
425 * Return TRUE if the named file is an audio file. Else, return FALSE.
428 audio_isaudiofile(char *name
)
432 int file_type
; /* ignored */
435 unsigned char buf
[sizeof (au_filehdr_t
)];
437 /* Open the file (set O_NONBLOCK in case the name refers to a device) */
438 fd
= open(name
, O_RDONLY
| O_NONBLOCK
);
440 if (errno
== EOVERFLOW
) {
448 /* Read the header (but not the text info). */
449 err
= read(fd
, (char *)buf
, sizeof (buf
));
451 if (errno
== EOVERFLOW
) {
460 if ((err
== sizeof (buf
)) &&
461 (audio_decode_filehdr(fd
, buf
, &file_type
, &hdr
, &isize
) ==
463 return (hdr
.encoding
);
472 * This routine tests the magic number at the head of a buffer
473 * containing the file header. The first thing in the header
474 * should be the magic number.
477 audio_endian(unsigned char *buf
, int *file_type
)
482 /* put the buffer into an int that is aligned properly */
483 (void) memcpy(&magic1
, buf
, sizeof (magic1
));
488 if (magic1
== AUDIO_AU_FILE_MAGIC
|| magic2
== AUDIO_AU_FILE_MAGIC
) {
489 *file_type
= FILE_AU
;
490 return (AUDIO_ENDIAN_BIG
);
491 } else if (magic1
== AUDIO_WAV_RIFF_ID
|| magic2
== AUDIO_WAV_RIFF_ID
) {
492 *file_type
= FILE_WAV
;
493 return (AUDIO_ENDIAN_SMALL
);
494 } else if (magic1
== AUDIO_AIFF_HDR_CHUNK_ID
||
495 magic2
== AUDIO_AIFF_HDR_CHUNK_ID
) {
496 *file_type
= FILE_AIFF
;
497 return (AUDIO_ENDIAN_BIG
);
500 return (AUDIO_ENDIAN_UNKNOWN
);
504 * Decode an aiff file header. Unlike .au and .wav, we have to process
508 decode_aiff(int fd
, unsigned char *buf
, Audio_hdr
*hdrp
, int *isize
)
510 aiff_hdr_chunk_t hdr_chunk
;
511 aiff_comm_chunk_t comm_chunk
;
512 aiff_ssnd_chunk_t ssnd_chunk
;
519 short bits_per_sample
;
522 /* we've read in 4 bytes, read in the rest of the wav header */
523 size
= sizeof (hdr_chunk
) - sizeof (hdr_chunk
.aiff_hdr_ID
);
525 /* read in the rest of the header */
526 if (read(fd
, &hdr_chunk
.aiff_hdr_size
, size
) != size
) {
527 return (AUDIO_UNIXERROR
);
530 /* see which kind of audio file we have */
531 AUDIO_AIFF_FILE2HOST_INT(&hdr_chunk
.aiff_hdr_data_type
, &data_type
);
532 if (data_type
!= AUDIO_AIFF_HDR_FORM_AIFF
) {
533 /* we can't play this version of a .aiff file */
534 return (AUDIO_ERR_BADFILEHDR
);
537 hdr_sizes
= sizeof (hdr_chunk
);
540 * We don't know what the chunk order will be, so read each, getting
541 * the data we need from each. Eventually we'll get to the end of
542 * the file, in which case we should have all of the info on the
543 * file that we need. We then lseek() back to the data to play.
545 * We start each loop by reading the chunk ID.
547 while (read(fd
, &tmp
, sizeof (tmp
)) == sizeof (tmp
)) {
548 AUDIO_AIFF_FILE2HOST_INT(&tmp
, &ID
);
550 case AUDIO_AIFF_COMM_ID
:
551 /* read in the rest of the COMM chunk */
552 size
= AUDIO_AIFF_COMM_CHUNK_SIZE
-
553 sizeof (comm_chunk
.aiff_comm_ID
);
554 if (read(fd
, &comm_chunk
.aiff_comm_size
, size
) !=
556 return (AUDIO_UNIXERROR
);
559 sr
= convert_from_ieee_extended(
560 comm_chunk
.aiff_comm_sample_rate
);
562 hdr_sizes
+= AUDIO_AIFF_COMM_CHUNK_SIZE
;
565 case AUDIO_AIFF_SSND_ID
:
566 /* read in the rest of the INST chunk */
567 size
= sizeof (ssnd_chunk
) -
568 sizeof (ssnd_chunk
.aiff_ssnd_ID
);
569 if (read(fd
, &ssnd_chunk
.aiff_ssnd_size
, size
) !=
571 return (AUDIO_UNIXERROR
);
575 * This has to be the last chunk because the audio data
576 * follows. So we should have all we need to tell the
577 * app the format information.
579 hdrp
->sample_rate
= sr
;
581 AUDIO_AIFF_FILE2HOST_SHORT(
582 &comm_chunk
.aiff_comm_channels
,
584 /* use channels to convert from short to int */
585 hdrp
->channels
= channels
;
587 AUDIO_AIFF_FILE2HOST_SHORT(
588 &comm_chunk
.aiff_comm_sample_size
,
590 switch (bits_per_sample
) {
591 case AUDIO_AIFF_COMM_8_BIT_SAMPLE_SIZE
:
592 hdrp
->encoding
= AUDIO_AU_ENCODING_LINEAR_8
;
594 case AUDIO_AIFF_COMM_16_BIT_SAMPLE_SIZE
:
595 hdrp
->encoding
= AUDIO_AU_ENCODING_LINEAR_16
;
598 return (AUDIO_ERR_BADFILEHDR
);
601 AUDIO_AIFF_FILE2HOST_INT(&ssnd_chunk
.aiff_ssnd_size
,
603 size
-= sizeof (ssnd_chunk
.aiff_ssnd_offset
) +
604 sizeof (ssnd_chunk
.aiff_ssnd_block_size
);
605 hdrp
->data_size
= size
;
607 hdr_sizes
+= sizeof (ssnd_chunk
);
609 *isize
= hdr_sizes
- sizeof (au_filehdr_t
);
611 return (AUDIO_SUCCESS
);
614 * Unknown chunk. Read the size, which is right after
615 * the ID. Then seek past it to get to the next chunk.
617 if (read(fd
, &size
, sizeof (size
)) != sizeof (size
)) {
618 return (AUDIO_UNIXERROR
);
621 if (lseek(fd
, size
, SEEK_CUR
) < 0) {
622 return (AUDIO_UNIXERROR
);
628 return (AUDIO_SUCCESS
);
630 } /* decode_aiff() */
633 * Decode an au file header.
636 decode_au(int fd
, unsigned char *buf
, Audio_hdr
*hdrp
, int *isize
,
644 /* read in the rest of the au header */
645 size
= sizeof (fhdr
) - sizeof (int);
646 (void) lseek(fd
, (off_t
)4, SEEK_SET
);
647 if (read(fd
, &buf
[sizeof (int)], size
) != size
) {
649 return (AUDIO_UNIXERROR
);
653 /* put the buffer into a structure that is aligned properly */
654 (void) memcpy(&fhdr
, buf
, sizeof (fhdr
));
656 /* Decode the 32-bit integer header fields. */
657 AUDIO_AU_FILE2HOST(&fhdr
.au_offset
, &offset
);
658 AUDIO_AU_FILE2HOST(&fhdr
.au_data_size
, &hdrp
->data_size
);
659 AUDIO_AU_FILE2HOST(&fhdr
.au_encoding
, &hdrp
->encoding
);
660 AUDIO_AU_FILE2HOST(&fhdr
.au_sample_rate
, &hdrp
->sample_rate
);
661 AUDIO_AU_FILE2HOST(&fhdr
.au_channels
, &hdrp
->channels
);
663 /* Set the info field size (ie, number of bytes left before data). */
664 *isize
= offset
- sizeof (au_filehdr_t
);
666 return (AUDIO_SUCCESS
);
671 * Decode a wav file header.
673 * .wav files are stored on-disk in little-endian format.
676 decode_wav(int fd
, unsigned char *buf
, Audio_hdr
*hdrp
, int *isize
)
681 short bits_per_sample
;
684 /* we've read in 4 bytes, read in the rest of the wav header */
685 size
= sizeof (fhdr
) - sizeof (int);
687 /* read in the rest of the header */
688 if (read(fd
, &buf
[sizeof (int)], size
) != size
) {
689 return (AUDIO_UNIXERROR
);
692 /* put the buffer into a structure that is aligned properly */
693 (void) memcpy(&fhdr
, buf
, sizeof (fhdr
));
695 /* make sure we have the correct RIFF type */
696 AUDIO_WAV_FILE2HOST_INT(&fhdr
.wav_type_ID
, &ID
);
697 if (ID
!= AUDIO_WAV_TYPE_ID
) {
698 /* not a wave file */
699 return (AUDIO_ERR_BADFILEHDR
);
702 /* decode the fields */
703 AUDIO_WAV_FILE2HOST_INT(&fhdr
.wav_fmt_ID
, &ID
);
704 if (ID
!= AUDIO_WAV_FORMAT_ID
) {
706 return (AUDIO_ERR_BADFILEHDR
);
709 AUDIO_WAV_FILE2HOST_SHORT(&fhdr
.wav_fmt_encoding
, &encoding
);
710 AUDIO_WAV_FILE2HOST_SHORT(&fhdr
.wav_fmt_channels
, &hdrp
->channels
);
711 AUDIO_WAV_FILE2HOST_INT(&fhdr
.wav_fmt_sample_rate
, &hdrp
->sample_rate
);
712 AUDIO_WAV_FILE2HOST_SHORT(&fhdr
.wav_fmt_bits_per_sample
,
715 /* convert .wav encodings to .au encodings */
717 case AUDIO_WAV_FMT_ENCODING_PCM
:
718 switch (bits_per_sample
) {
719 case AUDIO_WAV_FMT_BITS_PER_SAMPLE_8_BITS
:
720 hdrp
->encoding
= AUDIO_AU_ENCODING_LINEAR_8
;
722 case AUDIO_WAV_FMT_BITS_PER_SAMPLE_16_BITS
:
723 hdrp
->encoding
= AUDIO_AU_ENCODING_LINEAR_16
;
726 return (AUDIO_ERR_BADFILEHDR
);
729 case AUDIO_WAV_FMT_ENCODING_ALAW
:
730 hdrp
->encoding
= AUDIO_AU_ENCODING_ALAW
;
732 case AUDIO_WAV_FMT_ENCODING_MULAW
:
733 hdrp
->encoding
= AUDIO_AU_ENCODING_ULAW
;
736 return (AUDIO_ERR_BADFILEHDR
);
739 AUDIO_WAV_FILE2HOST_INT(&fhdr
.wav_data_size
, &hdrp
->data_size
);
741 *isize
= sizeof (wav_filehdr_t
) - sizeof (au_filehdr_t
);
743 return (AUDIO_SUCCESS
);
748 * Try to decode buffer containing an audio file header into an audio header.
751 audio_decode_filehdr(int fd
, unsigned char *buf
, int *file_type
,
752 Audio_hdr
*hdrp
, int *isize
)
753 /* file descriptor */
755 /* audio file type */
756 /* output audio header */
757 /* output size of info */
763 /* Test for .au first */
764 hdrp
->endian
= audio_endian(buf
, file_type
);
767 * When cat'ing a file, audioconvert will read the whole header
768 * trying to figure out the file. audioplay however, does not.
769 * Hence we check if this is a pipe and do not attempt to read
770 * any more header info if the file type is already known.
771 * Otherwise we overwrite the header data already in the buffer.
773 if (fstat(fd
, &fd_stat
) < 0) {
774 return (AUDIO_ERR_BADFILEHDR
);
776 if (S_ISFIFO(fd_stat
.st_mode
) && (*file_type
== FILE_AU
)) {
780 * Not an au file, or file type unknown. Reread the header's
781 * magic number. Fortunately this is always an int.
783 (void) lseek(fd
, (off_t
)0, SEEK_SET
);
784 err
= read(fd
, (char *)buf
, sizeof (int));
787 /* test the magic number to determine the endian */
788 if ((hdrp
->endian
= audio_endian(buf
, file_type
)) ==
789 AUDIO_ENDIAN_UNKNOWN
) {
791 return (AUDIO_ERR_BADFILEHDR
);
795 /* decode the different file types, putting the data into hdrp */
796 switch (*file_type
) {
798 if ((err
= decode_au(fd
, buf
, hdrp
, isize
, read_info
)) !=
804 if ((err
= decode_wav(fd
, buf
, hdrp
, isize
)) != AUDIO_SUCCESS
) {
809 if ((err
= decode_aiff(fd
, buf
, hdrp
, isize
)) !=
815 return (AUDIO_ERR_BADFILEHDR
);
818 /* Convert from file format info to audio format info */
819 switch (hdrp
->encoding
) {
820 case AUDIO_AU_ENCODING_ULAW
:
821 hdrp
->encoding
= AUDIO_ENCODING_ULAW
;
822 hdrp
->bytes_per_unit
= 1;
823 hdrp
->samples_per_unit
= 1;
825 case AUDIO_AU_ENCODING_ALAW
:
826 hdrp
->encoding
= AUDIO_ENCODING_ALAW
;
827 hdrp
->bytes_per_unit
= 1;
828 hdrp
->samples_per_unit
= 1;
830 case AUDIO_AU_ENCODING_LINEAR_8
:
831 if (*file_type
== FILE_WAV
) {
832 hdrp
->encoding
= AUDIO_ENCODING_LINEAR8
;
834 hdrp
->encoding
= AUDIO_ENCODING_LINEAR
;
836 hdrp
->bytes_per_unit
= 1;
837 hdrp
->samples_per_unit
= 1;
839 case AUDIO_AU_ENCODING_LINEAR_16
:
840 hdrp
->encoding
= AUDIO_ENCODING_LINEAR
;
841 hdrp
->bytes_per_unit
= 2;
842 hdrp
->samples_per_unit
= 1;
844 case AUDIO_AU_ENCODING_LINEAR_24
:
845 hdrp
->encoding
= AUDIO_ENCODING_LINEAR
;
846 hdrp
->bytes_per_unit
= 3;
847 hdrp
->samples_per_unit
= 1;
849 case AUDIO_AU_ENCODING_LINEAR_32
:
850 hdrp
->encoding
= AUDIO_ENCODING_LINEAR
;
851 hdrp
->bytes_per_unit
= 4;
852 hdrp
->samples_per_unit
= 1;
854 case AUDIO_AU_ENCODING_FLOAT
:
855 hdrp
->encoding
= AUDIO_ENCODING_FLOAT
;
856 hdrp
->bytes_per_unit
= 4;
857 hdrp
->samples_per_unit
= 1;
859 case AUDIO_AU_ENCODING_DOUBLE
:
860 hdrp
->encoding
= AUDIO_ENCODING_FLOAT
;
861 hdrp
->bytes_per_unit
= 8;
862 hdrp
->samples_per_unit
= 1;
864 case AUDIO_AU_ENCODING_ADPCM_G721
:
865 hdrp
->encoding
= AUDIO_ENCODING_G721
;
866 hdrp
->bytes_per_unit
= 1;
867 hdrp
->samples_per_unit
= 2;
869 case AUDIO_AU_ENCODING_ADPCM_G723_3
:
870 hdrp
->encoding
= AUDIO_ENCODING_G723
;
871 hdrp
->bytes_per_unit
= 3;
872 hdrp
->samples_per_unit
= 8;
874 case AUDIO_AU_ENCODING_ADPCM_G723_5
:
875 hdrp
->encoding
= AUDIO_ENCODING_G723
;
876 hdrp
->bytes_per_unit
= 5;
877 hdrp
->samples_per_unit
= 8;
881 return (AUDIO_ERR_BADFILEHDR
);
883 return (AUDIO_SUCCESS
);
887 * Encode a .aiff file header from the supplied Audio_hdr structure and
888 * store in the supplied char* buffer. blen is the size of the buffer to
889 * store the header in. Unlike .au and .wav we can't cast to a data structure.
890 * We have to build it one chunk at a time.
892 * NOTE: .aiff doesn't support unsigned 8-bit linear PCM.
895 audio_encode_aiff(Audio_hdr
*hdrp
, unsigned char *buf
, unsigned int *blen
)
898 /* output buffer size */
900 aiff_comm_chunk_t comm_chunk
;
901 aiff_hdr_chunk_t hdr_chunk
;
902 aiff_ssnd_chunk_t ssnd_chunk
;
909 /* the only encoding we support for .aiff is signed linear PCM */
910 if (hdrp
->encoding
!= AUDIO_ENCODING_LINEAR
) {
911 return (AUDIO_ERR_ENCODING
);
914 /* build the header chunk */
915 tmp_uint
= AUDIO_AIFF_HDR_CHUNK_ID
;
916 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint
, &hdr_chunk
.aiff_hdr_ID
);
917 /* needs to be fixed when closed */
918 tmp_uint
= AUDIO_AIFF_UNKNOWN_SIZE
;
919 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint
, &hdr_chunk
.aiff_hdr_size
);
920 tmp_uint
= AUDIO_AIFF_HDR_FORM_AIFF
;
921 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint
, &hdr_chunk
.aiff_hdr_data_type
);
922 (void) memcpy(&buf
[buf_size
], &hdr_chunk
, sizeof (hdr_chunk
));
923 buf_size
+= sizeof (hdr_chunk
);
925 /* build the COMM chunk */
926 tmp_uint
= AUDIO_AIFF_COMM_ID
;
927 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint
, &comm_chunk
.aiff_comm_ID
);
928 tmp_uint
= AUDIO_AIFF_COMM_SIZE
;
929 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint
, &comm_chunk
.aiff_comm_size
);
930 tmp_ushort
= hdrp
->channels
;
931 AUDIO_AIFF_HOST2FILE_SHORT(&tmp_ushort
, &comm_chunk
.aiff_comm_channels
);
932 /* needs to be fixed when closed */
933 tmp_uint
= AUDIO_AIFF_UNKNOWN_SIZE
;
934 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint
, &tmp_uint2
);
935 AUDIO_AIFF_COMM_INT2FRAMES(comm_chunk
.aiff_comm_frames
, tmp_uint2
);
936 tmp_ushort
= hdrp
->bytes_per_unit
* 8;
937 AUDIO_AIFF_HOST2FILE_SHORT(&tmp_ushort
,
938 &comm_chunk
.aiff_comm_sample_size
);
939 convert_to_ieee_extended((double)hdrp
->sample_rate
,
940 comm_chunk
.aiff_comm_sample_rate
);
941 (void) memcpy(&buf
[buf_size
], &comm_chunk
, AUDIO_AIFF_COMM_CHUNK_SIZE
);
942 buf_size
+= AUDIO_AIFF_COMM_CHUNK_SIZE
;
944 /* build the SSND chunk */
945 tmp_uint
= AUDIO_AIFF_SSND_ID
;
946 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint
, &ssnd_chunk
.aiff_ssnd_ID
);
947 /* needs to be fixed when closed */
948 tmp_uint
= AUDIO_AIFF_UNKNOWN_SIZE
;
949 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint
, &ssnd_chunk
.aiff_ssnd_size
);
950 ssnd_chunk
.aiff_ssnd_offset
= 0;
951 ssnd_chunk
.aiff_ssnd_block_size
= 0;
952 (void) memcpy(&buf
[buf_size
], &ssnd_chunk
, sizeof (ssnd_chunk
));
953 buf_size
+= sizeof (ssnd_chunk
);
957 return (AUDIO_SUCCESS
);
959 } /* audio_encode_aiff() */
962 * Encode a .au file header from the supplied Audio_hdr structure and
963 * store in the supplied char* buffer. blen is the size of the buffer to
964 * store the header in. If 'infop' is not NULL, it is the address of a
965 * buffer containing 'info' data. 'ilen' specifies the size of this buffer.
966 * The entire file header will be zero-padded to a double-word boundary.
968 * NOTE: .au doesn't support unsigned 8-bit linear PCM.
971 audio_encode_au(Audio_hdr
*hdrp
, char *infop
, unsigned int ilen
,
972 unsigned char *buf
, unsigned int *blen
)
974 /* info buffer pointer */
975 /* info buffer size */
977 /* output buffer size */
986 * Set the size of the real header (hdr size + info size).
987 * If no supplied info, make sure a minimum size is accounted for.
988 * Also, round the whole thing up to double-word alignment.
990 if ((infop
== NULL
) || (ilen
== 0)) {
994 hdrsize
= sizeof (fhdr
) + ilen
;
995 offset
= ROUND_DBL(hdrsize
);
997 /* Check the data encoding. */
998 switch (hdrp
->encoding
) {
999 case AUDIO_ENCODING_LINEAR8
:
1000 return (AUDIO_ERR_ENCODING
); /* we don't support ulinear */
1001 case AUDIO_ENCODING_ULAW
:
1002 if (hdrp
->samples_per_unit
!= 1)
1003 return (AUDIO_ERR_BADHDR
);
1005 switch (hdrp
->bytes_per_unit
) {
1007 encoding
= AUDIO_AU_ENCODING_ULAW
;
1010 return (AUDIO_ERR_BADHDR
);
1013 case AUDIO_ENCODING_ALAW
:
1014 if (hdrp
->samples_per_unit
!= 1)
1015 return (AUDIO_ERR_BADHDR
);
1017 switch (hdrp
->bytes_per_unit
) {
1019 encoding
= AUDIO_AU_ENCODING_ALAW
;
1022 return (AUDIO_ERR_BADHDR
);
1025 case AUDIO_ENCODING_LINEAR
:
1026 if (hdrp
->samples_per_unit
!= 1)
1027 return (AUDIO_ERR_BADHDR
);
1029 switch (hdrp
->bytes_per_unit
) {
1031 encoding
= AUDIO_AU_ENCODING_LINEAR_8
;
1034 encoding
= AUDIO_AU_ENCODING_LINEAR_16
;
1037 encoding
= AUDIO_AU_ENCODING_LINEAR_24
;
1040 encoding
= AUDIO_AU_ENCODING_LINEAR_32
;
1043 return (AUDIO_ERR_BADHDR
);
1046 case AUDIO_ENCODING_FLOAT
:
1047 if (hdrp
->samples_per_unit
!= 1)
1048 return (AUDIO_ERR_BADHDR
);
1050 switch (hdrp
->bytes_per_unit
) {
1052 encoding
= AUDIO_AU_ENCODING_FLOAT
;
1055 encoding
= AUDIO_AU_ENCODING_DOUBLE
;
1058 return (AUDIO_ERR_BADHDR
);
1061 case AUDIO_ENCODING_G721
:
1062 if (hdrp
->bytes_per_unit
!= 1)
1063 return (AUDIO_ERR_BADHDR
);
1064 else if (hdrp
->samples_per_unit
!= 2)
1065 return (AUDIO_ERR_BADHDR
);
1067 encoding
= AUDIO_AU_ENCODING_ADPCM_G721
;
1069 case AUDIO_ENCODING_G723
:
1070 if (hdrp
->samples_per_unit
!= 8)
1071 return (AUDIO_ERR_BADHDR
);
1072 else if (hdrp
->bytes_per_unit
== 3)
1073 encoding
= AUDIO_AU_ENCODING_ADPCM_G723_3
;
1074 else if (hdrp
->bytes_per_unit
== 5)
1075 encoding
= AUDIO_AU_ENCODING_ADPCM_G723_5
;
1077 return (AUDIO_ERR_BADHDR
);
1080 return (AUDIO_ERR_BADHDR
);
1083 /* copy the fhdr into the supplied buffer - make sure it'll fit */
1084 if (*blen
< offset
) {
1085 /* XXX - is this apropriate? */
1089 /* reset blen to actual size of hdr data */
1090 *blen
= (unsigned)offset
;
1092 magic
= AUDIO_AU_FILE_MAGIC
; /* set the magic number */
1094 /* Encode the audio header structure. */
1095 AUDIO_AU_HOST2FILE(&magic
, &fhdr
.au_magic
);
1096 AUDIO_AU_HOST2FILE(&offset
, &fhdr
.au_offset
);
1097 AUDIO_AU_HOST2FILE(&hdrp
->data_size
, &fhdr
.au_data_size
);
1098 AUDIO_AU_HOST2FILE(&encoding
, &fhdr
.au_encoding
);
1099 AUDIO_AU_HOST2FILE(&hdrp
->sample_rate
, &fhdr
.au_sample_rate
);
1100 AUDIO_AU_HOST2FILE(&hdrp
->channels
, &fhdr
.au_channels
);
1102 /* Copy to the buffer */
1103 (void) memcpy(buf
, &fhdr
, sizeof (fhdr
));
1105 /* Copy the info data, if present */
1106 if (infop
!= NULL
) {
1107 (void) memcpy(&buf
[sizeof (fhdr
)], infop
, (int)ilen
);
1111 if (offset
> hdrsize
) {
1112 (void) memset(&buf
[hdrsize
], '\0', (size_t)(offset
- hdrsize
));
1115 /* buf now has the data, just return ... */
1117 return (AUDIO_SUCCESS
);
1119 } /* audio_encode_au() */
1122 * Encode a .wav file header from the supplied Audio_hdr structure and
1123 * store in the supplied char* buffer. blen is the size of the buffer to
1124 * store the header in. .wav doesn't support an information string like
1127 * NOTE: .wav only supports a few encoding methods.
1130 audio_encode_wav(Audio_hdr
*hdrp
, unsigned char *buf
, unsigned int *blen
)
1133 /* output buffer size */
1136 int bytes_per_second
;
1137 int bytes_per_sample
;
1138 int bits_per_sample
;
1144 /* make sure we've got valid encoding and precision settings for .wav */
1145 switch (hdrp
->encoding
) {
1146 case AUDIO_ENCODING_LINEAR8
:
1147 if (hdrp
->bytes_per_unit
!= 1) {
1148 return (AUDIO_ERR_ENCODING
);
1150 encoding
= AUDIO_WAV_FMT_ENCODING_PCM
;
1152 case AUDIO_ENCODING_ULAW
:
1153 if (hdrp
->bytes_per_unit
!= 1) {
1154 return (AUDIO_ERR_ENCODING
);
1156 encoding
= AUDIO_WAV_FMT_ENCODING_MULAW
;
1158 case AUDIO_ENCODING_ALAW
:
1159 if (hdrp
->bytes_per_unit
!= 1) {
1160 return (AUDIO_ERR_ENCODING
);
1162 encoding
= AUDIO_WAV_FMT_ENCODING_ALAW
;
1164 case AUDIO_ENCODING_LINEAR
:
1165 if (hdrp
->bytes_per_unit
!= 2) {
1166 return (AUDIO_ERR_ENCODING
);
1168 encoding
= AUDIO_WAV_FMT_ENCODING_PCM
;
1171 return (AUDIO_ERR_ENCODING
);
1174 /* fill in the riff chunk */
1175 id
= AUDIO_WAV_RIFF_ID
;
1176 length
= AUDIO_WAV_UNKNOWN_SIZE
;
1177 AUDIO_WAV_HOST2FILE_INT(&id
, &fhdr
.wav_riff_ID
);
1178 AUDIO_WAV_HOST2FILE_INT(&length
, &fhdr
.wav_riff_size
);
1180 /* fill in the type chunk */
1181 type
= AUDIO_WAV_TYPE_ID
;
1182 AUDIO_WAV_HOST2FILE_INT(&type
, &fhdr
.wav_type_ID
);
1185 /* fill in the format chunk */
1186 id
= AUDIO_WAV_FORMAT_ID
;
1187 length
= AUDIO_WAV_FORMAT_SIZE
;
1188 bytes_per_second
= hdrp
->sample_rate
* hdrp
->channels
*
1189 hdrp
->bytes_per_unit
;
1190 bytes_per_sample
= hdrp
->channels
* hdrp
->bytes_per_unit
;
1191 bits_per_sample
= hdrp
->bytes_per_unit
* 8;
1193 AUDIO_WAV_HOST2FILE_INT(&id
, &fhdr
.wav_fmt_ID
);
1194 AUDIO_WAV_HOST2FILE_INT(&length
, &fhdr
.wav_fmt_size
);
1195 AUDIO_WAV_HOST2FILE_SHORT(&encoding
, &fhdr
.wav_fmt_encoding
);
1196 AUDIO_WAV_HOST2FILE_SHORT(&hdrp
->channels
, &fhdr
.wav_fmt_channels
);
1197 AUDIO_WAV_HOST2FILE_INT(&hdrp
->sample_rate
, &fhdr
.wav_fmt_sample_rate
);
1198 AUDIO_WAV_HOST2FILE_INT(&bytes_per_second
,
1199 &fhdr
.wav_fmt_bytes_per_second
);
1200 AUDIO_WAV_HOST2FILE_SHORT(&bytes_per_sample
,
1201 &fhdr
.wav_fmt_bytes_per_sample
);
1202 AUDIO_WAV_HOST2FILE_SHORT(&bits_per_sample
,
1203 &fhdr
.wav_fmt_bits_per_sample
);
1205 /* fill in the data chunk */
1206 id
= AUDIO_WAV_DATA_ID_LC
;
1207 length
= AUDIO_WAV_UNKNOWN_SIZE
;
1208 AUDIO_WAV_HOST2FILE_INT(&id
, &fhdr
.wav_data_ID
);
1209 AUDIO_WAV_HOST2FILE_INT(&length
, &fhdr
.wav_data_size
);
1211 *blen
= sizeof (fhdr
);
1213 /* copy to the buffer */
1214 (void) memcpy(buf
, &fhdr
, sizeof (fhdr
));
1216 return (AUDIO_SUCCESS
);
1218 } /* audio_encode_wav() */
1221 * Utility routine used to convert 10 byte IEEE extended float into
1222 * a regular double. Raw data arrives in an unsigned char array. Because
1223 * this is for sample rate, which is always positive, we don't worry
1227 convert_from_ieee_extended(unsigned char *data
)
1230 unsigned long high_mantissa
;
1231 unsigned long low_mantissa
;
1234 /* first 2 bytes are the exponent */
1235 exponent
= ((data
[0] & 0x7f) << 8) | data
[1];
1237 high_mantissa
= ((unsigned long)data
[2] << 24) |
1238 ((unsigned long)data
[3] << 16) |
1239 ((unsigned long)data
[4] << 8) |
1240 (unsigned long)data
[5];
1241 low_mantissa
= ((unsigned long)data
[6] << 24) |
1242 ((unsigned long)data
[7] << 16) |
1243 ((unsigned long)data
[8] << 8) |
1244 (unsigned long)data
[9];
1246 /* convert exponent and mantissas into a real double */
1247 if (exponent
== 0 && high_mantissa
== 0 && low_mantissa
== 0) {
1248 /* everything is 0, so we're done */
1251 if (exponent
== 0x7fff) { /* infinity */
1254 /* convert exponent from being unsigned to signed */
1258 value
= ldexp((double)high_mantissa
, exponent
);
1261 value
+= ldexp((double)low_mantissa
, exponent
);
1270 * Utility routine to convert a double into 10 byte IEEE extended floating
1271 * point. The new number is placed into the unsigned char array. This is a
1272 * very brain dead convesion routine. It only supports integers, but then
1273 * that should be all we need for sample rate.
1276 convert_to_ieee_extended(double value
, unsigned char *data
)
1285 while (fmantissa
< 44000) {
1290 mantissa
= (int)fmantissa
<< 16;
1292 data
[0] = exponent
>> 8;
1294 data
[2] = mantissa
>> 24;
1295 data
[3] = mantissa
>> 16;
1296 data
[4] = mantissa
>> 8;