git: 9front

Download patch

ref: 0608024e29217e4a904cb5d6186045af08b6f1b9
parent: 16b4df4c6d0e521ab3deed40d814b2b8f61cf504
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Thu Dec 13 23:38:45 EST 2012

audio: replace µlawdec, add big endian and µlaw audio formats to pcmconv, µlaw in wav support

to support µ-law audio embedded in wav and big endian pcm
in sun audio files the µ-law and a-law and big endian integer
decoding was added to pcmconv. sundec now parses the sun
audio header supporting stereo now.

--- a/sys/man/1/audio
+++ b/sys/man/1/audio
@@ -1,6 +1,6 @@
 .TH AUDIO 1
 .SH NAME
-mp3dec, mp3enc, oggdec, oggenc, flacdec, µlawdec, wavdec, pcmconv \- decode and encode audio files
+mp3dec, mp3enc, oggdec, oggenc, flacdec, sundec, wavdec, pcmconv \- decode and encode audio files
 .SH SYNOPSIS
 .B audio/mp3dec
 [
@@ -13,7 +13,7 @@
 .br
 .B audio/wavdec
 .br
-.B audio/µlawdec
+.B audio/sundec
 .PP
 .B audio/oggenc
 .br
@@ -65,12 +65,12 @@
 option enables debug output to standard error.
 .I Oggdec,
 .I flacdec,
-.I µlawdec
+.I sunwdec
 and
 .I wavdec
 are like
 .I mp3dec
-but decode OGG Vorbis, FLAC lossless audio, Sun µlaw audio and PCM Wave.
+but decode OGG Vorbis, FLAC lossless audio, Sun audio and RIFF wave.
 .PP
 The encoders read PCM on standard input and produce compressed audio
 on standard output.
@@ -226,17 +226,29 @@
 
 .TP
 .BI s #
-sample format is little endian signed integer where
+sample format is little-endian signed integer where
 .I #
 specifies the number of bits
 .TP
 .BI u #
-unsigned little endian integer format
+unsigned little-endian integer format
 .TP
+.BI S #
+singed big-endian integer format
+.TP
+.BI U #
+unsigned big-endian integer format
+.TP
 .BI f #
 floating point format where
 .I #
-has to be 32 or 64 for single or double precisition
+has to be 32 or 64 for single- or double-precisition
+.TP
+.B a8
+8-bit a-law format
+.TP
+.B µ8
+8-bit µ-law format
 .TP
 .BI c #
 specifies the number of channels
--- a/sys/src/cmd/audio/mkfile
+++ b/sys/src/cmd/audio/mkfile
@@ -1,7 +1,7 @@
 </$objtype/mkfile
 
 LIBS=libogg libvorbis libFLAC
-PROGS=pcmconv oggdec oggenc mp3dec mp3enc flacdec wavdec µlawdec
+PROGS=pcmconv oggdec oggenc mp3dec mp3enc flacdec wavdec sundec
 #libs must be made first
 DIRS=$LIBS $PROGS
 
--- a/sys/src/cmd/audio/pcmconv/pcmconv.c
+++ b/sys/src/cmd/audio/pcmconv/pcmconv.c
@@ -9,8 +9,9 @@
 	int	rate;
 	int	channels;
 	int	framesz;
-	int	bits;
-	int	fmt;
+	int	abits;	/* bits after input conversion */
+	int	bits;	/* bits in input stream per sample */
+	Rune	fmt;
 };
 
 struct Chan
@@ -236,6 +237,31 @@
 }
 
 void
+Siconv(int *dst, uchar *src, int bits, int skip, int count)
+{
+	int i, v, s, b;
+
+	b = (bits+7)/8;
+	s = sizeof(int)*8-bits;
+	while(count--){
+		v = 0;
+		i = 0;
+		switch(b){
+		case 4:
+			v = src[i++];
+		case 3:
+			v = (v<<8) | src[i++];
+		case 2:
+			v = (v<<8) | src[i++];
+		case 1:
+			v = (v<<8) | src[i];
+		}
+		*dst++ = v << s;
+		src += skip;
+	}
+}
+
+void
 uiconv(int *dst, uchar *src, int bits, int skip, int count)
 {
 	int i, s, b;
@@ -262,6 +288,32 @@
 }
 
 void
