Home | History | Annotate | Line # | Download | only in common
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