wave pcm support
This commit is contained in:
parent
f0facb2ed8
commit
388cd56d69
5 changed files with 235 additions and 5 deletions
|
@ -47,6 +47,8 @@ fn play1 {
|
|||
audio/oggdec
|
||||
case *mp3* *mpeg*
|
||||
audio/mp3dec
|
||||
case *wave*
|
||||
audio/wavdec
|
||||
case *flac*
|
||||
audio/flacdec
|
||||
case *pls*
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
10
sys/src/cmd/audio/wavdec/mkfile
Normal file
10
sys/src/cmd/audio/wavdec/mkfile
Normal file
|
@ -0,0 +1,10 @@
|
|||
</$objtype/mkfile
|
||||
<../config
|
||||
|
||||
OFILES=wavdec.$O
|
||||
|
||||
TARG=wavdec
|
||||
|
||||
</sys/src/cmd/mkone
|
||||
|
||||
CFLAGS=-FVp
|
215
sys/src/cmd/audio/wavdec/wavdec.c
Normal file
215
sys/src/cmd/audio/wavdec/wavdec.c
Normal 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);
|
||||
}
|
Loading…
Reference in a new issue