audio.c revision 1.7 1 1.7 mrg /* $NetBSD: audio.c,v 1.7 1999/03/30 14:46:23 mrg Exp $ */
2 1.2 mrg
3 1.2 mrg /*
4 1.2 mrg * Copyright (c) 1999 Matthew R. Green
5 1.2 mrg * All rights reserved.
6 1.2 mrg *
7 1.2 mrg * Redistribution and use in source and binary forms, with or without
8 1.2 mrg * modification, are permitted provided that the following conditions
9 1.2 mrg * are met:
10 1.2 mrg * 1. Redistributions of source code must retain the above copyright
11 1.2 mrg * notice, this list of conditions and the following disclaimer.
12 1.2 mrg * 2. Redistributions in binary form must reproduce the above copyright
13 1.2 mrg * notice, this list of conditions and the following disclaimer in the
14 1.2 mrg * documentation and/or other materials provided with the distribution.
15 1.2 mrg * 3. The name of the author may not be used to endorse or promote products
16 1.2 mrg * derived from this software without specific prior written permission.
17 1.2 mrg *
18 1.2 mrg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 1.2 mrg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 1.2 mrg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 1.2 mrg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 1.2 mrg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 1.2 mrg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 1.2 mrg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 1.2 mrg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 1.2 mrg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 1.2 mrg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 1.2 mrg * SUCH DAMAGE.
29 1.2 mrg */
30 1.2 mrg
31 1.7 mrg /*
32 1.7 mrg * XXX this is slightly icky in places...
33 1.7 mrg */
34 1.7 mrg
35 1.1 mrg #include <sys/types.h>
36 1.1 mrg #include <sys/audioio.h>
37 1.1 mrg #include <sys/ioctl.h>
38 1.1 mrg #include <sys/time.h>
39 1.1 mrg
40 1.1 mrg #include <ctype.h>
41 1.1 mrg #include <err.h>
42 1.1 mrg #include <stdio.h>
43 1.1 mrg #include <stdlib.h>
44 1.1 mrg #include <string.h>
45 1.1 mrg
46 1.1 mrg #include "libaudio.h"
47 1.1 mrg
48 1.1 mrg /* back and forth between encodings */
49 1.1 mrg struct {
50 1.1 mrg char *ename;
51 1.1 mrg int eno;
52 1.1 mrg } encs[] = {
53 1.1 mrg { AudioEmulaw, AUDIO_ENCODING_ULAW },
54 1.1 mrg { "ulaw", AUDIO_ENCODING_ULAW },
55 1.1 mrg { AudioEalaw, AUDIO_ENCODING_ALAW },
56 1.1 mrg { AudioEslinear, AUDIO_ENCODING_SLINEAR },
57 1.1 mrg { "linear", AUDIO_ENCODING_SLINEAR },
58 1.1 mrg { AudioEulinear, AUDIO_ENCODING_ULINEAR },
59 1.1 mrg { AudioEadpcm, AUDIO_ENCODING_ADPCM },
60 1.1 mrg { "ADPCM", AUDIO_ENCODING_ADPCM },
61 1.1 mrg { AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE },
62 1.1 mrg { "linear_le", AUDIO_ENCODING_SLINEAR_LE },
63 1.1 mrg { AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE },
64 1.1 mrg { AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE },
65 1.1 mrg { "linear_be", AUDIO_ENCODING_SLINEAR_BE },
66 1.1 mrg { AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE },
67 1.1 mrg { AudioEmpeg_l1_stream, AUDIO_ENCODING_MPEG_L1_STREAM },
68 1.1 mrg { AudioEmpeg_l1_packets,AUDIO_ENCODING_MPEG_L1_PACKETS },
69 1.1 mrg { AudioEmpeg_l1_system, AUDIO_ENCODING_MPEG_L1_SYSTEM },
70 1.1 mrg { AudioEmpeg_l2_stream, AUDIO_ENCODING_MPEG_L2_STREAM },
71 1.1 mrg { AudioEmpeg_l2_packets,AUDIO_ENCODING_MPEG_L2_PACKETS },
72 1.1 mrg { AudioEmpeg_l2_system, AUDIO_ENCODING_MPEG_L2_SYSTEM },
73 1.1 mrg { 0, -1 }
74 1.1 mrg };
75 1.1 mrg
76 1.1 mrg
77 1.1 mrg char *
78 1.1 mrg audio_enc_from_val(val)
79 1.1 mrg int val;
80 1.1 mrg {
81 1.1 mrg int i;
82 1.1 mrg
83 1.1 mrg for (i = 0; encs[i].ename; i++)
84 1.1 mrg if (encs[i].eno == val)
85 1.1 mrg break;
86 1.1 mrg return (encs[i].ename);
87 1.1 mrg }
88 1.1 mrg
89 1.1 mrg int
90 1.1 mrg audio_enc_to_val(enc)
91 1.1 mrg const char *enc;
92 1.1 mrg {
93 1.1 mrg int i;
94 1.1 mrg
95 1.1 mrg for (i = 0; encs[i].ename; i++)
96 1.1 mrg if (strcmp(encs[i].ename, enc) == 0)
97 1.1 mrg break;
98 1.1 mrg if (encs[i].ename)
99 1.1 mrg return (encs[i].eno);
100 1.1 mrg else
101 1.1 mrg return (-1);
102 1.1 mrg }
103 1.1 mrg
104 1.1 mrg /*
105 1.1 mrg * SunOS/NeXT .au format helpers
106 1.1 mrg */
107 1.1 mrg struct {
108 1.1 mrg int file_encoding;
109 1.1 mrg int encoding;
110 1.1 mrg int precision;
111 1.1 mrg } file2sw_encodings[] = {
112 1.1 mrg { AUDIO_FILE_ENCODING_MULAW_8, AUDIO_ENCODING_ULAW, 8 },
113 1.1 mrg { AUDIO_FILE_ENCODING_LINEAR_8, AUDIO_ENCODING_ULINEAR_BE, 8 },
114 1.1 mrg { AUDIO_FILE_ENCODING_LINEAR_16, AUDIO_ENCODING_ULINEAR_BE, 16 },
115 1.1 mrg { AUDIO_FILE_ENCODING_LINEAR_24, AUDIO_ENCODING_ULINEAR_BE, 24 },
116 1.1 mrg { AUDIO_FILE_ENCODING_LINEAR_32, AUDIO_ENCODING_ULINEAR_BE, 32 },
117 1.1 mrg #if 0
118 1.1 mrg { AUDIO_FILE_ENCODING_FLOAT, AUDIO_ENCODING_ULAW, 32 },
119 1.1 mrg { AUDIO_FILE_ENCODING_DOUBLE, AUDIO_ENCODING_ULAW, 64 },
120 1.1 mrg { AUDIO_FILE_ENCODING_ADPCM_G721, AUDIO_ENCODING_ULAW, 4 },
121 1.1 mrg { AUDIO_FILE_ENCODING_ADPCM_G722, AUDIO_ENCODING_ULAW, 0 },
122 1.1 mrg { AUDIO_FILE_ENCODING_ADPCM_G723_3, AUDIO_ENCODING_ULAW, 3 },
123 1.1 mrg { AUDIO_FILE_ENCODING_ADPCM_G723_5, AUDIO_ENCODING_ULAW, 5 },
124 1.1 mrg #endif
125 1.1 mrg { AUDIO_FILE_ENCODING_ALAW_8, AUDIO_ENCODING_ALAW, 8 },
126 1.1 mrg { -1, -1 }
127 1.1 mrg };
128 1.1 mrg
129 1.1 mrg int
130 1.1 mrg audio_get_sun_encoding(sun_encoding, encp, precp)
131 1.1 mrg int sun_encoding;
132 1.1 mrg int *encp;
133 1.1 mrg int *precp;
134 1.1 mrg {
135 1.1 mrg int i;
136 1.1 mrg
137 1.1 mrg for (i = 0; file2sw_encodings[i].file_encoding != -1; i++)
138 1.1 mrg if (file2sw_encodings[i].file_encoding == sun_encoding) {
139 1.1 mrg *precp = file2sw_encodings[i].precision;
140 1.1 mrg *encp = file2sw_encodings[i].encoding;
141 1.1 mrg return (0);
142 1.1 mrg }
143 1.1 mrg return (1);
144 1.1 mrg }
145 1.1 mrg
146 1.1 mrg /*
147 1.1 mrg * sample header is:
148 1.1 mrg *
149 1.1 mrg * RIFF\^@^C^@WAVEfmt ^P^@^@^@^A^@^B^@D<AC>^@^@^P<B1>^B^@^D^@^P^@data^@^@^C^@^@^@^@^@^@^@^@^@^@
150 1.1 mrg *
151 1.1 mrg */
152 1.1 mrg /*
153 1.1 mrg * WAV format helpers
154 1.1 mrg */
155 1.1 mrg /*
156 1.1 mrg * find a .wav header, etc. returns header length on success
157 1.1 mrg */
158 1.1 mrg size_t
159 1.1 mrg audio_parse_wav_hdr(hdr, sz, enc, prec, sample, channels)
160 1.1 mrg void *hdr;
161 1.1 mrg size_t sz;
162 1.1 mrg int *enc;
163 1.1 mrg int *prec;
164 1.1 mrg int *sample;
165 1.1 mrg int *channels;
166 1.1 mrg {
167 1.1 mrg char *where = hdr;
168 1.1 mrg wav_audioheaderpart *part;
169 1.1 mrg wav_audioheaderfmt *fmt;
170 1.1 mrg char *end = (((char *)hdr) + sz);
171 1.1 mrg int newenc, newprec;
172 1.1 mrg
173 1.1 mrg if (sz < 32)
174 1.1 mrg return (AUDIO_ENOENT);
175 1.1 mrg
176 1.1 mrg if (strncmp(where, "RIFF", 4))
177 1.1 mrg return (AUDIO_ENOENT);
178 1.1 mrg where += 8;
179 1.1 mrg if (strncmp(where, "WAVE", 4))
180 1.1 mrg return (AUDIO_ENOENT);
181 1.1 mrg where += 4;
182 1.1 mrg
183 1.1 mrg do {
184 1.1 mrg part = (wav_audioheaderpart *)where;
185 1.1 mrg where += getle32(part->len) + 8;
186 1.1 mrg } while (where < end && strncmp(part->name, "fmt ", 4));
187 1.1 mrg
188 1.1 mrg /* too short ? */
189 1.1 mrg if (where + 16 > end)
190 1.1 mrg return (AUDIO_ESHORTHDR);
191 1.1 mrg
192 1.1 mrg fmt = (wav_audioheaderfmt *)(part + 1);
193 1.1 mrg
194 1.1 mrg #if 0
195 1.1 mrg printf("fmt header is:\n\t%d\ttag\n\t%d\tchannels\n\t%d\tsample rate\n\t%d\tavg_bps\n\t%d\talignment\n\t%d\tbits per sample\n", getle16(fmt->tag), getle16(fmt->channels), getle32(fmt->sample_rate), getle32(fmt->avg_bps), getle16(fmt->alignment), getle16(fmt->bits_per_sample));
196 1.1 mrg #endif
197 1.1 mrg
198 1.1 mrg switch (getle16(fmt->tag)) {
199 1.1 mrg case WAVE_FORMAT_UNKNOWN:
200 1.1 mrg case WAVE_FORMAT_ADPCM:
201 1.1 mrg case WAVE_FORMAT_OKI_ADPCM:
202 1.1 mrg case WAVE_FORMAT_DIGISTD:
203 1.1 mrg case WAVE_FORMAT_DIGIFIX:
204 1.1 mrg case IBM_FORMAT_MULAW:
205 1.1 mrg case IBM_FORMAT_ALAW:
206 1.1 mrg case IBM_FORMAT_ADPCM:
207 1.1 mrg default:
208 1.1 mrg return (AUDIO_EWAVUNSUPP);
209 1.1 mrg
210 1.1 mrg case WAVE_FORMAT_PCM:
211 1.1 mrg switch (getle16(fmt->bits_per_sample)) {
212 1.1 mrg case 8:
213 1.1 mrg newprec = 8;
214 1.1 mrg break;
215 1.1 mrg case 16:
216 1.1 mrg newprec = 16;
217 1.1 mrg break;
218 1.1 mrg case 24:
219 1.1 mrg newprec = 24;
220 1.1 mrg break;
221 1.1 mrg case 32:
222 1.1 mrg newprec = 32;
223 1.1 mrg break;
224 1.1 mrg default:
225 1.1 mrg return (AUDIO_EWAVBADPCM);
226 1.1 mrg }
227 1.6 mycroft if (newprec == 8)
228 1.6 mycroft newenc = AUDIO_ENCODING_ULINEAR_LE;
229 1.6 mycroft else
230 1.6 mycroft newenc = AUDIO_ENCODING_SLINEAR_LE;
231 1.1 mrg break;
232 1.1 mrg case WAVE_FORMAT_ALAW:
233 1.1 mrg newenc = AUDIO_ENCODING_ALAW;
234 1.1 mrg newprec = 8;
235 1.1 mrg break;
236 1.1 mrg case WAVE_FORMAT_MULAW:
237 1.1 mrg newenc = AUDIO_ENCODING_ULAW;
238 1.1 mrg newprec = 8;
239 1.1 mrg break;
240 1.1 mrg }
241 1.1 mrg
242 1.1 mrg do {
243 1.1 mrg part = (wav_audioheaderpart *)where;
244 1.3 mrg #if 0
245 1.3 mrg printf("part `%c%c%c%c' len = %d\n", part->name[0], part->name[1], part->name[2], part->name[3], getle32(part->len));
246 1.3 mrg #endif
247 1.1 mrg where += (getle32(part->len) + 8);
248 1.1 mrg } while ((char *)where < end && strncmp(part->name, "data", 4));
249 1.1 mrg
250 1.3 mrg if ((where - getle32(part->len)) <= end) {
251 1.1 mrg *channels = getle16(fmt->channels);
252 1.1 mrg *sample = getle32(fmt->sample_rate);
253 1.1 mrg *enc = newenc;
254 1.1 mrg *prec = newprec;
255 1.1 mrg part++;
256 1.1 mrg return ((char *)part - (char *)hdr);
257 1.1 mrg }
258 1.1 mrg return (AUDIO_EWAVNODATA);
259 1.1 mrg }
260 1.1 mrg
261 1.1 mrg /*
262 1.1 mrg * these belong elsewhere??
263 1.1 mrg */
264 1.1 mrg void
265 1.1 mrg decode_int(arg, intp)
266 1.1 mrg const char *arg;
267 1.1 mrg int *intp;
268 1.1 mrg {
269 1.1 mrg char *ep;
270 1.1 mrg int ret;
271 1.1 mrg
272 1.1 mrg ret = strtoul(arg, &ep, 0);
273 1.1 mrg
274 1.1 mrg if (ep[0] == '\0') {
275 1.1 mrg *intp = ret;
276 1.1 mrg return;
277 1.1 mrg }
278 1.1 mrg errx(1, "argument `%s' not a valid integer", arg);
279 1.1 mrg }
280 1.1 mrg
281 1.1 mrg void
282 1.1 mrg decode_time(arg, tvp)
283 1.1 mrg const char *arg;
284 1.1 mrg struct timeval *tvp;
285 1.1 mrg {
286 1.1 mrg char *s, *colon, *dot;
287 1.1 mrg char *copy = strdup(arg);
288 1.1 mrg int first;
289 1.1 mrg
290 1.1 mrg if (copy == NULL)
291 1.1 mrg err(1, "could not allocate a copy of %s", arg);
292 1.1 mrg
293 1.1 mrg tvp->tv_sec = tvp->tv_usec = 0;
294 1.1 mrg s = copy;
295 1.1 mrg
296 1.1 mrg /* handle [hh:]mm:ss.dd */
297 1.1 mrg if ((colon = strchr(s, ':'))) {
298 1.1 mrg *colon++ = '\0';
299 1.1 mrg decode_int(s, &first);
300 1.1 mrg tvp->tv_sec = first * 60; /* minutes */
301 1.1 mrg s = colon;
302 1.1 mrg
303 1.1 mrg if ((colon = strchr(s, ':'))) {
304 1.1 mrg *colon++ = '\0';
305 1.1 mrg decode_int(s, &first);
306 1.1 mrg tvp->tv_sec += first;
307 1.1 mrg tvp->tv_sec *= 60; /* minutes and hours */
308 1.1 mrg s = colon;
309 1.1 mrg }
310 1.1 mrg }
311 1.1 mrg if ((dot = strchr(s, '.'))) {
312 1.1 mrg int i, base = 100000;
313 1.1 mrg
314 1.1 mrg *dot++ = '\0';
315 1.1 mrg
316 1.1 mrg for (i = 0; i < 6; i++, base /= 10) {
317 1.1 mrg if (!dot[i])
318 1.1 mrg break;
319 1.1 mrg if (!isdigit(dot[i]))
320 1.1 mrg errx(1, "argument `%s' is not a value time specification", arg);
321 1.1 mrg tvp->tv_usec += base * (dot[i] - '0');
322 1.1 mrg }
323 1.1 mrg }
324 1.1 mrg decode_int(s, &first);
325 1.1 mrg tvp->tv_sec += first;
326 1.1 mrg #if 0
327 1.1 mrg printf("tvp->tv_sec = %ld, tvp->tv_usec = %ld\n", tvp->tv_sec, tvp->tv_usec);
328 1.1 mrg #endif
329 1.1 mrg
330 1.1 mrg free(copy);
331 1.1 mrg }
332 1.1 mrg
333 1.1 mrg /*
334 1.1 mrg * decode a string into an encoding value.
335 1.1 mrg */
336 1.1 mrg void
337 1.1 mrg decode_encoding(arg, encp)
338 1.1 mrg const char *arg;
339 1.1 mrg int *encp;
340 1.1 mrg {
341 1.1 mrg size_t len;
342 1.1 mrg int i;
343 1.1 mrg
344 1.1 mrg len = strlen(arg);
345 1.1 mrg for (i = 0; encs[i].ename; i++)
346 1.1 mrg if (strncmp(encs[i].ename, arg, len) == 0) {
347 1.1 mrg *encp = encs[i].eno;
348 1.1 mrg return;
349 1.1 mrg }
350 1.1 mrg errx(1, "unknown encoding `%s'", arg);
351 1.1 mrg }
352 1.1 mrg
353 1.1 mrg const char *const audio_errlist[] = {
354 1.1 mrg "no audio entry",
355 1.1 mrg "short header",
356 1.1 mrg "unsupported WAV format",
357 1.1 mrg "bad (unsupported) WAV PCM format",
358 1.1 mrg "no WAV audio data",
359 1.1 mrg };
360 1.1 mrg
361 1.1 mrg const char *
362 1.1 mrg audio_errstring(errval)
363 1.1 mrg int errval;
364 1.1 mrg {
365 1.1 mrg
366 1.1 mrg errval = -errval;
367 1.1 mrg if (errval < 1 || errval > AUDIO_MAXERRNO)
368 1.1 mrg return "Invalid error";
369 1.1 mrg return audio_errlist[errval];
370 1.1 mrg }
371