summaryrefslogtreecommitdiff
path: root/sys/src/cmd/audio
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2012-12-14 04:38:45 +0100
committercinap_lenrek <cinap_lenrek@gmx.de>2012-12-14 04:38:45 +0100
commit5ceb834f0ed45978497ff81582b7c828d27dcf6f (patch)
tree7d3b283a1c43120c6eee7f4305fcedab5974c648 /sys/src/cmd/audio
parentd7b7723c96cdee0be6a5120293ecfde60bd65bdc (diff)
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.
Diffstat (limited to 'sys/src/cmd/audio')
-rw-r--r--sys/src/cmd/audio/mkfile2
-rw-r--r--sys/src/cmd/audio/pcmconv/pcmconv.c218
-rw-r--r--sys/src/cmd/audio/sundec/mkfile (renamed from sys/src/cmd/audio/µlawdec/mkfile)4
-rw-r--r--sys/src/cmd/audio/sundec/sundec.c62
-rw-r--r--sys/src/cmd/audio/wavdec/wavdec.c34
-rw-r--r--sys/src/cmd/audio/µlawdec/µlawdec.c368
6 files changed, 278 insertions, 410 deletions
diff --git a/sys/src/cmd/audio/mkfile b/sys/src/cmd/audio/mkfile
index ddc4af14d..f5d59a139 100644
--- 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
diff --git a/sys/src/cmd/audio/pcmconv/pcmconv.c b/sys/src/cmd/audio/pcmconv/pcmconv.c
index 92f963ac6..add9b0548 100644
--- a/sys/src/cmd/audio/pcmconv/pcmconv.c
+++ b/sys/src/cmd/audio/pcmconv/pcmconv.c
@@ -9,8 +9,9 @@ struct Desc
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 @@ siconv(int *dst, uchar *src, int bits, int skip, int count)
}
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,38 +288,105 @@ uiconv(int *dst, uchar *src, int bits, int skip, int count)
}
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){
while(count--){
float f;
- f = *((float*)src);
+ f = *((float*)src), src += skip;
if(f > 1.0)
*dst++ = 0x7fffffff;
else if(f < -1.0)
*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)
*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 @@ soconv(int *src, uchar *dst, int bits, int skip, int count)
}
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 @@ uoconv(int *src, uchar *dst, int bits, int skip, int count)
}
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 @@ Desc
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 @@ mkdesc(char *f)
}
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 @@ main(int argc, char *argv[])
}
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 @@ main(int argc, char *argv[])
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 @@ main(int argc, char *argv[])
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);
diff --git a/sys/src/cmd/audio/µlawdec/mkfile b/sys/src/cmd/audio/sundec/mkfile
index c4ed6668c..33be86055 100644
--- a/sys/src/cmd/audio/µlawdec/mkfile
+++ b/sys/src/cmd/audio/sundec/mkfile
@@ -1,8 +1,8 @@
</$objtype/mkfile
<../config
-OFILES=µlawdec.$O
+OFILES=sundec.$O
-TARG=µlawdec
+TARG=sundec
</sys/src/cmd/mkone
diff --git a/sys/src/cmd/audio/sundec/sundec.c b/sys/src/cmd/audio/sundec/sundec.c
new file mode 100644
index 000000000..345bcc03e
--- /dev/null
+++ b/sys/src/cmd/audio/sundec/sundec.c
@@ -0,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);
+}
diff --git a/sys/src/cmd/audio/wavdec/wavdec.c b/sys/src/cmd/audio/wavdec/wavdec.c
index 77a7e3e26..9b116c550 100644
--- a/sys/src/cmd/audio/wavdec/wavdec.c
+++ b/sys/src/cmd/audio/wavdec/wavdec.c
@@ -42,7 +42,7 @@ getcc(char tag[4])
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 @@ main(int, char *argv[])
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);
}
diff --git a/sys/src/cmd/audio/µlawdec/µlawdec.c b/sys/src/cmd/audio/µlawdec/µlawdec.c
deleted file mode 100644
index 3c55f83f8..000000000
--- a/sys/src/cmd/audio/µlawdec/µlawdec.c
+++ /dev/null
@@ -1,368 +0,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);
-}