git: 9front

Download patch

ref: 56e57d5db5b92a82dbba0469ba483ac668d34b2e
parent: c22a6c9415d40dbb97a40a941d344575d5fcc092
author: cinap_lenrek <cinap_lenrek@flatbox.9hal>
date: Thu Mar 8 02:25:14 EST 2012

wave pcm support

--- a/rc/bin/play
+++ b/rc/bin/play
@@ -47,6 +47,8 @@
 			audio/oggdec
 		case *mp3* *mpeg*
 			audio/mp3dec
+		case *wave*
+			audio/wavdec
 		case *flac*
 			audio/flacdec
 		case *pls*
--- 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 @@
 .B audio/oggdec
 .br
 .B audio/flacdec
+.br
+.B audio/wavdec
 .PP
 .B audio/oggenc
 .br
@@ -47,12 +49,13 @@
 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.
--- 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
 
--- /dev/null
+++ b/sys/src/cmd/audio/wavdec/mkfile
@@ -1,0 +1,10 @@
+</$objtype/mkfile
+<../config
+
+OFILES=wavdec.$O
+
+TARG=wavdec
+
+</sys/src/cmd/mkone
+
+CFLAGS=-FVp
--- /dev/null
+++ b/sys/src/cmd/audio/wavdec/wavdec.c
@@ -1,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);
+}
--