+Uiconv(int *dst, uchar *src, int bits, int skip, int count)
+{
+	int i, s, b;
+	uint v;
+
+	b = (bits+7)/8;
+	s = sizeof(uint)*8-bits;
+	while(count--){
+		v = 0;
+		i = 0;
+		switch(b){
+		case 4:
+			v = src[i++];
+		case 3:
+			v = (v<<8) | src[i++];
+		case 2:
+			v = (v<<8) | src[i++];
+		case 1:
+			v = (v<<8) | src[i];
+		}
+		*dst++ = (v << s) - (~0UL>>1);
+		src += skip;
+	}
+}
+
+void
 ficonv(int *dst, uchar *src, int bits, int skip, int count)
 {
 	if(bits == 32){
@@ -268,7 +320,7 @@
 		while(count--){
 			float f;
 
-			f = *((float*)src);
+			f = *((float*)src), src += skip;
 			if(f > 1.0)
 				*dst++ = 0x7fffffff;
 			else if(f < -1.0)
@@ -275,13 +327,12 @@
 				*dst++ = -0x80000000;
 			else
 				*dst++ = f*2147483647.f;
-			src += skip;
 		}
 	} else {
 		while(count--){
 			double d;
 
-			d = *((double*)src);
+			d = *((double*)src), src += skip;
 			if(d > 1.0)
 				*dst++ = 0x7fffffff;
 			else if(d < -1.0)
@@ -288,12 +339,54 @@
 				*dst++ = -0x80000000;
 			else
 				*dst++ = d*2147483647.f;
-			src += skip;
 		}
 	}
 }
 
 void
+aiconv(int *dst, uchar *src, int, int skip, int count)
+{
+	int t, seg;
+	uchar a;
+
+	while(count--){
+		a = *src, src += skip;
+		a ^= 0x55;
+		t = (a & 0xf) << 4;
+		seg = (a & 0x70) >> 4;
+		switch(seg){
+		case 0:
+			t += 8;
+			break;
+		case 1:
+			t += 0x108;
+			break;
+		default:
+			t += 0x108;
+			t <<= seg - 1;
+		}
+		t = (a & 0x80) ? t : -t;
+		*dst++ = t << (sizeof(int)*8 - 16);
+	}
+}
+
+void
+µiconv(int *dst, uchar *src, int, int skip, int count)
+{
+	int t;
+	uchar u;
+
+	while(count--){
+		u = *src, src += skip;
+		u = ~u;
+		t = ((u & 0xf) << 3) + 0x84;
+		t <<= (u & 0x70) >> 4;
+		t = u & 0x80 ? 0x84 - t: t - 0x84;
+		*dst++ = t << (sizeof(int)*8 - 16);
+	}
+}
+
+void
 soconv(int *src, uchar *dst, int bits, int skip, int count)
 {
 	int i, v, s, b;
@@ -318,6 +411,30 @@
 }
 
 void
+Soconv(int *src, uchar *dst, int bits, int skip, int count)
+{
+	int i, v, s, b;
+
+	b = (bits+7)/8;
+	s = sizeof(int)*8-bits;
+	while(count--){
+		v = *src++ >> s;
+		i = b;
+		switch(b){
+		case 4:
+			dst[--i] = v, v >>= 8;
+		case 3:
+			dst[--i] = v, v >>= 8;
+		case 2:
+			dst[--i] = v, v >>= 8;
+		case 1:
+			dst[--i] = v;
+		}
+		dst += skip;
+	}
+}
+
+void
 uoconv(int *src, uchar *dst, int bits, int skip, int count)
 {
 	int i, s, b;
@@ -343,6 +460,31 @@
 }
 
 void
