| @@ -1,17 +1,17 @@ | | | @@ -1,17 +1,17 @@ |
1 | /* $NetBSD: wav.c,v 1.8 2008/05/29 14:51:27 mrg Exp $ */ | | 1 | /* $NetBSD: wav.c,v 1.8.4.1 2009/06/23 06:53:36 snj Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2002 Matthew R. Green | | 4 | * Copyright (c) 2002, 2009 Matthew R. Green |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * | | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| @@ -23,40 +23,41 @@ | | | @@ -23,40 +23,41 @@ |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. | | 26 | * SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | /* | | 29 | /* |
30 | * WAV support for the audio tools; thanks go to the sox utility for | | 30 | * WAV support for the audio tools; thanks go to the sox utility for |
31 | * clearing up issues with WAV files. | | 31 | * clearing up issues with WAV files. |
32 | */ | | 32 | */ |
33 | #include <sys/cdefs.h> | | 33 | #include <sys/cdefs.h> |
34 | | | 34 | |
35 | #ifndef lint | | 35 | #ifndef lint |
36 | __RCSID("$NetBSD: wav.c,v 1.8 2008/05/29 14:51:27 mrg Exp $"); | | 36 | __RCSID("$NetBSD: wav.c,v 1.8.4.1 2009/06/23 06:53:36 snj Exp $"); |
37 | #endif | | 37 | #endif |
38 | | | 38 | |
39 | | | 39 | |
40 | #include <sys/types.h> | | 40 | #include <sys/types.h> |
41 | #include <sys/audioio.h> | | 41 | #include <sys/audioio.h> |
42 | #include <sys/ioctl.h> | | 42 | #include <sys/ioctl.h> |
43 | #include <sys/time.h> | | 43 | #include <sys/time.h> |
44 | | | 44 | |
45 | #include <ctype.h> | | 45 | #include <ctype.h> |
46 | #include <err.h> | | 46 | #include <err.h> |
47 | #include <stdio.h> | | 47 | #include <stdio.h> |
48 | #include <stdlib.h> | | 48 | #include <stdlib.h> |
49 | #include <string.h> | | 49 | #include <string.h> |
| | | 50 | #include <stdint.h> |
50 | | | 51 | |
51 | #include "libaudio.h" | | 52 | #include "libaudio.h" |
52 | | | 53 | |
53 | struct { | | 54 | struct { |
54 | int wenc; | | 55 | int wenc; |
55 | const char *wname; | | 56 | const char *wname; |
56 | } wavencs[] = { | | 57 | } wavencs[] = { |
57 | { WAVE_FORMAT_UNKNOWN, "Microsoft Official Unknown" }, | | 58 | { WAVE_FORMAT_UNKNOWN, "Microsoft Official Unknown" }, |
58 | { WAVE_FORMAT_PCM, "Microsoft PCM" }, | | 59 | { WAVE_FORMAT_PCM, "Microsoft PCM" }, |
59 | { WAVE_FORMAT_ADPCM, "Microsoft ADPCM" }, | | 60 | { WAVE_FORMAT_ADPCM, "Microsoft ADPCM" }, |
60 | { WAVE_FORMAT_ALAW, "Microsoft A-law" }, | | 61 | { WAVE_FORMAT_ALAW, "Microsoft A-law" }, |
61 | { WAVE_FORMAT_MULAW, "Microsoft mu-law" }, | | 62 | { WAVE_FORMAT_MULAW, "Microsoft mu-law" }, |
62 | { WAVE_FORMAT_OKI_ADPCM,"OKI ADPCM" }, | | 63 | { WAVE_FORMAT_OKI_ADPCM,"OKI ADPCM" }, |
| @@ -66,53 +67,57 @@ struct { | | | @@ -66,53 +67,57 @@ struct { |
66 | }; | | 67 | }; |
67 | | | 68 | |
68 | const char * | | 69 | const char * |
69 | wav_enc_from_val(int encoding) | | 70 | wav_enc_from_val(int encoding) |
70 | { | | 71 | { |
71 | int i; | | 72 | int i; |
72 | | | 73 | |
73 | for (i = 0; wavencs[i].wenc != -1; i++) | | 74 | for (i = 0; wavencs[i].wenc != -1; i++) |
74 | if (wavencs[i].wenc == encoding) | | 75 | if (wavencs[i].wenc == encoding) |
75 | break; | | 76 | break; |
76 | return (wavencs[i].wname); | | 77 | return (wavencs[i].wname); |
77 | } | | 78 | } |
78 | | | 79 | |
| | | 80 | extern int verbose; |
| | | 81 | |
79 | /* | | 82 | /* |
80 | * sample header is: | | 83 | * sample header is: |
81 | * | | 84 | * |
82 | * RIFF\^@^C^@WAVEfmt ^P^@^@^@^A^@^B^@D<AC>^@^@^P<B1>^B^@^D^@^P^@data^@^@^C^@^@^@^@^@^@^@^@^@^@ | | 85 | * RIFF\^@^C^@WAVEfmt ^P^@^@^@^A^@^B^@D<AC>^@^@^P<B1>^B^@^D^@^P^@data^@^@^C^@^@^@^@^@^@^@^@^@^@ |
83 | * | | 86 | * |
84 | */ | | 87 | */ |
85 | /* | | 88 | /* |
86 | * WAV format helpers | | 89 | * WAV format helpers |
87 | */ | | 90 | */ |
88 | /* | | 91 | /* |
89 | * find a .wav header, etc. returns header length on success | | 92 | * find a .wav header, etc. returns header length on success |
90 | */ | | 93 | */ |
91 | ssize_t | | 94 | ssize_t |
92 | audio_wav_parse_hdr(hdr, sz, enc, prec, sample, channels, datasize) | | 95 | audio_wav_parse_hdr(hdr, sz, enc, prec, sample, channels, datasize) |
93 | void *hdr; | | 96 | void *hdr; |
94 | size_t sz; | | 97 | size_t sz; |
95 | u_int *enc; | | 98 | u_int *enc; |
96 | u_int *prec; | | 99 | u_int *prec; |
97 | u_int *sample; | | 100 | u_int *sample; |
98 | u_int *channels; | | 101 | u_int *channels; |
99 | size_t *datasize; | | 102 | size_t *datasize; |
100 | { | | 103 | { |
101 | char *where = hdr, *owhere; | | 104 | char *where = hdr, *owhere; |
102 | wav_audioheaderpart part; | | 105 | wav_audioheaderpart part; |
103 | wav_audioheaderfmt fmt; | | 106 | wav_audioheaderfmt fmt; |
| | | 107 | wav_audiohdrextensible ext; |
104 | char *end = (((char *)hdr) + sz); | | 108 | char *end = (((char *)hdr) + sz); |
105 | u_int newenc, newprec; | | 109 | u_int newenc, newprec; |
| | | 110 | u_int16_t fmttag; |
106 | static const char | | 111 | static const char |
107 | strfmt[4] = "fmt ", | | 112 | strfmt[4] = "fmt ", |
108 | strRIFF[4] = "RIFF", | | 113 | strRIFF[4] = "RIFF", |
109 | strWAVE[4] = "WAVE", | | 114 | strWAVE[4] = "WAVE", |
110 | strdata[4] = "data"; | | 115 | strdata[4] = "data"; |
111 | | | 116 | |
112 | if (sz < 32) | | 117 | if (sz < 32) |
113 | return (AUDIO_ENOENT); | | 118 | return (AUDIO_ENOENT); |
114 | | | 119 | |
115 | if (strncmp(where, strRIFF, sizeof strRIFF)) | | 120 | if (strncmp(where, strRIFF, sizeof strRIFF)) |
116 | return (AUDIO_ENOENT); | | 121 | return (AUDIO_ENOENT); |
117 | where += 8; | | 122 | where += 8; |
118 | if (strncmp(where, strWAVE, sizeof strWAVE)) | | 123 | if (strncmp(where, strWAVE, sizeof strWAVE)) |
| @@ -121,39 +126,55 @@ audio_wav_parse_hdr(hdr, sz, enc, prec, | | | @@ -121,39 +126,55 @@ audio_wav_parse_hdr(hdr, sz, enc, prec, |
121 | | | 126 | |
122 | do { | | 127 | do { |
123 | memcpy(&part, where, sizeof part); | | 128 | memcpy(&part, where, sizeof part); |
124 | owhere = where; | | 129 | owhere = where; |
125 | where += getle32(part.len) + 8; | | 130 | where += getle32(part.len) + 8; |
126 | } while (where < end && strncmp(part.name, strfmt, sizeof strfmt)); | | 131 | } while (where < end && strncmp(part.name, strfmt, sizeof strfmt)); |
127 | | | 132 | |
128 | /* too short ? */ | | 133 | /* too short ? */ |
129 | if (where + sizeof fmt > end) | | 134 | if (where + sizeof fmt > end) |
130 | return (AUDIO_ESHORTHDR); | | 135 | return (AUDIO_ESHORTHDR); |
131 | | | 136 | |
132 | memcpy(&fmt, (owhere + 8), sizeof fmt); | | 137 | memcpy(&fmt, (owhere + 8), sizeof fmt); |
133 | | | 138 | |
134 | switch (getle16(fmt.tag)) { | | 139 | fmttag = getle16(fmt.tag); |
| | | 140 | if (verbose) |
| | | 141 | printf("WAVE format tag: %x\n", fmttag); |
| | | 142 | |
| | | 143 | if (fmttag == WAVE_FORMAT_EXTENSIBLE) { |
| | | 144 | if ((uintptr_t)(where - owhere) < sizeof(fmt) + sizeof(ext)) |
| | | 145 | return (AUDIO_ESHORTHDR); |
| | | 146 | memcpy(&ext, owhere + sizeof fmt, sizeof ext); |
| | | 147 | if (getle16(ext.len) < sizeof(ext) - sizeof(ext.len)) |
| | | 148 | return (AUDIO_ESHORTHDR); |
| | | 149 | fmttag = ext.sub_tag; |
| | | 150 | if (verbose) |
| | | 151 | printf("WAVE extensible sub tag: %x\n", fmttag); |
| | | 152 | } |
| | | 153 | |
| | | 154 | switch (fmttag) { |
135 | case WAVE_FORMAT_UNKNOWN: | | 155 | case WAVE_FORMAT_UNKNOWN: |
136 | case WAVE_FORMAT_ADPCM: | | | |
137 | case WAVE_FORMAT_OKI_ADPCM: | | | |
138 | case WAVE_FORMAT_DIGISTD: | | | |
139 | case WAVE_FORMAT_DIGIFIX: | | | |
140 | case IBM_FORMAT_MULAW: | | 156 | case IBM_FORMAT_MULAW: |
141 | case IBM_FORMAT_ALAW: | | 157 | case IBM_FORMAT_ALAW: |
142 | case IBM_FORMAT_ADPCM: | | 158 | case IBM_FORMAT_ADPCM: |
143 | default: | | 159 | default: |
144 | return (AUDIO_EWAVUNSUPP); | | 160 | return (AUDIO_EWAVUNSUPP); |
145 | | | 161 | |
146 | case WAVE_FORMAT_PCM: | | 162 | case WAVE_FORMAT_PCM: |
| | | 163 | case WAVE_FORMAT_ADPCM: |
| | | 164 | case WAVE_FORMAT_OKI_ADPCM: |
| | | 165 | case WAVE_FORMAT_IMA_ADPCM: |
| | | 166 | case WAVE_FORMAT_DIGIFIX: |
| | | 167 | case WAVE_FORMAT_DIGISTD: |
147 | switch (getle16(fmt.bits_per_sample)) { | | 168 | switch (getle16(fmt.bits_per_sample)) { |
148 | case 8: | | 169 | case 8: |
149 | newprec = 8; | | 170 | newprec = 8; |
150 | break; | | 171 | break; |
151 | case 16: | | 172 | case 16: |
152 | newprec = 16; | | 173 | newprec = 16; |
153 | break; | | 174 | break; |
154 | case 24: | | 175 | case 24: |
155 | newprec = 24; | | 176 | newprec = 24; |
156 | break; | | 177 | break; |
157 | case 32: | | 178 | case 32: |
158 | newprec = 32; | | 179 | newprec = 32; |
159 | break; | | 180 | break; |