audio.c revision 1.3 1 1.3 mrg /* $NetBSD: audio.c,v 1.3 1999/03/27 05:14:37 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.1 mrg #include <sys/types.h>
32 1.1 mrg #include <sys/audioio.h>
33 1.1 mrg #include <sys/ioctl.h>
34 1.1 mrg #include <sys/time.h>
35 1.1 mrg
36 1.1 mrg #include <ctype.h>
37 1.1 mrg #include <err.h>
38 1.1 mrg #include <stdio.h>
39 1.1 mrg #include <stdlib.h>
40 1.1 mrg #include <string.h>
41 1.1 mrg
42 1.1 mrg #include "libaudio.h"
43 1.1 mrg
44 1.1 mrg /* back and forth between encodings */
45 1.1 mrg struct {
46 1.1 mrg char *ename;
47 1.1 mrg int eno;
48 1.1 mrg } encs[] = {
49 1.1 mrg { AudioEmulaw, AUDIO_ENCODING_ULAW },
50 1.1 mrg { "ulaw", AUDIO_ENCODING_ULAW },
51 1.1 mrg { AudioEalaw, AUDIO_ENCODING_ALAW },
52 1.1 mrg { AudioEslinear, AUDIO_ENCODING_SLINEAR },
53 1.1 mrg { "linear", AUDIO_ENCODING_SLINEAR },
54 1.1 mrg { AudioEulinear, AUDIO_ENCODING_ULINEAR },
55 1.1 mrg { AudioEadpcm, AUDIO_ENCODING_ADPCM },
56 1.1 mrg { "ADPCM", AUDIO_ENCODING_ADPCM },
57 1.1 mrg { AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE },
58 1.1 mrg { "linear_le", AUDIO_ENCODING_SLINEAR_LE },
59 1.1 mrg { AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE },
60 1.1 mrg { AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE },
61 1.1 mrg { "linear_be", AUDIO_ENCODING_SLINEAR_BE },
62 1.1 mrg { AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE },
63 1.1 mrg { AudioEmpeg_l1_stream, AUDIO_ENCODING_MPEG_L1_STREAM },
64 1.1 mrg { AudioEmpeg_l1_packets,AUDIO_ENCODING_MPEG_L1_PACKETS },
65 1.1 mrg { AudioEmpeg_l1_system, AUDIO_ENCODING_MPEG_L1_SYSTEM },
66 1.1 mrg { AudioEmpeg_l2_stream, AUDIO_ENCODING_MPEG_L2_STREAM },
67 1.1 mrg { AudioEmpeg_l2_packets,AUDIO_ENCODING_MPEG_L2_PACKETS },
68 1.1 mrg { AudioEmpeg_l2_system, AUDIO_ENCODING_MPEG_L2_SYSTEM },
69 1.1 mrg { 0, -1 }
70 1.1 mrg };
71 1.1 mrg
72 1.1 mrg
73 1.1 mrg char *
74 1.1 mrg audio_enc_from_val(val)
75 1.1 mrg int val;
76 1.1 mrg {
77 1.1 mrg int i;
78 1.1 mrg
79 1.1 mrg for (i = 0; encs[i].ename; i++)
80 1.1 mrg if (encs[i].eno == val)
81 1.1 mrg break;
82 1.1 mrg return (encs[i].ename);
83 1.1 mrg }
84 1.1 mrg
85 1.1 mrg int
86 1.1 mrg audio_enc_to_val(enc)
87 1.1 mrg const char *enc;
88 1.1 mrg {
89 1.1 mrg int i;
90 1.1 mrg
91 1.1 mrg for (i = 0; encs[i].ename; i++)
92 1.1 mrg if (strcmp(encs[i].ename, enc) == 0)
93 1.1 mrg break;
94 1.1 mrg if (encs[i].ename)
95 1.1 mrg return (encs[i].eno);
96 1.1 mrg else
97 1.1 mrg return (-1);
98 1.1 mrg }
99 1.1 mrg
100 1.1 mrg int
101 1.1 mrg audio_parse_encoding(encoding_str, fd, encp, precp)
102 1.1 mrg char *encoding_str;
103 1.1 mrg int fd;
104 1.1 mrg int *encp;
105 1.1 mrg int *precp;
106 1.1 mrg {
107 1.1 mrg int i, prec = 0;
108 1.1 mrg char *colon, *star;
109 1.1 mrg
110 1.1 mrg colon = strchr(encoding_str, ':');
111 1.1 mrg if (colon) {
112 1.1 mrg *colon++ = '\0';
113 1.1 mrg if (*colon)
114 1.1 mrg prec = atoi(colon);
115 1.1 mrg }
116 1.1 mrg star = strrchr(encoding_str, '*');
117 1.1 mrg if (star)
118 1.1 mrg *star = '\0';
119 1.1 mrg for (i = 0; ; i++) {
120 1.1 mrg audio_encoding_t enc;
121 1.1 mrg
122 1.1 mrg enc.index = i;
123 1.1 mrg if (ioctl(fd, AUDIO_GETENC, &enc) < 0)
124 1.1 mrg break;
125 1.1 mrg
126 1.1 mrg if (strcasecmp(enc.name, encoding_str) == 0 &&
127 1.1 mrg (prec == 0 || prec == enc.precision)) {
128 1.1 mrg *encp = enc.encoding;
129 1.1 mrg *precp = enc.precision;
130 1.1 mrg return (0);
131 1.1 mrg }
132 1.1 mrg
133 1.1 mrg }
134 1.1 mrg return (1);
135 1.1 mrg }
136 1.1 mrg
137 1.1 mrg /*
138 1.1 mrg * SunOS/NeXT .au format helpers
139 1.1 mrg */
140 1.1 mrg struct {
141 1.1 mrg int file_encoding;
142 1.1 mrg int encoding;
143 1.1 mrg int precision;
144 1.1 mrg } file2sw_encodings[] = {
145 1.1 mrg { AUDIO_FILE_ENCODING_MULAW_8, AUDIO_ENCODING_ULAW, 8 },
146 1.1 mrg { AUDIO_FILE_ENCODING_LINEAR_8, AUDIO_ENCODING_ULINEAR_BE, 8 },
147 1.1 mrg { AUDIO_FILE_ENCODING_LINEAR_16, AUDIO_ENCODING_ULINEAR_BE, 16 },
148 1.1 mrg { AUDIO_FILE_ENCODING_LINEAR_24, AUDIO_ENCODING_ULINEAR_BE, 24 },
149 1.1 mrg { AUDIO_FILE_ENCODING_LINEAR_32, AUDIO_ENCODING_ULINEAR_BE, 32 },
150 1.1 mrg #if 0
151 1.1 mrg { AUDIO_FILE_ENCODING_FLOAT, AUDIO_ENCODING_ULAW, 32 },
152 1.1 mrg { AUDIO_FILE_ENCODING_DOUBLE, AUDIO_ENCODING_ULAW, 64 },
153 1.1 mrg { AUDIO_FILE_ENCODING_ADPCM_G721, AUDIO_ENCODING_ULAW, 4 },
154 1.1 mrg { AUDIO_FILE_ENCODING_ADPCM_G722, AUDIO_ENCODING_ULAW, 0 },
155 1.1 mrg { AUDIO_FILE_ENCODING_ADPCM_G723_3, AUDIO_ENCODING_ULAW, 3 },
156 1.1 mrg { AUDIO_FILE_ENCODING_ADPCM_G723_5, AUDIO_ENCODING_ULAW, 5 },
157 1.1 mrg #endif
158 1.1 mrg { AUDIO_FILE_ENCODING_ALAW_8, AUDIO_ENCODING_ALAW, 8 },
159 1.1 mrg { -1, -1 }
160 1.1 mrg };
161 1.1 mrg
162 1.1 mrg int
163 1.1 mrg audio_get_sun_encoding(sun_encoding, encp, precp)
164 1.1 mrg int sun_encoding;
165 1.1 mrg int *encp;
166 1.1 mrg int *precp;
167 1.1 mrg {
168 1.1 mrg int i;
169 1.1 mrg
170 1.1 mrg for (i = 0; file2sw_encodings[i].file_encoding != -1; i++)
171 1.1 mrg if (file2sw_encodings[i].file_encoding == sun_encoding) {
172 1.1 mrg *precp = file2sw_encodings[i].precision;
173 1.1 mrg *encp = file2sw_encodings[i].encoding;
174 1.1 mrg return (0);
175 1.1 mrg }
176 1.1 mrg return (1);
177 1.1 mrg }
178 1.1 mrg
179 1.1 mrg /*
180 1.1 mrg * sample header is:
181 1.1 mrg *
182 1.1 mrg * RIFF\^@^C^@WAVEfmt ^P^@^@^@^A^@^B^@D<AC>^@^@^P<B1>^B^@^D^@^P^@data^@^@^C^@^@^@^@^@^@^@^@^@^@
183 1.1 mrg *
184 1.1 mrg */
185 1.1 mrg /*
186 1.1 mrg * WAV format helpers
187 1.1 mrg */
188 1.1 mrg /*
189 1.1 mrg * find a .wav header, etc. returns header length on success
190 1.1 mrg */
191 1.1 mrg size_t
192 1.1 mrg audio_parse_wav_hdr(hdr, sz, enc, prec, sample, channels)
193 1.1 mrg void *hdr;
194 1.1 mrg size_t sz;
195 1.1 mrg int *enc;
196 1.1 mrg int *prec;
197 1.1 mrg int *sample;
198 1.1 mrg int *channels;
199 1.1 mrg {
200 1.1 mrg char *where = hdr;
201 1.1 mrg wav_audioheaderpart *part;
202 1.1 mrg wav_audioheaderfmt *fmt;
203 1.1 mrg char *end = (((char *)hdr) + sz);
204 1.1 mrg int newenc, newprec;
205 1.1 mrg
206 1.1 mrg if (sz < 32)
207 1.1 mrg return (AUDIO_ENOENT);
208 1.1 mrg
209 1.1 mrg if (strncmp(where, "RIFF", 4))
210 1.1 mrg return (AUDIO_ENOENT);
211 1.1 mrg where += 8;
212 1.1 mrg if (strncmp(where, "WAVE", 4))
213 1.1 mrg return (AUDIO_ENOENT);
214 1.1 mrg where += 4;
215 1.1 mrg
216 1.1 mrg do {
217 1.1 mrg part = (wav_audioheaderpart *)where;
218 1.1 mrg where += getle32(part->len) + 8;
219 1.1 mrg } while (where < end && strncmp(part->name, "fmt ", 4));
220 1.1 mrg
221 1.1 mrg /* too short ? */
222 1.1 mrg if (where + 16 > end)
223 1.1 mrg return (AUDIO_ESHORTHDR);
224 1.1 mrg
225 1.1 mrg fmt = (wav_audioheaderfmt *)(part + 1);
226 1.1 mrg
227 1.1 mrg #if 0
228 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));
229 1.1 mrg #endif
230 1.1 mrg
231 1.1 mrg switch (getle16(fmt->tag)) {
232 1.1 mrg case WAVE_FORMAT_UNKNOWN:
233 1.1 mrg case WAVE_FORMAT_ADPCM:
234 1.1 mrg case WAVE_FORMAT_OKI_ADPCM:
235 1.1 mrg case WAVE_FORMAT_DIGISTD:
236 1.1 mrg case WAVE_FORMAT_DIGIFIX:
237 1.1 mrg case IBM_FORMAT_MULAW:
238 1.1 mrg case IBM_FORMAT_ALAW:
239 1.1 mrg case IBM_FORMAT_ADPCM:
240 1.1 mrg default:
241 1.1 mrg return (AUDIO_EWAVUNSUPP);
242 1.1 mrg
243 1.1 mrg case WAVE_FORMAT_PCM:
244 1.1 mrg switch (getle16(fmt->bits_per_sample)) {
245 1.1 mrg case 8:
246 1.1 mrg newprec = 8;
247 1.1 mrg break;
248 1.1 mrg case 16:
249 1.1 mrg newprec = 16;
250 1.1 mrg break;
251 1.1 mrg case 24:
252 1.1 mrg newprec = 24;
253 1.1 mrg break;
254 1.1 mrg case 32:
255 1.1 mrg newprec = 32;
256 1.1 mrg break;
257 1.1 mrg default:
258 1.1 mrg return (AUDIO_EWAVBADPCM);
259 1.1 mrg }
260 1.1 mrg newenc = AUDIO_ENCODING_ULINEAR;;
261 1.1 mrg break;
262 1.1 mrg case WAVE_FORMAT_ALAW:
263 1.1 mrg newenc = AUDIO_ENCODING_ALAW;
264 1.1 mrg newprec = 8;
265 1.1 mrg break;
266 1.1 mrg case WAVE_FORMAT_MULAW:
267 1.1 mrg newenc = AUDIO_ENCODING_ULAW;
268 1.1 mrg newprec = 8;
269 1.1 mrg break;
270 1.1 mrg }
271 1.1 mrg
272 1.1 mrg do {
273 1.1 mrg part = (wav_audioheaderpart *)where;
274 1.3 mrg #if 0
275 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));
276 1.3 mrg #endif
277 1.1 mrg where += (getle32(part->len) + 8);
278 1.1 mrg } while ((char *)where < end && strncmp(part->name, "data", 4));
279 1.1 mrg
280 1.3 mrg if ((where - getle32(part->len)) <= end) {
281 1.1 mrg *channels = getle16(fmt->channels);
282 1.1 mrg *sample = getle32(fmt->sample_rate);
283 1.1 mrg *enc = newenc;
284 1.1 mrg *prec = newprec;
285 1.1 mrg part++;
286 1.1 mrg return ((char *)part - (char *)hdr);
287 1.1 mrg }
288 1.1 mrg return (AUDIO_EWAVNODATA);
289 1.1 mrg }
290 1.1 mrg
291 1.1 mrg /*
292 1.1 mrg * these belong elsewhere??
293 1.1 mrg */
294 1.1 mrg void
295 1.1 mrg decode_int(arg, intp)
296 1.1 mrg const char *arg;
297 1.1 mrg int *intp;
298 1.1 mrg {
299 1.1 mrg char *ep;
300 1.1 mrg int ret;
301 1.1 mrg
302 1.1 mrg ret = strtoul(arg, &ep, 0);
303 1.1 mrg
304 1.1 mrg if (ep[0] == '\0') {
305 1.1 mrg *intp = ret;
306 1.1 mrg return;
307 1.1 mrg }
308 1.1 mrg errx(1, "argument `%s' not a valid integer", arg);
309 1.1 mrg }
310 1.1 mrg
311 1.1 mrg #include <stdio.h>
312 1.1 mrg void
313 1.1 mrg decode_time(arg, tvp)
314 1.1 mrg const char *arg;
315 1.1 mrg struct timeval *tvp;
316 1.1 mrg {
317 1.1 mrg char *s, *colon, *dot;
318 1.1 mrg char *copy = strdup(arg);
319 1.1 mrg int first;
320 1.1 mrg
321 1.1 mrg if (copy == NULL)
322 1.1 mrg err(1, "could not allocate a copy of %s", arg);
323 1.1 mrg
324 1.1 mrg tvp->tv_sec = tvp->tv_usec = 0;
325 1.1 mrg s = copy;
326 1.1 mrg
327 1.1 mrg /* handle [hh:]mm:ss.dd */
328 1.1 mrg if ((colon = strchr(s, ':'))) {
329 1.1 mrg *colon++ = '\0';
330 1.1 mrg decode_int(s, &first);
331 1.1 mrg tvp->tv_sec = first * 60; /* minutes */
332 1.1 mrg s = colon;
333 1.1 mrg
334 1.1 mrg if ((colon = strchr(s, ':'))) {
335 1.1 mrg *colon++ = '\0';
336 1.1 mrg decode_int(s, &first);
337 1.1 mrg tvp->tv_sec += first;
338 1.1 mrg tvp->tv_sec *= 60; /* minutes and hours */
339 1.1 mrg s = colon;
340 1.1 mrg }
341 1.1 mrg }
342 1.1 mrg if ((dot = strchr(s, '.'))) {
343 1.1 mrg int i, base = 100000;
344 1.1 mrg
345 1.1 mrg *dot++ = '\0';
346 1.1 mrg
347 1.1 mrg for (i = 0; i < 6; i++, base /= 10) {
348 1.1 mrg if (!dot[i])
349 1.1 mrg break;
350 1.1 mrg if (!isdigit(dot[i]))
351 1.1 mrg errx(1, "argument `%s' is not a value time specification", arg);
352 1.1 mrg tvp->tv_usec += base * (dot[i] - '0');
353 1.1 mrg }
354 1.1 mrg }
355 1.1 mrg decode_int(s, &first);
356 1.1 mrg tvp->tv_sec += first;
357 1.1 mrg #if 0
358 1.1 mrg printf("tvp->tv_sec = %ld, tvp->tv_usec = %ld\n", tvp->tv_sec, tvp->tv_usec);
359 1.1 mrg #endif
360 1.1 mrg
361 1.1 mrg free(copy);
362 1.1 mrg }
363 1.1 mrg
364 1.1 mrg /*
365 1.1 mrg * decode a string into an encoding value.
366 1.1 mrg */
367 1.1 mrg void
368 1.1 mrg decode_encoding(arg, encp)
369 1.1 mrg const char *arg;
370 1.1 mrg int *encp;
371 1.1 mrg {
372 1.1 mrg size_t len;
373 1.1 mrg int i;
374 1.1 mrg
375 1.1 mrg len = strlen(arg);
376 1.1 mrg for (i = 0; encs[i].ename; i++)
377 1.1 mrg if (strncmp(encs[i].ename, arg, len) == 0) {
378 1.1 mrg *encp = encs[i].eno;
379 1.1 mrg return;
380 1.1 mrg }
381 1.1 mrg errx(1, "unknown encoding `%s'", arg);
382 1.1 mrg }
383 1.1 mrg
384 1.1 mrg const char *const audio_errlist[] = {
385 1.1 mrg "no audio entry",
386 1.1 mrg "short header",
387 1.1 mrg "unsupported WAV format",
388 1.1 mrg "bad (unsupported) WAV PCM format",
389 1.1 mrg "no WAV audio data",
390 1.1 mrg };
391 1.1 mrg
392 1.1 mrg const char *
393 1.1 mrg audio_errstring(errval)
394 1.1 mrg int errval;
395 1.1 mrg {
396 1.1 mrg
397 1.1 mrg errval = -errval;
398 1.1 mrg if (errval < 1 || errval > AUDIO_MAXERRNO)
399 1.1 mrg return "Invalid error";
400 1.1 mrg return audio_errlist[errval];
401 1.1 mrg }
402