+Uoconv(int *src, uchar *dst, int bits, int skip, int count)
+{
+	int i, s, b;
+	uint v;
+
+	b = (bits+7)/8;
+	s = sizeof(uint)*8-bits;
+	while(count--){
+		v = ((~0UL>>1) + *src++) >> s;
+		i = b;
+		switch(b){
+		case 4:
+			dst[--i] = v, v >>= 8;
+		case 3:
+			dst[--i] = v, v >>= 8;
+		case 2:
+			dst[--i] = v, v >>= 8;
+		case 1:
+			dst[--i] = v;
+		}
+		dst += skip;
+	}
+}
+
+void
 foconv(int *src, uchar *dst, int bits, int skip, int count)
 {
 	if(bits == 32){
@@ -362,24 +504,31 @@
 mkdesc(char *f)
 {
 	Desc d;
-	int c;
+	Rune r;
 	char *p;
 
 	memset(&d, 0, sizeof(d));
 	p = f;
-	while(c = *p++){
-		switch(c){
-		case 'r':
+	while(*p != 0){
+		p += chartorune(&r, p);
+		switch(r){
+		case L'r':
 			d.rate = strtol(p, &p, 10);
 			break;
-		case 'c':
+		case L'c':
 			d.channels = strtol(p, &p, 10);
 			break;
-		case 's':
-		case 'u':
-		case 'f':
-			d.fmt = c;
-			d.bits = strtol(p, &p, 10);
+		case L'm':
+			r = L'µ';
+		case L's':
+		case L'S':
+		case L'u':
+		case L'U':
+		case L'f':
+		case L'a':
+		case L'µ':
+			d.fmt = r;
+			d.bits = d.abits = strtol(p, &p, 10);
 			break;
 		default:
 			goto Bad;
@@ -387,9 +536,14 @@
 	}
 	if(d.rate <= 0)
 		goto Bad;
-	if(d.fmt == 'f'){
+	if(d.fmt == L'a' || d.fmt == L'µ'){
+		if(d.bits != 8)
+			goto Bad;
+		d.abits = sizeof(int)*8 - 16;
+	} else if(d.fmt == L'f'){
 		if(d.bits != 32 && d.bits != 64)
 			goto Bad;
+		d.abits = sizeof(int)*8;
 	} else if(d.bits <= 0 || d.bits > 32)
 		goto Bad;
 	d.framesz = ((d.bits+7)/8) * d.channels;
@@ -472,21 +626,31 @@
 	}
 
 	if(i.channels > nelem(ch))
-		sysfatal("too many input channels %d", i.channels);
+		sysfatal("too many input channels: %d", i.channels);
 
 	switch(i.fmt){
-	case 's': iconv = siconv; break;
-	case 'u': iconv = uiconv; break;
-	case 'f': iconv = ficonv; break;
+	case L's': iconv = siconv; break;
+	case L'S': iconv = Siconv; break;
+	case L'u': iconv = uiconv; break;
+	case L'U': iconv = Uiconv; break;
+	case L'f': iconv = ficonv; break;
+	case L'a': iconv = aiconv; break;
+	case L'µ': iconv = µiconv; break;
+	default:
+		sysfatal("unsupported input format: %C", i.fmt);
 	}
 
 	switch(o.fmt){
-	case 's': oconv = soconv; break;
-	case 'u': oconv = uoconv; break;
-	case 'f': oconv = foconv; break;
+	case L's': oconv = soconv; break;
+	case L'S': oconv = Soconv; break;
+	case L'u': oconv = uoconv; break;
+	case L'U': oconv = Uoconv; break;
+	case L'f': oconv = foconv; break;
+	default:
+		sysfatal("unsupported output format: %C", o.fmt);
 	}
 
-	if(i.fmt == 'f' || o.fmt == 'f')
+	if(i.fmt == L'f' || o.fmt == L'f')
 		setfcr(getfcr() & ~(FPINVAL|FPOVFL));
 
 	nin = (sizeof(ibuf)-i.framesz)/i.framesz;
@@ -511,7 +675,7 @@
 			l -= n;
 		n /= i.framesz;
 		(*iconv)(in, ibuf, i.bits, i.framesz, n);
-		dither(in, i.bits, o.bits, n);
+		dither(in, i.abits, o.abits, n);
 		m = resample(&ch[0], in, out, n) - out;
 		if(m < 1){
 			if(n == 0)
@@ -521,7 +685,7 @@
 		if(i.channels == o.channels){
 			for(k=1; k<i.channels; k++){
 				(*iconv)(in, ibuf + k*((i.bits+7)/8), i.bits, i.framesz, n);
-				dither(in, i.bits, o.bits, n);
+				dither(in, i.abits, o.abits, n);
 				resample(&ch[k], in, out, n);
 				if(m > 0)
 					(*oconv)(out, obuf + k*((o.bits+7)/8), o.bits, o.framesz, m);
--- /dev/null
+++ b/sys/src/cmd/audio/sundec/mkfile
@@ -1,0 +1,8 @@
+</$objtype/mkfile
+<../config
+
+OFILES=sundec.$O
+
+TARG=sundec
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/sys/src/cmd/audio/sundec/sundec.c
@@ -1,0 +1,62 @@
+#include <u.h>
+#include <libc.h>
+
+ulong
+get4(void)
+{
+	uchar buf[4];
+
+	if(readn(0, buf, 4) != 4)
+		sysfatal("read: %r");
+	return buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3];
+}
+
+char *fmttab[] = {
+	[1] "µ8",	/* 8-bit G.711 µ-law */
+	[2] "S8",	/* 8-bit linear PCM */
+	[3] "S16",	/* 16-bit linear PCM */
+	[4] "S24",	/* 24-bit linear PCM */
+	[5] "S32",	/* 32-bit linear PCM */
+	[6] "f32",	/* 32-bit IEEE floating point */
+	[7] "f64",	/* 64-bit IEEE floating point */
+	[27] "a8",	/* 8-bit G.711 A-law */
+};
+
+void
+main(int, char *argv[])
+{
+	char buf[64], fmt[32];
+	ulong enc, rate, chans, len, off;
+	int n;
+
+	argv0 = argv[0];
+	if(get4() != 0x2e736e64UL)
+		sysfatal("no sun format");
+	off = get4();
+	if(off < 24)
+		sysfatal("bad data ofset");
+	off -= 24;
+	len = get4();
+	if(len == 0xffffffffUL)
+		len = 0;
+	enc = get4();
+	rate = get4();
+	chans = get4();
+	if(enc >= nelem(fmttab) || fmttab[enc] == 0)
+		sysfatal("unsupported encoding: %lux", enc);
+	snprint(fmt, sizeof(fmt), "%sc%ludr%lud", fmttab[enc], chans, rate);
+	while(off > 0){
+		n = sizeof(buf);
+		if(off < n)
+			n = off;
+		n = read(0, buf, n);
+		if(n <= 0)
+			sysfatal("read: %r");
+		off -= n;
+	}
+	if(len > 0){
+		snprint(buf, sizeof(buf), "%lud", len);
+		execl("/bin/audio/pcmconv", "pcmconv", "-i", fmt, "-l", buf, 0);
+	} else
+		execl("/bin/audio/pcmconv", "pcmconv", "-i", fmt, 0);
+}
--- a/sys/src/cmd/audio/wavdec/wavdec.c
+++ b/sys/src/cmd/audio/wavdec/wavdec.c
@@ -42,7 +42,7 @@
 void
 main(int, char *argv[])
 {
-	char buf[8*1024], fmt[32];
+	char buf[1024], fmt[32];
 	ulong len, n;
 	Wave wav;
 
@@ -70,22 +70,32 @@
 			len -= 2+2+4+4+2+2;
 		}
 		while(len > 0){
-			if(len < sizeof(buf))
+			n = sizeof(buf);
+			if(len < n)
 				n = len;
-			else
-				n = sizeof(buf);
-			if(readn(0, buf, n) != n)
+			n = read(0, buf, n);
+			if(n <= 0)
 				sysfatal("read: %r");
 			len -= n;
 		}
 	}
-
-	if(wav.fmt != 1)
-		sysfatal("compressed format (0x%x) not supported", wav.fmt);
-	snprint(fmt, sizeof(fmt), "%c%dr%dc%d",
-		wav.bits == 8 ? 'u' : 's', wav.bits,
-		wav.rate,
-		wav.channels);
+	switch(wav.fmt){
+	case 1:
+		snprint(fmt, sizeof(fmt), "%c%dr%dc%d", wav.bits == 8 ? 'u' : 's',
+			wav.bits, wav.rate, wav.channels);
+		break;
+	case 3:
+		snprint(fmt, sizeof(fmt), "f32r%dc%d", wav.rate, wav.channels);
+		break;
+	case 6:
+		snprint(fmt, sizeof(fmt), "a8r%dc%d", wav.rate, wav.channels);
+		break;
+	case 7:
+		snprint(fmt, sizeof(fmt), "µ8r%dc%d", wav.rate, wav.channels);
+		break;
+	default:
+		sysfatal("wave format (0x%lux) not supported", (ulong)wav.fmt);
+	}
 	snprint(buf, sizeof(buf), "%lud", len);
 	execl("/bin/audio/pcmconv", "pcmconv", "-i", fmt, "-l", buf, 0);
 }
--- a/sys/src/cmd/audio/µlawdec/mkfile
+++ /dev/null
@@ -1,8 +1,0 @@
-</$objtype/mkfile
-<../config
-
-OFILES=µlawdec.$O
-
-TARG=µlawdec
-
-</sys/src/cmd/mkone
--- a/sys/src/cmd/audio/µlawdec/µlawdec.c
+++ /dev/null
@@ -1,368 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-
-enum {
-	Qmask	= 0xf,		/* quantization mask */
-	Nsegs	= 8,		/* A-law segments */
-	Segshift	= 4,
-	Segmask	= 0x70,
-};
-
-static short segend[Nsegs] = {
-	0xff,	0x1ff,	0x3ff,	0x7ff,
-	0xfff,	0x1fff,	0x3fff,	0x7fff
-};
-
-/* copy from CCITT G.711 specifications */
-static uchar u2a[128] = {			/* μ- to A-law conversions */
-	1,	1,	2,	2,	3,	3,	4,	4,
-	5,	5,	6,	6,	7,	7,	8,	8,
-	9,	10,	11,	12,	13,	14,	15,	16,
-	17,	18,	19,	20,	21,	22,	23,	24,
-	25,	27,	29,	31,	33,	34,	35,	36,
-	37,	38,	39,	40,	41,	42,	43,	44,
-	46,	48,	49,	50,	51,	52,	53,	54,
-	55,	56,	57,	58,	59,	60,	61,	62,
-	64,	65,	66,	67,	68,	69,	70,	71,
-	72,	73,	74,	75,	76,	77,	78,	79,
-	81,	82,	83,	84,	85,	86,	87,	88,
-	89,	90,	91,	92,	93,	94,	95,	96,
-	97,	98,	99,	100,	101,	102,	103,	104,
-	105,	106,	107,	108,	109,	110,	111,	112,
-	113,	114,	115,	116,	117,	118,	119,	120,
-	121,	122,	123,	124,	125,	126,	127,	128
-};
-
-static uchar a2u[128] = {			/* A- to μ-law conversions */
-	1,	3,	5,	7,	9,	11,	13,	15,
-	16,	17,	18,	19,	20,	21,	22,	23,
-	24,	25,	26,	27,	28,	29,	30,	31,
-	32,	32,	33,	33,	34,	34,	35,	35,
-	36,	37,	38,	39,	40,	41,	42,	43,
-	44,	45,	46,	47,	48,	48,	49,	49,
-	50,	51,	52,	53,	54,	55,	56,	57,
-	58,	59,	60,	61,	62,	63,	64,	64,
-	65,	66,	67,	68,	69,	70,	71,	72,
-	73,	74,	75,	76,	77,	78,	79,	79,
-	80,	81,	82,	83,	84,	85,	86,	87,
-	88,	89,	90,	91,	92,	93,	94,	95,
-	96,	97,	98,	99,	100,	101,	102,	103,
-	104,	105,	106,	107,	108,	109,	110,	111,
-	112,	113,	114,	115,	116,	117,	118,	119,
-	120,	121,	122,	123,	124,	125,	126,	127
-};
-
-/* speed doesn't matter.  table has 8 entires */
-static int
-search(int val, short *table, int size)
-{
-	int i;
-
-	for (i = 0; i < size; i++) {
-		if (val <= *table++)
-			return i;
-	}
-	return size;
-}
-
-/*
- * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
- *
- * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
- *
- *		Linear Input Code	Compressed Code
- *	------------------------	---------------
- *	0000000wxyza			000wxyz
- *	0000001wxyza			001wxyz
- *	000001wxyzab			010wxyz
- *	00001wxyzabc			011wxyz
- *	0001wxyzabcd			100wxyz
- *	001wxyzabcde			101wxyz
- *	01wxyzabcdef			110wxyz
- *	1wxyzabcdefg			111wxyz
- *
- * For further information see John C. Bellamy's Digital Telephony, 1982,
- * John Wiley & Sons, pps 98-111 and 472-476.
- */
-uchar
-linear2alaw(int pcm)	/* 2's complement (16-bit range) */
-{
-	uchar aval;
-	int mask, seg;
-
-	if (pcm >= 0) {
-		mask = 0xd5;		/* sign (7th) bit = 1 */
-	} else {
-		mask = 0x55;		/* sign bit = 0 */
-		pcm = -pcm - 8;
-	}
-
-	/* Convert the scaled magnitude to segment number. */
-	seg = search(pcm, segend, 8);
-
-	/* Combine the sign, segment, and quantization bits. */
-	if (seg >= 8)
-		/* out of range, return maximum value. */
-		return 0x7f ^ mask;
-	else {
-		aval = seg << Segshift;
-		if (seg < 2)
-			aval |= pcm>>4 & Qmask;
-		else
-			aval |= pcm>>(seg + 3) & Qmask;
-		return aval ^ mask;
-	}
-}
-
-/*
- * alaw2linear() - Convert an A-law value to 16-bit linear PCM
- *
- */
-int
-alaw2linear(uchar a)
-{
-	int t, seg;
-
-	a ^= 0x55;
-
-	t = (a & Qmask) << 4;
-	seg = (a & Segmask) >> Segshift;
-	switch (seg) {
-	case 0:
-		t += 8;
-		break;
-	case 1:
-		t += 0x108;
-		break;
-	default:
-		t += 0x108;
-		t <<= seg - 1;
-	}
-	return (a & 0x80) ? t : -t;
-}
-
-enum {
-	Bias	= 0x84,		/* Bias for linear code. */
-};
-
-/*
- * linear2μlaw() - Convert a linear PCM value to μ-law
- *
- * In order to simplify the encoding process, the original linear magnitude
- * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
- * (33 - 8191). The result can be seen in the following encoding table:
- *
- *	Biased Linear Input Code	Compressed Code
- *	------------------------	---------------
- *	00000001wxyza			000wxyz
- *	0000001wxyzab			001wxyz
- *	000001wxyzabc			010wxyz
- *	00001wxyzabcd			011wxyz
- *	0001wxyzabcde			100wxyz
- *	001wxyzabcdef			101wxyz
- *	01wxyzabcdefg			110wxyz
- *	1wxyzabcdefgh			111wxyz
- *
- * Each biased linear code has a leading 1 which identifies the segment
- * number. The value of the segment number is equal to 7 minus the number
- * of leading 0's. The quantization interval is directly available as the
- * four bits wxyz.  * The trailing bits (a - h) are ignored.
- *
- * Ordinarily the complement of the resulting code word is used for
- * transmission, and so the code word is complemented before it is returned.
- *
- * For further information see John C. Bellamy's Digital Telephony, 1982,
- * John Wiley & Sons, pps 98-111 and 472-476.
- */
-uchar
-linear2μlaw(int pcm)
-{
-	int mask, seg;
-	uchar uval;
-
-	/* Get the sign and the magnitude of the value. */
-	if (pcm < 0) {
-		pcm = Bias - pcm;
-		mask = 0x7f;
-	} else {
-		pcm += Bias;
-		mask = 0xff;
-	}
-
-	/* Convert the scaled magnitude to segment number. */
-	seg = search(pcm, segend, 8);
-
-	/*
-	 * Combine the sign, segment, quantization bits;
-	 * and complement the code word.
-	 */
-	if (seg >= 8)
-		/* out of range, return maximum value. */
-		return 0x7f ^ mask;
-	else {
-		uval = seg<< 4 | ((pcm >> (seg + 3)) & 0xf);
-		return uval ^ mask;
-	}
-}
-
-/*
- * μlaw2linear() - Convert a μ-law value to 16-bit linear PCM
- *
- * First, a biased linear code is derived from the code word. An unbiased
- * output can then be obtained by subtracting 33 from the biased code.
- *
- * Note that this function expects to be passed the complement of the
- * original code word. This is in keeping with ISDN conventions.
- */
-int
-μlaw2linear(uchar μ)
-{
-	int t;
-
-	/* Complement to obtain normal μ-law value. */
-	μ = ~μ;
-
-	/*
-	 * Extract and bias the quantization bits. Then
-	 * shift up by the segment number and subtract out the bias.
-	 */
-	t = ((μ & Qmask) << 3) + Bias;
-	t <<= (μ & Segmask) >> Segshift;
-
-	return μ & 0x80? Bias - t: t - Bias;
-}
-
-/* A-law to μ-law conversion */
-uchar
-alaw2μlaw(uchar a)
-{
-//	a &= 0xff;
-	if(a & 0x80)
-		return 0xff ^ a2u[a ^ 0xd5];
-	else
-		return 0x7f ^ a2u[a ^ 0x55];
-}
-
-/* μ-law to A-law conversion */
-uchar
-μlaw2alaw(uchar μ)
-{
-//	μ &= 0xff;
-	if(μ & 0x80)
-		return 0xd5 ^ u2a[0xff ^ μ] - 1;
-	else
-		return 0x55 ^ u2a[0x7f ^ μ] - 1;
-}
-
-static void
-setrate(int rate)
-{
-	int fd;
-
-	fd = open("/dev/volume", OWRITE);
-	if(fd == -1){
-		fprint(2, "μlawdec: can't set rate %d: open: %r\n", rate);
-		return;
-	}
-	if(fprint(fd, "speed %d", rate) == -1)
-		fprint(2, "μlawdec: can't set rate %d: fprint: %r\n", rate);
-	else
-		fprint(2, "μlawdec: rate %d\n", rate);
-	close(fd);
-}
-
-enum {
-	Sig	= 0,
-	Offset	= 1,
-	Enc	= 3,
-	Rate	= 4,
-	Nchan	= 5,
-};
-
-u32int
-μlawword(uchar *buf, int w)
-{
-	buf += 4*w;
-	return buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3];
-}
-
-int
-pcmconv(char *fmt)
-{
-	int pid, pfd[2];
-
-	if(pipe(pfd) < 0)
-		return -1;
-	pid = fork();
-	if(pid < 0){
-		close(pfd[0]);
-		close(pfd[1]);
-		return -1;
-	}
-	if(pid == 0){
-		dup(pfd[1], 0);
-		close(pfd[1]);
-		close(pfd[0]);
-		execl("/bin/audio/pcmconv", "pcmconv", "-i", fmt, 0);
-		sysfatal("exec: %r");
-	}
-	close(pfd[1]);
-	return pfd[0];
-}
-
-void
-main(void)
-{
-	int fd, n;
-	uchar buf[5*4];
-	char fmt[32];
-	vlong off;
-	Biobuf i, o;
-
-	if(Binit(&i, 0, OREAD) == -1)
-		sysfatal("μlawdec: Binit: %r");
-	if(Bread(&i, buf, sizeof buf) != sizeof buf)
-		sysfatal("μlawdec: Bread: %r");
-	off = μlawword(buf, Offset);
-	if(off < 24)
-		sysfatal("μlawdec: bad offset: %lld", off);
-	if(μlawword(buf, Sig) != 0x2e736e64)
-		sysfatal("μlawdec: not .au file");
-	if(μlawword(buf, Enc) != 1)
-		sysfatal("μlawdec: not μlaw");
-
-	snprint(fmt, sizeof(fmt), "s16c1r%d", μlawword(buf, Rate));
-	fd = pcmconv(fmt);
-	if(fd < 0)
-		sysfatal("μlawdec: pcmconv: %r");
-
-	if(Binit(&o, fd, OWRITE) == -1)
-		sysfatal("μlawdec: Binit: %r");
-
-	while(off > 0){
-		n = sizeof(buf);
-		if(off < n)
-			n = off;
-		if(Bread(&i, buf, n) != n)
-			sysfatal("μlawdec: Bread: %r");
-		off -= n;
-	}
-
-	for(;;){
-		switch(Bread(&i, buf, 1)){
-		case 0:
-			goto done;
-		case -1:
-			sysfatal("μlawdec: Bread: %r");
-		}
-		n = μlaw2linear(buf[0]);
-		buf[0] = n&0xff;
-		buf[1] = (n&0xff00)>>8;
-		if(Bwrite(&o, buf, 2) != 2)
-			sysfatal("μlawdec: Bwrite: %r");
-	}
-done:
-	Bterm(&o);
-	Bterm(&i);
-}
--