summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@flatbox.9hal>2012-03-08 07:25:14 +0100
committercinap_lenrek <cinap_lenrek@flatbox.9hal>2012-03-08 07:25:14 +0100
commit388cd56d6917c9e3fdbf29801cdd9d379d1c938f (patch)
treebbc206880d4d00f3f9a8910aeebd73f1367c9b7a
parentf0facb2ed88a2d9768340c9577aede526df3c09f (diff)
downloadplan9front-388cd56d6917c9e3fdbf29801cdd9d379d1c938f.tar.xz
wave pcm support
-rwxr-xr-xrc/bin/play2
-rw-r--r--sys/man/1/audio11
-rw-r--r--sys/src/cmd/audio/mkfile2
-rw-r--r--sys/src/cmd/audio/wavdec/mkfile10
-rw-r--r--sys/src/cmd/audio/wavdec/wavdec.c215
5 files changed, 235 insertions, 5 deletions
diff --git a/rc/bin/play b/rc/bin/play
index bd15dec77..b3cd2833c 100755
--- a/rc/bin/play
+++ b/rc/bin/play
@@ -47,6 +47,8 @@ fn play1 {
audio/oggdec
case *mp3* *mpeg*
audio/mp3dec
+ case *wave*
+ audio/wavdec
case *flac*
audio/flacdec
case *pls*
diff --git a/sys/man/1/audio b/sys/man/1/audio
index c941fa5f0..5736a3341 100644
--- a/sys/man/1/audio
+++ b/sys/man/1/audio
@@ -1,6 +1,6 @@
.TH AUDIO 1
.SH NAME
-mp3dec, mp3enc, oggdec, oggenc, flacdec \- decode and encode audio files
+mp3dec, mp3enc, oggdec, oggenc, flacdec, wavdec \- decode and encode audio files
.SH SYNOPSIS
.B audio/mp3dec
[
@@ -10,6 +10,8 @@ mp3dec, mp3enc, oggdec, oggenc, flacdec \- decode and encode audio files
.B audio/oggdec
.br
.B audio/flacdec
+.br
+.B audio/wavdec
.PP
.B audio/oggenc
.br
@@ -47,12 +49,13 @@ a sampling frequency of 44.1KHz.
decodes MPEG audio (layer 1, 2 and 3). The
.B -d
option enables debug output to standard error.
-.I Oggdec
-and
+.I Oggdec,
.I flacdec
+and
+.I wavdec
are like
.I mp3dec
-but decode OGG Vorbis and FLAC lossless audio.
+but decode OGG Vorbis, FLAC lossless audio and PCM Wave.
.PP
The encoders read PCM on standard input and produce compressed audio
on standard output.
diff --git a/sys/src/cmd/audio/mkfile b/sys/src/cmd/audio/mkfile
index b7e11bfc2..20a7c9663 100644
--- a/sys/src/cmd/audio/mkfile
+++ b/sys/src/cmd/audio/mkfile
@@ -1,7 +1,7 @@
</$objtype/mkfile
LIBS=libogg libvorbis libFLAC
-PROGS=oggdec oggenc mp3dec mp3enc flacdec
+PROGS=oggdec oggenc mp3dec mp3enc flacdec wavdec
#libs must be made first
DIRS=$LIBS $PROGS
diff --git a/sys/src/cmd/audio/wavdec/mkfile b/sys/src/cmd/audio/wavdec/mkfile
new file mode 100644
index 000000000..658c8bf80
--- /dev/null
+++ b/sys/src/cmd/audio/wavdec/mkfile
@@ -0,0 +1,10 @@
+</$objtype/mkfile
+<../config
+
+OFILES=wavdec.$O
+
+TARG=wavdec
+
+</sys/src/cmd/mkone
+
+CFLAGS=-FVp
diff --git a/sys/src/cmd/audio/wavdec/wavdec.c b/sys/src/cmd/audio/wavdec/wavdec.c
new file mode 100644
index 000000000..5189a60f6
--- /dev/null
+++ b/sys/src/cmd/audio/wavdec/wavdec.c
@@ -0,0 +1,215 @@
+#include <u.h>
+#include <libc.h>
+
+int debug = 0;
+int rate = 44100;
+
+typedef struct Wave Wave;
+typedef struct Chan Chan;
+
+struct Chan
+{
+ ulong phase;
+ int last;
+};
+
+struct Wave
+{
+ int rate;
+ int channels;
+ int framesz;
+ int bits;
+ int fmt;
+};
+
+ulong
+get2(void)
+{
+ uchar buf[2];
+
+ if(readn(0, buf, 2) != 2)
+ sysfatal("read: %r");
+ return buf[0] | buf[1]<<8;
+}
+
+ulong
+get4(void)
+{
+ uchar buf[4];
+
+ if(readn(0, buf, 4) != 4)
+ sysfatal("read: %r");
+ return buf[0] | buf[1]<<8 | buf[2]<<16 | buf[3]<<24;
+}
+
+uchar*
+getcc(uchar tag[4])
+{
+ if(readn(0, tag, 4) != 4)
+ sysfatal("read: %r");
+ return tag;
+}
+
+uchar*
+resample(Chan *c, int *src, uchar *dst, int mono, ulong delta, ulong count)
+{
+ int last, val, out;
+ ulong phase, pos;
+ vlong v;
+
+ last = c->last;
+ phase = c->phase;
+ pos = phase >> 16;
+ while(pos < count){
+ val = src[pos];
+ if(pos)
+ last = src[pos-1];
+
+ /* interpolate */
+ v = val;
+ v -= last;
+ v *= (phase & 0xFFFF);
+ out = (last + (v >> 16)) >> (sizeof(int)*8 - 16);
+
+ *dst++ = out;
+ *dst++ = out >> 8;
+ if(mono){
+ *dst++ = out;
+ *dst++ = out >> 8;
+ } else
+ dst += 2;
+ phase += delta;
+ pos = phase >> 16;
+ }
+ c->last = val;
+ if(delta < 0x10000)
+ c->phase = phase & 0xFFFF;
+ else
+ c->phase = phase - (count << 16);
+
+ return dst;
+}
+
+void
+conv(int *dst, uchar *src, int bits, int skip, int n)
+{
+ int i, v;
+
+ while(n--){
+ if(bits == 8)
+ v = (int)src[0] - 127;
+ else {
+ v = 0;
+ switch(i = bits/8){
+ 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];
+ }
+ }
+ v <<= sizeof(int)*8-bits;
+ *dst++ = v;
+ src += skip;
+ }
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [ -d ]\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ uchar buf[8*1024], *out, *p;
+ int *samples;
+ Chan c0, c1;
+ Wave wav;
+ ulong delta, len;
+ int n, z;
+
+ ARGBEGIN {
+ case 'd':
+ debug++;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if(memcmp(getcc(buf), "RIFF", 4) != 0)
+ sysfatal("no riff format");
+ get4();
+ if(memcmp(getcc(buf), "WAVE", 4) != 0)
+ sysfatal("not a wave file");
+
+ for(;;){
+ getcc(buf);
+ len = get4();
+ if(memcmp(buf, "data", 4) == 0)
+ break;
+ if(memcmp(buf, "fmt ", 4) == 0){
+ if(len < 2+2+4+4+2+2)
+ sysfatal("format chunk too small");
+ wav.fmt = get2();
+ wav.channels = get2();
+ wav.rate = get4();
+ get4();
+ wav.framesz = get2();
+ wav.bits = get2();
+ len -= 2+2+4+4+2+2;
+ }
+ while(len > 0){
+ if(len < sizeof(buf))
+ n = len;
+ else
+ n = sizeof(buf);
+ if(readn(0, buf, n) != n)
+ sysfatal("read: %r");
+ len -= n;
+ }
+ }
+
+ if(wav.fmt != 1)
+ sysfatal("compressed format (0x%x) not supported", wav.fmt);
+ if(wav.framesz <= 0 || wav.bits <= 0 || wav.framesz != wav.channels*wav.bits/8)
+ sysfatal("bad format");
+ if(debug)
+ fprint(2, "wave: PCM %d Hz, %d ch, %d bits\n",
+ wav.rate, wav.channels, wav.bits);
+
+ delta = (wav.rate << 16) / rate;
+ n = sizeof(buf)/wav.framesz;
+ samples = malloc(sizeof(int) * n);
+ out = malloc(4 * ((wav.rate + n*rate)/wav.rate));
+ if(samples == nil || out == nil)
+ sysfatal("out of memory");
+
+ while(len % wav.framesz)
+ --len;
+ while(len){
+ if(len < sizeof(buf))
+ n = len;
+ else
+ n = sizeof(buf);
+ while(n % wav.framesz)
+ --n;
+ if(readn(0, buf, n) != n)
+ sysfatal("read: %r");
+ len -= n;
+ n /= wav.framesz;
+ if(wav.channels == 2){
+ conv(samples, buf + wav.bits/8, wav.bits, wav.framesz, n);
+ resample(&c1, samples, out+2, 0, delta, n);
+ }
+ conv(samples, buf, wav.bits, wav.framesz, n);
+ p = resample(&c0, samples, out, wav.channels == 1, delta, n);
+ write(1, out, p-out);
+ }
+ exits(0);
+}