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