1 /*
2 * CDDL HEADER START
3 *
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
7 * with the License.
8 *
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.
13 *
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]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * This file contains a set of Very Paranoid routines to convert
29 * audio file headers to in-core audio headers and vice versa.
30 *
31 * They are robust enough to handle any random file input without
32 * crashing miserably. Of course, bad audio headers coming from
33 * the calling program can cause significant problems.
34 */
35
36 #include <stdlib.h>
37 #include <memory.h>
38 #include <fcntl.h>
39 #include <errno.h> /* needed for large file error checking */
40 #include <stdio.h>
41 #include <sys/types.h>
42 #include <sys/file.h>
43 #include <sys/stat.h>
44 #include <libintl.h>
45 #include <math.h>
46
47 #include <libaudio_impl.h> /* include other audio hdr's */
48
49 /* Round up to a double boundary */
50 #define ROUND_DBL(x) (((x) + 7) & ~7)
51
52 #define HEADER_BUFFER 100
53
54 #define _MGET_(str) (char *)dgettext(TEXT_DOMAIN, str)
55
56 static int audio_encode_aiff(Audio_hdr *, unsigned char *, unsigned int *);
57 static int audio_encode_au(Audio_hdr *, char *, unsigned int,
58 unsigned char *, unsigned int *);
59 static int audio_encode_wav(Audio_hdr *, unsigned char *, unsigned int *);
60 static double convert_from_ieee_extended(unsigned char *);
61 static void convert_to_ieee_extended(double, unsigned char *);
62
63 /*
64 * Write an audio file header to an output stream.
65 *
66 * The file header is encoded from the supplied Audio_hdr structure.
67 * If 'infop' is not NULL, it is the address of a buffer containing 'info'
68 * data. 'ilen' specifies the size of this buffer.
69 * The entire file header will be zero-padded to a double-word boundary.
70 *
71 * Note that the file header is stored on-disk in big-endian format,
72 * regardless of the machine type.
73 *
74 * Note also that the output file descriptor must not have been set up
75 * non-blocking i/o. If non-blocking behavior is desired, set this
76 * flag after writing the file header.
77 */
78 int
audio_write_filehdr(int fd,Audio_hdr * hdrp,int file_type,char * infop,unsigned int ilen)79 audio_write_filehdr(int fd, Audio_hdr *hdrp, int file_type, char *infop,
80 unsigned int ilen)
81 /* file descriptor */
82 /* audio header */
83 /* audio header type */
84 /* info buffer pointer */
85 /* buffer size */
86 {
87 int err;
88 unsigned blen;
89 unsigned char *buf; /* temporary buffer */
90
91 /* create tmp buf for the encoding routines to work with */
92 blen = HEADER_BUFFER + (infop ? ilen : 0) + 4;
93 blen = ROUND_DBL(blen);
94
95 if (!(buf = (unsigned char *)calloc(1, blen))) {
96 return (AUDIO_UNIXERROR);
97 }
98
99 switch (file_type) {
100 case FILE_AU:
101 err = audio_encode_au(hdrp, infop, ilen, buf, &blen);
102 break;
103 case FILE_WAV:
104 err = audio_encode_wav(hdrp, buf, &blen);
105 break;
106 case FILE_AIFF:
107 err = audio_encode_aiff(hdrp, buf, &blen);
108 break;
109 default:
110 return (AUDIO_ERR_BADFILETYPE);
111 }
112
113 if (err != AUDIO_SUCCESS) {
114 return (err);
115 }
116
117 /* Write and free the holding buffer */
118 err = write(fd, (char *)buf, (int)blen);
119 (void) free((char *)buf);
120
121 if (err != blen)
122 return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
123
124 return (AUDIO_SUCCESS);
125
126 }
127
128 /*
129 * Rewrite the aiff header chunk length and the data chunk length fields.
130 */
131 static int
audio_rewrite_aiff_filesize(int fd,unsigned int size,unsigned int channels,unsigned int bytes_per_sample)132 audio_rewrite_aiff_filesize(int fd, unsigned int size, unsigned int channels,
133 unsigned int bytes_per_sample)
134 {
135 unsigned int offset;
136 unsigned int tmp_uint;
137 unsigned int tmp_uint2;
138 unsigned int total_size;
139
140 /* first fix aiff_hdr_size */
141 total_size = size + sizeof (aiff_hdr_chunk_t) +
142 AUDIO_AIFF_COMM_CHUNK_SIZE + sizeof (aiff_ssnd_chunk_t);
143 tmp_uint = total_size - (2 * sizeof (int));
144 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &tmp_uint2);
145 offset = sizeof (int);
146 if (lseek(fd, offset, SEEK_SET) < 0) {
147 return (AUDIO_ERR_NOEFFECT);
148 }
149 if (write(fd, &tmp_uint2, sizeof (tmp_uint2)) != sizeof (tmp_uint2)) {
150 return (AUDIO_ERR_NOEFFECT);
151 }
152
153 /* fix the frame count */
154 tmp_uint = size / channels / bytes_per_sample;
155 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &tmp_uint2);
156 offset = sizeof (aiff_hdr_chunk_t) + (2 * sizeof (int)) +
157 sizeof (short);
158 if (lseek(fd, offset, SEEK_SET) < 0) {
159 return (AUDIO_ERR_NOEFFECT);
160 }
161 if (write(fd, &tmp_uint2, sizeof (tmp_uint2)) != sizeof (tmp_uint2)) {
162 return (AUDIO_ERR_NOEFFECT);
163 }
164
165 /* fix the data size */
166 tmp_uint = size + sizeof (aiff_ssnd_chunk_t) - (2 * sizeof (int));
167 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &tmp_uint2);
168 offset = sizeof (aiff_hdr_chunk_t) + AUDIO_AIFF_COMM_CHUNK_SIZE +
169 sizeof (int);
170 if (lseek(fd, offset, SEEK_SET) < 0) {
171 return (AUDIO_ERR_NOEFFECT);
172 }
173 if (write(fd, &tmp_uint2, sizeof (tmp_uint2)) != sizeof (tmp_uint2)) {
174 return (AUDIO_ERR_NOEFFECT);
175 }
176
177 return (AUDIO_SUCCESS);
178
179 }
180
181 /*
182 * Rewrite the data size field for the .au file format. Rewrite the audio
183 * file header au_data_size field with the supplied value. Otherwise,
184 * return AUDIO_ERR_NOEFFECT.
185 */
186 static int
audio_rewrite_au_filesize(int fd,unsigned int size)187 audio_rewrite_au_filesize(int fd, unsigned int size)
188 {
189 au_filehdr_t fhdr;
190 int err;
191 int data;
192 int offset;
193
194 /* seek to the position of the au_data_size member */
195 offset = (char *)&fhdr.au_data_size - (char *)&fhdr;
196 if (lseek(fd, offset, SEEK_SET) < 0) {
197 return (AUDIO_ERR_NOEFFECT);
198 }
199
200 /* Encode the 32-bit integer header field */
201 AUDIO_AU_HOST2FILE(&size, &data);
202
203 /* Write the data */
204 err = write(fd, (char *)&data, sizeof (fhdr.au_data_size));
205 if (err != sizeof (fhdr.au_data_size))
206 return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
207
208 return (AUDIO_SUCCESS);
209
210 }
211
212 /*
213 * Rewrite the riff header chunk length and the data chunk length fields.
214 */
215 static int
audio_rewrite_wav_filesize(int fd,unsigned int size)216 audio_rewrite_wav_filesize(int fd, unsigned int size)
217 {
218 wav_filehdr_t fhdr;
219 int calc_size;
220 int err;
221 int data;
222 int offset;
223
224 /* seek to the position of the riff header chunk length */
225 calc_size = size + sizeof (fhdr) - sizeof (fhdr.wav_riff_ID) -
226 sizeof (fhdr.wav_riff_size);
227 AUDIO_WAV_HOST2FILE_INT(&calc_size, &data);
228 offset = (char *)&fhdr.wav_riff_size - (char *)&fhdr;
229 if (lseek(fd, offset, SEEK_SET) < 0) {
230 return (AUDIO_ERR_NOEFFECT);
231 }
232
233 /* Write the data */
234 err = write(fd, (char *)&data, sizeof (fhdr.wav_riff_size));
235 if (err != sizeof (fhdr.wav_riff_size))
236 return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
237
238 /* now seek to the position of the data chunk length */
239 AUDIO_WAV_HOST2FILE_INT(&size, &data);
240 offset = (char *)&fhdr.wav_data_size - (char *)&fhdr;
241 if (lseek(fd, offset, SEEK_SET) < 0) {
242 return (AUDIO_ERR_NOEFFECT);
243 }
244
245 /* Write the data */
246 err = write(fd, (char *)&data, sizeof (fhdr.wav_data_size));
247 if (err != sizeof (fhdr.wav_data_size))
248 return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
249
250 return (AUDIO_SUCCESS);
251
252 }
253
254 /*
255 * Rewrite the data size field of an audio header to the output stream if
256 * the output file is capable of seeking.
257 */
258 int
audio_rewrite_filesize(int fd,int file_type,unsigned int size,unsigned int channels,unsigned int bytes_per_sample)259 audio_rewrite_filesize(int fd, int file_type, unsigned int size,
260 unsigned int channels, unsigned int bytes_per_sample)
261 /* file descriptor */
262 /* audio file type */
263 /* new data size */
264 /* number of channels */
265 /* number of bytes per sample */
266 {
267 int fcntl_err;
268
269 /* Can we seek back in this file and write without appending? */
270 fcntl_err = fcntl(fd, F_GETFL, 0);
271 if ((fcntl_err < 0) && ((errno == EOVERFLOW) || (errno == EINVAL))) {
272 /* Large file encountered (probably) */
273 perror("fcntl");
274 exit(1);
275 } else if ((lseek(fd, (off_t)0, SEEK_SET) < 0) ||
276 (fcntl_err & FAPPEND)) {
277 return (AUDIO_ERR_NOEFFECT);
278 }
279
280 switch (file_type) {
281 case FILE_AU:
282 return (audio_rewrite_au_filesize(fd, size));
283 case FILE_WAV:
284 return (audio_rewrite_wav_filesize(fd, size));
285 case FILE_AIFF:
286 return (audio_rewrite_aiff_filesize(fd, size, channels,
287 bytes_per_sample));
288 default:
289 return (AUDIO_ERR_BADFILETYPE);
290 }
291 }
292
293
294 /*
295 * Decode an audio file header from an input stream.
296 *
297 * The file header is decoded into the supplied Audio_hdr structure, regardless
298 * of the file format. Thus .wav and .aiff files look like .au files once the
299 * header is decoded.
300 *
301 * If 'infop' is not NULL, it is the address of a buffer to which the
302 * 'info' portion of the file header will be copied. 'ilen' specifies
303 * the maximum number of bytes to copy. The buffer will be NULL-terminated,
304 * even if it means over-writing the last byte.
305 *
306 * Note that the .au file header is stored on-disk in big-endian format,
307 * regardless of the machine type. This may not have been true if
308 * the file was written on a non-Sun machine. For now, such
309 * files will appear invalid.
310 *
311 * Note also that the input file descriptor must not have been set up
312 * non-blocking i/o. If non-blocking behavior is desired, set this
313 * flag after reading the file header.
314 */
315 int
audio_read_filehdr(int fd,Audio_hdr * hdrp,int * file_type,char * infop,unsigned int ilen)316 audio_read_filehdr(int fd, Audio_hdr *hdrp, int *file_type, char *infop,
317 unsigned int ilen)
318 /* input file descriptor */
319 /* output audio header */
320 /* audio file type */
321 /* info buffer pointer */
322 /* buffer size */
323 {
324 int err;
325 int dsize;
326 int isize;
327 unsigned resid;
328 unsigned char buf[HEADER_BUFFER];
329 struct stat st;
330
331 /* decode the file header and fill in the hdrp structure */
332 if ((err = audio_decode_filehdr(fd, buf, file_type, hdrp, &isize)) !=
333 AUDIO_SUCCESS) {
334 goto checkerror;
335 }
336
337 /* Stat the file, to determine if it is a regular file. */
338 err = fstat(fd, &st);
339 if (err < 0) {
340 return (AUDIO_UNIXERROR);
341 }
342
343 /*
344 * If au_data_size is not indeterminate (i.e., this isn't a pipe),
345 * try to validate the au_offset and au_data_size.
346 */
347 if (*file_type == FILE_AU && hdrp->data_size != AUDIO_UNKNOWN_SIZE) {
348 /* Only trust the size for regular files */
349 if (S_ISREG(st.st_mode)) {
350 dsize = isize + hdrp->data_size + sizeof (au_filehdr_t);
351 if (st.st_size < dsize) {
352 (void) fprintf(stderr,
353 _MGET_("Warning: More audio data "
354 "than the file header specifies\n"));
355 } else if (st.st_size > dsize) {
356 (void) fprintf(stderr,
357 _MGET_("Warning: Less audio data "
358 "than the file header specifies\n"));
359 }
360 }
361 }
362
363 resid = isize;
364 /*
365 * Deal with extra header data.
366 */
367 if ((infop != NULL) && (ilen != 0)) {
368 /*
369 * If infop is non-NULL, try to read in the info data
370 */
371 if (isize > ilen)
372 isize = ilen;
373 err = read(fd, infop, (int)isize);
374 if (err != isize)
375 goto checkerror;
376
377 /* Zero any residual bytes in the text buffer */
378 if (isize < ilen)
379 (void) memset(&infop[isize], '\0',
380 (int)(ilen - isize));
381 else
382 infop[ilen - 1] = '\0'; /* zero-terminate */
383
384 resid -= err; /* subtract the amount read */
385 }
386
387 /*
388 * If we truncated the info, seek or read data until info size
389 * is satisfied. If regular file, seek nearly to end and check
390 * for eof.
391 */
392 if (resid != 0) {
393 if (S_ISREG(st.st_mode)) {
394 err = lseek(fd, (off_t)(resid - 1), SEEK_CUR);
395 if ((err < 0) ||
396 ((err = read(fd, (char *)buf, 1)) != 1))
397 goto checkerror;
398 } else while (resid != 0) {
399 char junk[8192]; /* temporary buffer */
400
401 isize = (resid > sizeof (junk)) ?
402 sizeof (junk) : resid;
403 err = read(fd, junk, isize);
404 if (err != isize)
405 goto checkerror;
406 resid -= err;
407 }
408 }
409
410 return (AUDIO_SUCCESS);
411
412 checkerror:
413 if ((err < 0) && (errno == EOVERFLOW)) {
414 perror("read");
415 exit(1);
416 } else {
417 return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
418 }
419 return (AUDIO_SUCCESS);
420 }
421
422 /*
423 * Return TRUE if the named file is an audio file. Else, return FALSE.
424 */
425 int
audio_isaudiofile(char * name)426 audio_isaudiofile(char *name)
427 {
428 int fd;
429 int err;
430 int file_type; /* ignored */
431 int isize;
432 Audio_hdr hdr;
433 unsigned char buf[sizeof (au_filehdr_t)];
434
435 /* Open the file (set O_NONBLOCK in case the name refers to a device) */
436 fd = open(name, O_RDONLY | O_NONBLOCK);
437 if (fd < 0) {
438 if (errno == EOVERFLOW) {
439 perror("open");
440 exit(1);
441 } else {
442 return (FALSE);
443 }
444 }
445
446 /* Read the header (but not the text info). */
447 err = read(fd, (char *)buf, sizeof (buf));
448 if (err < 0) {
449 if (errno == EOVERFLOW) {
450 perror("open");
451 exit(1);
452 } else {
453 return (FALSE);
454 }
455 }
456 (void) close(fd);
457
458 if ((err == sizeof (buf)) &&
459 (audio_decode_filehdr(fd, buf, &file_type, &hdr, &isize) ==
460 AUDIO_SUCCESS)) {
461 return (hdr.encoding);
462 } else {
463 return (FALSE);
464 }
465 }
466
467 /*
468 * audio_endian()
469 *
470 * This routine tests the magic number at the head of a buffer
471 * containing the file header. The first thing in the header
472 * should be the magic number.
473 */
474 static int
audio_endian(unsigned char * buf,int * file_type)475 audio_endian(unsigned char *buf, int *file_type)
476 {
477 unsigned int magic1;
478 unsigned int magic2;
479
480 /* put the buffer into an int that is aligned properly */
481 (void) memcpy(&magic1, buf, sizeof (magic1));
482
483 magic2 = magic1;
484 SWABI(magic2);
485
486 if (magic1 == AUDIO_AU_FILE_MAGIC || magic2 == AUDIO_AU_FILE_MAGIC) {
487 *file_type = FILE_AU;
488 return (AUDIO_ENDIAN_BIG);
489 } else if (magic1 == AUDIO_WAV_RIFF_ID || magic2 == AUDIO_WAV_RIFF_ID) {
490 *file_type = FILE_WAV;
491 return (AUDIO_ENDIAN_SMALL);
492 } else if (magic1 == AUDIO_AIFF_HDR_CHUNK_ID ||
493 magic2 == AUDIO_AIFF_HDR_CHUNK_ID) {
494 *file_type = FILE_AIFF;
495 return (AUDIO_ENDIAN_BIG);
496 }
497
498 return (AUDIO_ENDIAN_UNKNOWN);
499 }
500
501 /*
502 * Decode an aiff file header. Unlike .au and .wav, we have to process
503 * by chunk.
504 */
505 static int
decode_aiff(int fd,unsigned char * buf,Audio_hdr * hdrp,int * isize)506 decode_aiff(int fd, unsigned char *buf, Audio_hdr *hdrp, int *isize)
507 {
508 aiff_hdr_chunk_t hdr_chunk;
509 aiff_comm_chunk_t comm_chunk;
510 aiff_ssnd_chunk_t ssnd_chunk;
511 uint32_t ID;
512 uint32_t size;
513 uint32_t tmp;
514 int data_type;
515 int hdr_sizes;
516 int sr;
517 short bits_per_sample;
518 short channels;
519
520 /* we've read in 4 bytes, read in the rest of the wav header */
521 size = sizeof (hdr_chunk) - sizeof (hdr_chunk.aiff_hdr_ID);
522
523 /* read in the rest of the header */
524 if (read(fd, &hdr_chunk.aiff_hdr_size, size) != size) {
525 return (AUDIO_UNIXERROR);
526 }
527
528 /* see which kind of audio file we have */
529 AUDIO_AIFF_FILE2HOST_INT(&hdr_chunk.aiff_hdr_data_type, &data_type);
530 if (data_type != AUDIO_AIFF_HDR_FORM_AIFF) {
531 /* we can't play this version of a .aiff file */
532 return (AUDIO_ERR_BADFILEHDR);
533 }
534
535 hdr_sizes = sizeof (hdr_chunk);
536
537 /*
538 * We don't know what the chunk order will be, so read each, getting
539 * the data we need from each. Eventually we'll get to the end of
540 * the file, in which case we should have all of the info on the
541 * file that we need. We then lseek() back to the data to play.
542 *
543 * We start each loop by reading the chunk ID.
544 */
545 while (read(fd, &tmp, sizeof (tmp)) == sizeof (tmp)) {
546 AUDIO_AIFF_FILE2HOST_INT(&tmp, &ID);
547 switch (ID) {
548 case AUDIO_AIFF_COMM_ID:
549 /* read in the rest of the COMM chunk */
550 size = AUDIO_AIFF_COMM_CHUNK_SIZE -
551 sizeof (comm_chunk.aiff_comm_ID);
552 if (read(fd, &comm_chunk.aiff_comm_size, size) !=
553 size) {
554 return (AUDIO_UNIXERROR);
555 }
556
557 sr = convert_from_ieee_extended(
558 comm_chunk.aiff_comm_sample_rate);
559
560 hdr_sizes += AUDIO_AIFF_COMM_CHUNK_SIZE;
561
562 break;
563 case AUDIO_AIFF_SSND_ID:
564 /* read in the rest of the INST chunk */
565 size = sizeof (ssnd_chunk) -
566 sizeof (ssnd_chunk.aiff_ssnd_ID);
567 if (read(fd, &ssnd_chunk.aiff_ssnd_size, size) !=
568 size) {
569 return (AUDIO_UNIXERROR);
570 }
571
572 /*
573 * This has to be the last chunk because the audio data
574 * follows. So we should have all we need to tell the
575 * app the format information.
576 */
577 hdrp->sample_rate = sr;
578
579 AUDIO_AIFF_FILE2HOST_SHORT(
580 &comm_chunk.aiff_comm_channels,
581 &channels);
582 /* use channels to convert from short to int */
583 hdrp->channels = channels;
584
585 AUDIO_AIFF_FILE2HOST_SHORT(
586 &comm_chunk.aiff_comm_sample_size,
587 &bits_per_sample);
588 switch (bits_per_sample) {
589 case AUDIO_AIFF_COMM_8_BIT_SAMPLE_SIZE:
590 hdrp->encoding = AUDIO_AU_ENCODING_LINEAR_8;
591 break;
592 case AUDIO_AIFF_COMM_16_BIT_SAMPLE_SIZE:
593 hdrp->encoding = AUDIO_AU_ENCODING_LINEAR_16;
594 break;
595 default:
596 return (AUDIO_ERR_BADFILEHDR);
597 }
598
599 AUDIO_AIFF_FILE2HOST_INT(&ssnd_chunk.aiff_ssnd_size,
600 &size);
601 size -= sizeof (ssnd_chunk.aiff_ssnd_offset) +
602 sizeof (ssnd_chunk.aiff_ssnd_block_size);
603 hdrp->data_size = size;
604
605 hdr_sizes += sizeof (ssnd_chunk);
606
607 *isize = hdr_sizes - sizeof (au_filehdr_t);
608
609 return (AUDIO_SUCCESS);
610 default:
611 /*
612 * Unknown chunk. Read the size, which is right after
613 * the ID. Then seek past it to get to the next chunk.
614 */
615 if (read(fd, &size, sizeof (size)) != sizeof (size)) {
616 return (AUDIO_UNIXERROR);
617 }
618
619 if (lseek(fd, size, SEEK_CUR) < 0) {
620 return (AUDIO_UNIXERROR);
621 }
622 break;
623 }
624 }
625
626 return (AUDIO_SUCCESS);
627
628 } /* decode_aiff() */
629
630 /*
631 * Decode an au file header.
632 */
633 static int
decode_au(int fd,unsigned char * buf,Audio_hdr * hdrp,int * isize,boolean_t read_info)634 decode_au(int fd, unsigned char *buf, Audio_hdr *hdrp, int *isize,
635 boolean_t read_info)
636 {
637 au_filehdr_t fhdr;
638 int offset;
639 int size;
640
641 if (read_info) {
642 /* read in the rest of the au header */
643 size = sizeof (fhdr) - sizeof (int);
644 (void) lseek(fd, (off_t)4, SEEK_SET);
645 if (read(fd, &buf[sizeof (int)], size) != size) {
646
647 return (AUDIO_UNIXERROR);
648 }
649 }
650
651 /* put the buffer into a structure that is aligned properly */
652 (void) memcpy(&fhdr, buf, sizeof (fhdr));
653
654 /* Decode the 32-bit integer header fields. */
655 AUDIO_AU_FILE2HOST(&fhdr.au_offset, &offset);
656 AUDIO_AU_FILE2HOST(&fhdr.au_data_size, &hdrp->data_size);
657 AUDIO_AU_FILE2HOST(&fhdr.au_encoding, &hdrp->encoding);
658 AUDIO_AU_FILE2HOST(&fhdr.au_sample_rate, &hdrp->sample_rate);
659 AUDIO_AU_FILE2HOST(&fhdr.au_channels, &hdrp->channels);
660
661 /* Set the info field size (ie, number of bytes left before data). */
662 *isize = offset - sizeof (au_filehdr_t);
663
664 return (AUDIO_SUCCESS);
665
666 } /* decode_au() */
667
668 /*
669 * Decode a wav file header.
670 *
671 * .wav files are stored on-disk in little-endian format.
672 */
673 static int
decode_wav(int fd,unsigned char * buf,Audio_hdr * hdrp,int * isize)674 decode_wav(int fd, unsigned char *buf, Audio_hdr *hdrp, int *isize)
675 {
676 wav_filehdr_t fhdr;
677 uint32_t ID;
678 uint32_t size;
679 short bits_per_sample;
680 short encoding;
681
682 /* we've read in 4 bytes, read in the rest of the wav header */
683 size = sizeof (fhdr) - sizeof (int);
684
685 /* read in the rest of the header */
686 if (read(fd, &buf[sizeof (int)], size) != size) {
687 return (AUDIO_UNIXERROR);
688 }
689
690 /* put the buffer into a structure that is aligned properly */
691 (void) memcpy(&fhdr, buf, sizeof (fhdr));
692
693 /* make sure we have the correct RIFF type */
694 AUDIO_WAV_FILE2HOST_INT(&fhdr.wav_type_ID, &ID);
695 if (ID != AUDIO_WAV_TYPE_ID) {
696 /* not a wave file */
697 return (AUDIO_ERR_BADFILEHDR);
698 }
699
700 /* decode the fields */
701 AUDIO_WAV_FILE2HOST_INT(&fhdr.wav_fmt_ID, &ID);
702 if (ID != AUDIO_WAV_FORMAT_ID) {
703 /* mangled format */
704 return (AUDIO_ERR_BADFILEHDR);
705 }
706
707 AUDIO_WAV_FILE2HOST_SHORT(&fhdr.wav_fmt_encoding, &encoding);
708 AUDIO_WAV_FILE2HOST_SHORT(&fhdr.wav_fmt_channels, &hdrp->channels);
709 AUDIO_WAV_FILE2HOST_INT(&fhdr.wav_fmt_sample_rate, &hdrp->sample_rate);
710 AUDIO_WAV_FILE2HOST_SHORT(&fhdr.wav_fmt_bits_per_sample,
711 &bits_per_sample);
712
713 /* convert .wav encodings to .au encodings */
714 switch (encoding) {
715 case AUDIO_WAV_FMT_ENCODING_PCM:
716 switch (bits_per_sample) {
717 case AUDIO_WAV_FMT_BITS_PER_SAMPLE_8_BITS:
718 hdrp->encoding = AUDIO_AU_ENCODING_LINEAR_8;
719 break;
720 case AUDIO_WAV_FMT_BITS_PER_SAMPLE_16_BITS:
721 hdrp->encoding = AUDIO_AU_ENCODING_LINEAR_16;
722 break;
723 default:
724 return (AUDIO_ERR_BADFILEHDR);
725 }
726 break;
727 case AUDIO_WAV_FMT_ENCODING_ALAW:
728 hdrp->encoding = AUDIO_AU_ENCODING_ALAW;
729 break;
730 case AUDIO_WAV_FMT_ENCODING_MULAW:
731 hdrp->encoding = AUDIO_AU_ENCODING_ULAW;
732 break;
733 default:
734 return (AUDIO_ERR_BADFILEHDR);
735 }
736
737 AUDIO_WAV_FILE2HOST_INT(&fhdr.wav_data_size, &hdrp->data_size);
738
739 *isize = sizeof (wav_filehdr_t) - sizeof (au_filehdr_t);
740
741 return (AUDIO_SUCCESS);
742
743 } /* decode_wav() */
744
745 /*
746 * Try to decode buffer containing an audio file header into an audio header.
747 */
748 int
audio_decode_filehdr(int fd,unsigned char * buf,int * file_type,Audio_hdr * hdrp,int * isize)749 audio_decode_filehdr(int fd, unsigned char *buf, int *file_type,
750 Audio_hdr *hdrp, int *isize)
751 /* file descriptor */
752 /* buffer address */
753 /* audio file type */
754 /* output audio header */
755 /* output size of info */
756 {
757 int err;
758 struct stat fd_stat;
759 boolean_t read_info;
760
761 /* Test for .au first */
762 hdrp->endian = audio_endian(buf, file_type);
763
764 /*
765 * When cat'ing a file, audioconvert will read the whole header
766 * trying to figure out the file. audioplay however, does not.
767 * Hence we check if this is a pipe and do not attempt to read
768 * any more header info if the file type is already known.
769 * Otherwise we overwrite the header data already in the buffer.
770 */
771 if (fstat(fd, &fd_stat) < 0) {
772 return (AUDIO_ERR_BADFILEHDR);
773 }
774 if (S_ISFIFO(fd_stat.st_mode) && (*file_type == FILE_AU)) {
775 read_info = B_FALSE;
776 } else {
777 /*
778 * Not an au file, or file type unknown. Reread the header's
779 * magic number. Fortunately this is always an int.
780 */
781 (void) lseek(fd, (off_t)0, SEEK_SET);
782 err = read(fd, (char *)buf, sizeof (int));
783 read_info = B_TRUE;
784
785 /* test the magic number to determine the endian */
786 if ((hdrp->endian = audio_endian(buf, file_type)) ==
787 AUDIO_ENDIAN_UNKNOWN) {
788
789 return (AUDIO_ERR_BADFILEHDR);
790 }
791 }
792
793 /* decode the different file types, putting the data into hdrp */
794 switch (*file_type) {
795 case FILE_AU:
796 if ((err = decode_au(fd, buf, hdrp, isize, read_info)) !=
797 AUDIO_SUCCESS) {
798 return (err);
799 }
800 break;
801 case FILE_WAV:
802 if ((err = decode_wav(fd, buf, hdrp, isize)) != AUDIO_SUCCESS) {
803 return (err);
804 }
805 break;
806 case FILE_AIFF:
807 if ((err = decode_aiff(fd, buf, hdrp, isize)) !=
808 AUDIO_SUCCESS) {
809 return (err);
810 }
811 break;
812 default:
813 return (AUDIO_ERR_BADFILEHDR);
814 }
815
816 /* Convert from file format info to audio format info */
817 switch (hdrp->encoding) {
818 case AUDIO_AU_ENCODING_ULAW:
819 hdrp->encoding = AUDIO_ENCODING_ULAW;
820 hdrp->bytes_per_unit = 1;
821 hdrp->samples_per_unit = 1;
822 break;
823 case AUDIO_AU_ENCODING_ALAW:
824 hdrp->encoding = AUDIO_ENCODING_ALAW;
825 hdrp->bytes_per_unit = 1;
826 hdrp->samples_per_unit = 1;
827 break;
828 case AUDIO_AU_ENCODING_LINEAR_8:
829 if (*file_type == FILE_WAV) {
830 hdrp->encoding = AUDIO_ENCODING_LINEAR8;
831 } else {
832 hdrp->encoding = AUDIO_ENCODING_LINEAR;
833 }
834 hdrp->bytes_per_unit = 1;
835 hdrp->samples_per_unit = 1;
836 break;
837 case AUDIO_AU_ENCODING_LINEAR_16:
838 hdrp->encoding = AUDIO_ENCODING_LINEAR;
839 hdrp->bytes_per_unit = 2;
840 hdrp->samples_per_unit = 1;
841 break;
842 case AUDIO_AU_ENCODING_LINEAR_24:
843 hdrp->encoding = AUDIO_ENCODING_LINEAR;
844 hdrp->bytes_per_unit = 3;
845 hdrp->samples_per_unit = 1;
846 break;
847 case AUDIO_AU_ENCODING_LINEAR_32:
848 hdrp->encoding = AUDIO_ENCODING_LINEAR;
849 hdrp->bytes_per_unit = 4;
850 hdrp->samples_per_unit = 1;
851 break;
852 case AUDIO_AU_ENCODING_FLOAT:
853 hdrp->encoding = AUDIO_ENCODING_FLOAT;
854 hdrp->bytes_per_unit = 4;
855 hdrp->samples_per_unit = 1;
856 break;
857 case AUDIO_AU_ENCODING_DOUBLE:
858 hdrp->encoding = AUDIO_ENCODING_FLOAT;
859 hdrp->bytes_per_unit = 8;
860 hdrp->samples_per_unit = 1;
861 break;
862 case AUDIO_AU_ENCODING_ADPCM_G721:
863 hdrp->encoding = AUDIO_ENCODING_G721;
864 hdrp->bytes_per_unit = 1;
865 hdrp->samples_per_unit = 2;
866 break;
867 case AUDIO_AU_ENCODING_ADPCM_G723_3:
868 hdrp->encoding = AUDIO_ENCODING_G723;
869 hdrp->bytes_per_unit = 3;
870 hdrp->samples_per_unit = 8;
871 break;
872 case AUDIO_AU_ENCODING_ADPCM_G723_5:
873 hdrp->encoding = AUDIO_ENCODING_G723;
874 hdrp->bytes_per_unit = 5;
875 hdrp->samples_per_unit = 8;
876 break;
877
878 default:
879 return (AUDIO_ERR_BADFILEHDR);
880 }
881 return (AUDIO_SUCCESS);
882 }
883
884 /*
885 * Encode a .aiff file header from the supplied Audio_hdr structure and
886 * store in the supplied char* buffer. blen is the size of the buffer to
887 * store the header in. Unlike .au and .wav we can't cast to a data structure.
888 * We have to build it one chunk at a time.
889 *
890 * NOTE: .aiff doesn't support unsigned 8-bit linear PCM.
891 */
892 static int
audio_encode_aiff(Audio_hdr * hdrp,unsigned char * buf,unsigned int * blen)893 audio_encode_aiff(Audio_hdr *hdrp, unsigned char *buf, unsigned int *blen)
894 /* audio header */
895 /* output buffer */
896 /* output buffer size */
897 {
898 aiff_comm_chunk_t comm_chunk;
899 aiff_hdr_chunk_t hdr_chunk;
900 aiff_ssnd_chunk_t ssnd_chunk;
901 uint32_t tmp_uint;
902 uint32_t tmp_uint2;
903 int buf_size = 0;
904 uint16_t tmp_ushort;
905
906 /* the only encoding we support for .aiff is signed linear PCM */
907 if (hdrp->encoding != AUDIO_ENCODING_LINEAR) {
908 return (AUDIO_ERR_ENCODING);
909 }
910
911 /* build the header chunk */
912 tmp_uint = AUDIO_AIFF_HDR_CHUNK_ID;
913 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &hdr_chunk.aiff_hdr_ID);
914 /* needs to be fixed when closed */
915 tmp_uint = AUDIO_AIFF_UNKNOWN_SIZE;
916 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &hdr_chunk.aiff_hdr_size);
917 tmp_uint = AUDIO_AIFF_HDR_FORM_AIFF;
918 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &hdr_chunk.aiff_hdr_data_type);
919 (void) memcpy(&buf[buf_size], &hdr_chunk, sizeof (hdr_chunk));
920 buf_size += sizeof (hdr_chunk);
921
922 /* build the COMM chunk */
923 tmp_uint = AUDIO_AIFF_COMM_ID;
924 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &comm_chunk.aiff_comm_ID);
925 tmp_uint = AUDIO_AIFF_COMM_SIZE;
926 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &comm_chunk.aiff_comm_size);
927 tmp_ushort = hdrp->channels;
928 AUDIO_AIFF_HOST2FILE_SHORT(&tmp_ushort, &comm_chunk.aiff_comm_channels);
929 /* needs to be fixed when closed */
930 tmp_uint = AUDIO_AIFF_UNKNOWN_SIZE;
931 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &tmp_uint2);
932 AUDIO_AIFF_COMM_INT2FRAMES(comm_chunk.aiff_comm_frames, tmp_uint2);
933 tmp_ushort = hdrp->bytes_per_unit * 8;
934 AUDIO_AIFF_HOST2FILE_SHORT(&tmp_ushort,
935 &comm_chunk.aiff_comm_sample_size);
936 convert_to_ieee_extended((double)hdrp->sample_rate,
937 comm_chunk.aiff_comm_sample_rate);
938 (void) memcpy(&buf[buf_size], &comm_chunk, AUDIO_AIFF_COMM_CHUNK_SIZE);
939 buf_size += AUDIO_AIFF_COMM_CHUNK_SIZE;
940
941 /* build the SSND chunk */
942 tmp_uint = AUDIO_AIFF_SSND_ID;
943 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &ssnd_chunk.aiff_ssnd_ID);
944 /* needs to be fixed when closed */
945 tmp_uint = AUDIO_AIFF_UNKNOWN_SIZE;
946 AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &ssnd_chunk.aiff_ssnd_size);
947 ssnd_chunk.aiff_ssnd_offset = 0;
948 ssnd_chunk.aiff_ssnd_block_size = 0;
949 (void) memcpy(&buf[buf_size], &ssnd_chunk, sizeof (ssnd_chunk));
950 buf_size += sizeof (ssnd_chunk);
951
952 *blen = buf_size;
953
954 return (AUDIO_SUCCESS);
955
956 } /* audio_encode_aiff() */
957
958 /*
959 * Encode a .au file header from the supplied Audio_hdr structure and
960 * store in the supplied char* buffer. blen is the size of the buffer to
961 * store the header in. If 'infop' is not NULL, it is the address of a
962 * buffer containing 'info' data. 'ilen' specifies the size of this buffer.
963 * The entire file header will be zero-padded to a double-word boundary.
964 *
965 * NOTE: .au doesn't support unsigned 8-bit linear PCM.
966 */
967 static int
audio_encode_au(Audio_hdr * hdrp,char * infop,unsigned int ilen,unsigned char * buf,unsigned int * blen)968 audio_encode_au(Audio_hdr *hdrp, char *infop, unsigned int ilen,
969 unsigned char *buf, unsigned int *blen)
970 /* audio header */
971 /* info buffer pointer */
972 /* info buffer size */
973 /* output buffer */
974 /* output buffer size */
975 {
976 au_filehdr_t fhdr;
977 int encoding;
978 int hdrsize;
979 int magic;
980 int offset;
981
982 /*
983 * Set the size of the real header (hdr size + info size).
984 * If no supplied info, make sure a minimum size is accounted for.
985 * Also, round the whole thing up to double-word alignment.
986 */
987 if ((infop == NULL) || (ilen == 0)) {
988 infop = NULL;
989 ilen = 4;
990 }
991 hdrsize = sizeof (fhdr) + ilen;
992 offset = ROUND_DBL(hdrsize);
993
994 /* Check the data encoding. */
995 switch (hdrp->encoding) {
996 case AUDIO_ENCODING_LINEAR8:
997 return (AUDIO_ERR_ENCODING); /* we don't support ulinear */
998 case AUDIO_ENCODING_ULAW:
999 if (hdrp->samples_per_unit != 1)
1000 return (AUDIO_ERR_BADHDR);
1001
1002 switch (hdrp->bytes_per_unit) {
1003 case 1:
1004 encoding = AUDIO_AU_ENCODING_ULAW;
1005 break;
1006 default:
1007 return (AUDIO_ERR_BADHDR);
1008 }
1009 break;
1010 case AUDIO_ENCODING_ALAW:
1011 if (hdrp->samples_per_unit != 1)
1012 return (AUDIO_ERR_BADHDR);
1013
1014 switch (hdrp->bytes_per_unit) {
1015 case 1:
1016 encoding = AUDIO_AU_ENCODING_ALAW;
1017 break;
1018 default:
1019 return (AUDIO_ERR_BADHDR);
1020 }
1021 break;
1022 case AUDIO_ENCODING_LINEAR:
1023 if (hdrp->samples_per_unit != 1)
1024 return (AUDIO_ERR_BADHDR);
1025
1026 switch (hdrp->bytes_per_unit) {
1027 case 1:
1028 encoding = AUDIO_AU_ENCODING_LINEAR_8;
1029 break;
1030 case 2:
1031 encoding = AUDIO_AU_ENCODING_LINEAR_16;
1032 break;
1033 case 3:
1034 encoding = AUDIO_AU_ENCODING_LINEAR_24;
1035 break;
1036 case 4:
1037 encoding = AUDIO_AU_ENCODING_LINEAR_32;
1038 break;
1039 default:
1040 return (AUDIO_ERR_BADHDR);
1041 }
1042 break;
1043 case AUDIO_ENCODING_FLOAT:
1044 if (hdrp->samples_per_unit != 1)
1045 return (AUDIO_ERR_BADHDR);
1046
1047 switch (hdrp->bytes_per_unit) {
1048 case 4:
1049 encoding = AUDIO_AU_ENCODING_FLOAT;
1050 break;
1051 case 8:
1052 encoding = AUDIO_AU_ENCODING_DOUBLE;
1053 break;
1054 default:
1055 return (AUDIO_ERR_BADHDR);
1056 }
1057 break;
1058 case AUDIO_ENCODING_G721:
1059 if (hdrp->bytes_per_unit != 1)
1060 return (AUDIO_ERR_BADHDR);
1061 else if (hdrp->samples_per_unit != 2)
1062 return (AUDIO_ERR_BADHDR);
1063 else
1064 encoding = AUDIO_AU_ENCODING_ADPCM_G721;
1065 break;
1066 case AUDIO_ENCODING_G723:
1067 if (hdrp->samples_per_unit != 8)
1068 return (AUDIO_ERR_BADHDR);
1069 else if (hdrp->bytes_per_unit == 3)
1070 encoding = AUDIO_AU_ENCODING_ADPCM_G723_3;
1071 else if (hdrp->bytes_per_unit == 5)
1072 encoding = AUDIO_AU_ENCODING_ADPCM_G723_5;
1073 else
1074 return (AUDIO_ERR_BADHDR);
1075 break;
1076 default:
1077 return (AUDIO_ERR_BADHDR);
1078 }
1079
1080 /* copy the fhdr into the supplied buffer - make sure it'll fit */
1081 if (*blen < offset) {
1082 /* XXX - is this apropriate? */
1083 return (AUDIO_EOF);
1084 }
1085
1086 /* reset blen to actual size of hdr data */
1087 *blen = (unsigned)offset;
1088
1089 magic = AUDIO_AU_FILE_MAGIC; /* set the magic number */
1090
1091 /* Encode the audio header structure. */
1092 AUDIO_AU_HOST2FILE(&magic, &fhdr.au_magic);
1093 AUDIO_AU_HOST2FILE(&offset, &fhdr.au_offset);
1094 AUDIO_AU_HOST2FILE(&hdrp->data_size, &fhdr.au_data_size);
1095 AUDIO_AU_HOST2FILE(&encoding, &fhdr.au_encoding);
1096 AUDIO_AU_HOST2FILE(&hdrp->sample_rate, &fhdr.au_sample_rate);
1097 AUDIO_AU_HOST2FILE(&hdrp->channels, &fhdr.au_channels);
1098
1099 /* Copy to the buffer */
1100 (void) memcpy(buf, &fhdr, sizeof (fhdr));
1101
1102 /* Copy the info data, if present */
1103 if (infop != NULL) {
1104 (void) memcpy(&buf[sizeof (fhdr)], infop, (int)ilen);
1105 buf += ilen;
1106 }
1107
1108 if (offset > hdrsize) {
1109 (void) memset(&buf[hdrsize], '\0', (size_t)(offset - hdrsize));
1110 }
1111
1112 /* buf now has the data, just return ... */
1113
1114 return (AUDIO_SUCCESS);
1115
1116 } /* audio_encode_au() */
1117
1118 /*
1119 * Encode a .wav file header from the supplied Audio_hdr structure and
1120 * store in the supplied char* buffer. blen is the size of the buffer to
1121 * store the header in. .wav doesn't support an information string like
1122 * .au does.
1123 *
1124 * NOTE: .wav only supports a few encoding methods.
1125 */
1126 static int
audio_encode_wav(Audio_hdr * hdrp,unsigned char * buf,unsigned int * blen)1127 audio_encode_wav(Audio_hdr *hdrp, unsigned char *buf, unsigned int *blen)
1128 /* audio header */
1129 /* output buffer */
1130 /* output buffer size */
1131 {
1132 wav_filehdr_t fhdr;
1133 int bytes_per_second;
1134 int bytes_per_sample;
1135 int bits_per_sample;
1136 int id;
1137 int length;
1138 int type;
1139 short encoding;
1140
1141 /* make sure we've got valid encoding and precision settings for .wav */
1142 switch (hdrp->encoding) {
1143 case AUDIO_ENCODING_LINEAR8:
1144 if (hdrp->bytes_per_unit != 1) {
1145 return (AUDIO_ERR_ENCODING);
1146 }
1147 encoding = AUDIO_WAV_FMT_ENCODING_PCM;
1148 break;
1149 case AUDIO_ENCODING_ULAW:
1150 if (hdrp->bytes_per_unit != 1) {
1151 return (AUDIO_ERR_ENCODING);
1152 }
1153 encoding = AUDIO_WAV_FMT_ENCODING_MULAW;
1154 break;
1155 case AUDIO_ENCODING_ALAW:
1156 if (hdrp->bytes_per_unit != 1) {
1157 return (AUDIO_ERR_ENCODING);
1158 }
1159 encoding = AUDIO_WAV_FMT_ENCODING_ALAW;
1160 break;
1161 case AUDIO_ENCODING_LINEAR:
1162 if (hdrp->bytes_per_unit != 2) {
1163 return (AUDIO_ERR_ENCODING);
1164 }
1165 encoding = AUDIO_WAV_FMT_ENCODING_PCM;
1166 break;
1167 default:
1168 return (AUDIO_ERR_ENCODING);
1169 }
1170
1171 /* fill in the riff chunk */
1172 id = AUDIO_WAV_RIFF_ID;
1173 length = AUDIO_WAV_UNKNOWN_SIZE;
1174 AUDIO_WAV_HOST2FILE_INT(&id, &fhdr.wav_riff_ID);
1175 AUDIO_WAV_HOST2FILE_INT(&length, &fhdr.wav_riff_size);
1176
1177 /* fill in the type chunk */
1178 type = AUDIO_WAV_TYPE_ID;
1179 AUDIO_WAV_HOST2FILE_INT(&type, &fhdr.wav_type_ID);
1180
1181
1182 /* fill in the format chunk */
1183 id = AUDIO_WAV_FORMAT_ID;
1184 length = AUDIO_WAV_FORMAT_SIZE;
1185 bytes_per_second = hdrp->sample_rate * hdrp->channels *
1186 hdrp->bytes_per_unit;
1187 bytes_per_sample = hdrp->channels * hdrp->bytes_per_unit;
1188 bits_per_sample = hdrp->bytes_per_unit * 8;
1189
1190 AUDIO_WAV_HOST2FILE_INT(&id, &fhdr.wav_fmt_ID);
1191 AUDIO_WAV_HOST2FILE_INT(&length, &fhdr.wav_fmt_size);
1192 AUDIO_WAV_HOST2FILE_SHORT(&encoding, &fhdr.wav_fmt_encoding);
1193 AUDIO_WAV_HOST2FILE_SHORT(&hdrp->channels, &fhdr.wav_fmt_channels);
1194 AUDIO_WAV_HOST2FILE_INT(&hdrp->sample_rate, &fhdr.wav_fmt_sample_rate);
1195 AUDIO_WAV_HOST2FILE_INT(&bytes_per_second,
1196 &fhdr.wav_fmt_bytes_per_second);
1197 AUDIO_WAV_HOST2FILE_SHORT(&bytes_per_sample,
1198 &fhdr.wav_fmt_bytes_per_sample);
1199 AUDIO_WAV_HOST2FILE_SHORT(&bits_per_sample,
1200 &fhdr.wav_fmt_bits_per_sample);
1201
1202 /* fill in the data chunk */
1203 id = AUDIO_WAV_DATA_ID_LC;
1204 length = AUDIO_WAV_UNKNOWN_SIZE;
1205 AUDIO_WAV_HOST2FILE_INT(&id, &fhdr.wav_data_ID);
1206 AUDIO_WAV_HOST2FILE_INT(&length, &fhdr.wav_data_size);
1207
1208 *blen = sizeof (fhdr);
1209
1210 /* copy to the buffer */
1211 (void) memcpy(buf, &fhdr, sizeof (fhdr));
1212
1213 return (AUDIO_SUCCESS);
1214
1215 } /* audio_encode_wav() */
1216
1217 /*
1218 * Utility routine used to convert 10 byte IEEE extended float into
1219 * a regular double. Raw data arrives in an unsigned char array. Because
1220 * this is for sample rate, which is always positive, we don't worry
1221 * about the sign.
1222 */
1223 static double
convert_from_ieee_extended(unsigned char * data)1224 convert_from_ieee_extended(unsigned char *data)
1225 {
1226 double value = 0.0;
1227 unsigned long high_mantissa;
1228 unsigned long low_mantissa;
1229 int exponent;
1230
1231 /* first 2 bytes are the exponent */
1232 exponent = ((data[0] & 0x7f) << 8) | data[1];
1233
1234 high_mantissa = ((unsigned long)data[2] << 24) |
1235 ((unsigned long)data[3] << 16) |
1236 ((unsigned long)data[4] << 8) |
1237 (unsigned long)data[5];
1238 low_mantissa = ((unsigned long)data[6] << 24) |
1239 ((unsigned long)data[7] << 16) |
1240 ((unsigned long)data[8] << 8) |
1241 (unsigned long)data[9];
1242
1243 /* convert exponent and mantissas into a real double */
1244 if (exponent == 0 && high_mantissa == 0 && low_mantissa == 0) {
1245 /* everything is 0, so we're done */
1246 value = 0.0;
1247 } else {
1248 if (exponent == 0x7fff) { /* infinity */
1249 value = MAXFLOAT;
1250 } else {
1251 /* convert exponent from being unsigned to signed */
1252 exponent -= 0x3fff;
1253
1254 exponent -= 31;
1255 value = ldexp((double)high_mantissa, exponent);
1256
1257 exponent -= 32;
1258 value += ldexp((double)low_mantissa, exponent);
1259 }
1260 }
1261
1262 return (value);
1263
1264 }
1265
1266 /*
1267 * Utility routine to convert a double into 10 byte IEEE extended floating
1268 * point. The new number is placed into the unsigned char array. This is a
1269 * very brain dead convesion routine. It only supports integers, but then
1270 * that should be all we need for sample rate.
1271 */
1272 static void
convert_to_ieee_extended(double value,unsigned char * data)1273 convert_to_ieee_extended(double value, unsigned char *data)
1274 {
1275 double fmantissa;
1276 int exponent;
1277 int mantissa;
1278
1279 exponent = 16398;
1280 fmantissa = value;
1281
1282 while (fmantissa < 44000) {
1283 fmantissa *= 2;
1284 exponent--;
1285 }
1286
1287 mantissa = (int)fmantissa << 16;
1288
1289 data[0] = exponent >> 8;
1290 data[1] = exponent;
1291 data[2] = mantissa >> 24;
1292 data[3] = mantissa >> 16;
1293 data[4] = mantissa >> 8;
1294 data[5] = mantissa;
1295 data[6] = 0;
1296 data[7] = 0;
1297 data[8] = 0;
1298 data[9] = 0;
1299
1300 }
1301