wave pcm support

This commit is contained in:
cinap_lenrek 2012-03-08 07:25:14 +01:00
parent f0facb2ed8
commit 388cd56d69
5 changed files with 235 additions and 5 deletions

View file

@ -47,6 +47,8 @@ fn play1 {
audio/oggdec
case *mp3* *mpeg*
audio/mp3dec
case *wave*
audio/wavdec
case *flac*
audio/flacdec
case *pls*

View file

@ -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.

View file

@ -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

View file

@ -0,0 +1,10 @@
</$objtype/mkfile
<../config
OFILES=wavdec.$O
TARG=wavdec
</sys/src/cmd/mkone
CFLAGS=-FVp

View file

@ -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);
}