summaryrefslogtreecommitdiff
path: root/sys/src/cmd/audio
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2012-12-08 08:26:50 +0100
committercinap_lenrek <cinap_lenrek@gmx.de>2012-12-08 08:26:50 +0100
commit0d84343fbc134763de86dc3d39af078eb183c86f (patch)
treebcded769d74fcc167992ca7cc2449b1bec76d089 /sys/src/cmd/audio
parent950706198644c4715efbc95ec79857fd4fa55353 (diff)
audio: add audio/pcmconv program
instead of duplicating resampling and pcm format conversion code, put it in the new pcmconv program.
Diffstat (limited to 'sys/src/cmd/audio')
-rw-r--r--sys/src/cmd/audio/flacdec/flacdec.c170
-rw-r--r--sys/src/cmd/audio/libFLAC/FLAC/stream_decoder.h2
-rw-r--r--sys/src/cmd/audio/mkfile2
-rw-r--r--sys/src/cmd/audio/mp3dec/main.c142
-rw-r--r--sys/src/cmd/audio/oggdec/mkfile2
-rw-r--r--sys/src/cmd/audio/oggdec/oggdec.c121
-rw-r--r--sys/src/cmd/audio/pcmconv/mkfile8
-rw-r--r--sys/src/cmd/audio/pcmconv/pcmconv.c328
-rw-r--r--sys/src/cmd/audio/wavdec/mkfile2
-rw-r--r--sys/src/cmd/audio/wavdec/wavdec.c148
10 files changed, 534 insertions, 391 deletions
diff --git a/sys/src/cmd/audio/flacdec/flacdec.c b/sys/src/cmd/audio/flacdec/flacdec.c
index 038e5ef48..c29cc7421 100644
--- a/sys/src/cmd/audio/flacdec/flacdec.c
+++ b/sys/src/cmd/audio/flacdec/flacdec.c
@@ -1,92 +1,8 @@
#include <stdio.h>
+#include <unistd.h>
#include <stdlib.h>
#include "FLAC/stream_decoder.h"
-int rate = 44100;
-
-typedef unsigned long ulong;
-typedef unsigned char uchar;
-typedef long long vlong;
-
-typedef struct Chan Chan;
-struct Chan
-{
- ulong phase;
- FLAC__int32 last;
- FLAC__int32 rand;
-};
-
-enum
-{
- OutBits = 16,
- Max = 32767,
- Min = -32768,
-};
-
-#define PRNG(x) (((x)*0x19660dL + 0x3c6ef35fL) & 0xffffffffL)
-
-static uchar*
-resample(Chan *c, FLAC__int32 *src, uchar *dst, int mono, ulong delta, ulong count, ulong bps)
-{
- FLAC__int32 last, val, out, rand;
- ulong phase, pos, scale, lowmask, lowmask2;
- vlong v;
-
- scale = 0;
- if(bps > OutBits){
- scale = bps - OutBits;
- lowmask = (1<<scale)-1;
- lowmask2 = lowmask/2;
- }
-
- rand = c->rand;
- 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);
-
- /* scale / dithering */
- if(scale){
- out += (rand & lowmask) - lowmask2;
- rand = PRNG(rand);
- out >>= scale;
- }
-
- /* cliping */
- if(out > Max)
- out = Max;
- else if(out < Min)
- out = Min;
-
- *dst++ = out;
- *dst++ = out >> 8;
- if(mono){
- *dst++ = out;
- *dst++ = out >> 8;
- } else
- dst += 2;
- phase += delta;
- pos = phase >> 16;
- }
- c->rand = rand;
- c->last = val;
- if(delta < 0x10000)
- c->phase = phase & 0xFFFF;
- else
- c->phase = phase - (count << 16);
-
- return dst;
-}
-
static FLAC__StreamDecoderReadStatus
decinput(FLAC__StreamDecoder *dec, FLAC__byte buffer[], unsigned *bytes, void *client_data)
{
@@ -105,24 +21,80 @@ decinput(FLAC__StreamDecoder *dec, FLAC__byte buffer[], unsigned *bytes, void *c
static FLAC__StreamDecoderWriteStatus
decoutput(FLAC__StreamDecoder *dec, FLAC__Frame *frame, FLAC__int32 *buffer[], void *client_data)
{
- static uchar *buf;
- static int nbuf;
- static Chan c1, c0;
- ulong length, n, delta, bps;
- uchar *p;
-
- bps = frame->header.bits_per_sample;
- length = frame->header.blocksize;
- delta = (frame->header.sample_rate << 16) / rate;
- n = 4 * (frame->header.sample_rate + length * rate) / frame->header.sample_rate;
+ static int rate, chans, bits;
+ static unsigned char *buf;
+ static int nbuf, ifd = -1;
+ FLAC__int32 *s, v;
+ unsigned char *p;
+ int i, j, n, b, len;
+
+ /* start converter if format changed */
+ if(rate != frame->header.sample_rate
+ || chans != frame->header.channels
+ || bits != frame->header.bits_per_sample){
+ int pid, pfd[2];
+ char fmt[32];
+
+ rate = frame->header.sample_rate;
+ chans = frame->header.channels;
+ bits = frame->header.bits_per_sample;
+ sprintf(fmt, "s%dr%dc%d", bits, rate, chans);
+
+ if(ifd >= 0)
+ close(ifd);
+ if(pipe(pfd) < 0){
+ fprintf(stderr, "Error creating pipe\n");
+ exit(1);
+ }
+ pid = fork();
+ if(pid < 0){
+ fprintf(stderr, "Error forking\n");
+ exit(1);
+ }
+ if(pid == 0){
+ dup2(pfd[1], 0);
+ close(pfd[1]);
+ close(pfd[0]);
+ execl("/bin/audio/pcmconv", "pcmconv", "-i", fmt, 0);
+ fprintf(stderr, "Error executing converter\n");
+ exit(1);
+ }
+ close(pfd[1]);
+ ifd = pfd[0];
+ }
+ len = frame->header.blocksize;
+ b = (bits+7)/8;
+ n = b * chans * len;
if(n > nbuf){
nbuf = n;
buf = realloc(buf, nbuf);
+ if(buf == NULL){
+ fprintf(stderr, "Error allocating memory\n");
+ exit(1);
+ }
+ }
+ p = buf;
+ for(j=0; j < chans; j++){
+ s = buffer[j];
+ p = buf + j*b;
+ for(i=0; i < len; i++){
+ n = 0;
+ v = *s++;
+ switch(b){
+ case 4:
+ p[n++] = v, v>>=8;
+ case 3:
+ p[n++] = v, v>>=8;
+ case 2:
+ p[n++] = v, v>>=8;
+ case 1:
+ p[n] = v;
+ }
+ p += chans*b;
+ }
}
- if(frame->header.channels == 2)
- resample(&c1, buffer[1], buf+2, 0, delta, length, bps);
- p = resample(&c0, buffer[0], buf, frame->header.channels == 1, delta, length, bps);
- fwrite(buf, p-buf, 1, stdout);
+ if(p > buf)
+ write(ifd, buf, p - buf);
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
diff --git a/sys/src/cmd/audio/libFLAC/FLAC/stream_decoder.h b/sys/src/cmd/audio/libFLAC/FLAC/stream_decoder.h
index 9c2c36703..9c151b962 100644
--- a/sys/src/cmd/audio/libFLAC/FLAC/stream_decoder.h
+++ b/sys/src/cmd/audio/libFLAC/FLAC/stream_decoder.h
@@ -396,7 +396,7 @@ typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *deco
* \retval FLAC__StreamDecoder*
* \c NULL if there was an error allocating memory, else the new instance.
*/
-FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new();
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void);
/** Free a decoder instance. Deletes the object pointed to by \a decoder.
*
diff --git a/sys/src/cmd/audio/mkfile b/sys/src/cmd/audio/mkfile
index 20a7c9663..b85ff65c2 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 wavdec
+PROGS=pcmconv oggdec oggenc mp3dec mp3enc flacdec wavdec
#libs must be made first
DIRS=$LIBS $PROGS
diff --git a/sys/src/cmd/audio/mp3dec/main.c b/sys/src/cmd/audio/mp3dec/main.c
index 10d2102b8..4c6bc89ec 100644
--- a/sys/src/cmd/audio/mp3dec/main.c
+++ b/sys/src/cmd/audio/mp3dec/main.c
@@ -7,14 +7,14 @@
/* Current input file */
vlong offset;
-int rate = 44100;
int debug = 0;
+int ifd = -1;
static enum mad_flow
input(void *, struct mad_stream *stream)
{
- int fd, n, m;
static uchar buf[32768];
+ int fd, n, m;
n = stream->bufend - stream->next_frame;
memmove(buf, stream->next_frame, n);
@@ -29,99 +29,67 @@ input(void *, struct mad_stream *stream)
return MAD_FLOW_CONTINUE;
}
-typedef struct Chan Chan;
-struct Chan
-{
- ulong phase;
- mad_fixed_t last;
- mad_fixed_t rand;
-};
-
-#define PRNG(x) (((x)*0x19660dL + 0x3c6ef35fL) & 0xffffffffL)
-
-enum
-{
- FracBits = MAD_F_FRACBITS,
- OutBits = 16,
- ScaleBits = FracBits + 1 - OutBits,
- LowMask = (1<<ScaleBits) - 1,
- Min = -MAD_F_ONE,
- Max = MAD_F_ONE - 1,
-};
-
-static uchar*
-resample(Chan *c, mad_fixed_t *src, uchar *dst, int mono, ulong delta, ulong count)
-{
- mad_fixed_t last, val, out, rand;
- ulong phase, pos;
- vlong v;
-
- rand = c->rand;
- 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);
-
- /* dithering */
- out += (rand & LowMask) - LowMask/2;
- rand = PRNG(rand);
-
- /* cliping */
- if(out > Max)
- out = Max;
- else if(out < Min)
- out = Min;
-
- out >>= ScaleBits;
-
- *dst++ = out;
- *dst++ = out >> 8;
- if(mono){
- *dst++ = out;
- *dst++ = out >> 8;
- } else
- dst += 2;
- phase += delta;
- pos = phase >> 16;
- }
- c->rand = rand;
- c->last = val;
- if(delta < 0x10000)
- c->phase = phase & 0xFFFF;
- else
- c->phase = phase - (count << 16);
-
- return dst;
-}
-
static enum mad_flow
output(void *, struct mad_header const* header, struct mad_pcm *pcm)
{
+ static int rate, chans;
static uchar *buf;
static int nbuf;
- static Chan c1, c0;
- ulong n, delta;
+ mad_fixed_t v, *s;
+ int i, j, n;
uchar *p;
- delta = (pcm->samplerate << 16) / rate;
- n = 4 * (pcm->samplerate + pcm->length * rate) / pcm->samplerate;
+ /* start converter if format changed */
+ if(rate != pcm->samplerate || chans != pcm->channels){
+ int pid, pfd[2];
+ char fmt[32];
+
+ rate = pcm->samplerate;
+ chans = pcm->channels;
+ snprint(fmt, sizeof(fmt), "s32r%dc%d", rate, chans);
+
+ if(ifd >= 0){
+ close(ifd);
+ waitpid();
+ }
+ if(pipe(pfd) < 0)
+ sysfatal("pipe: %r");
+ pid = fork();
+ if(pid < 0)
+ sysfatal("fork: %r");
+ 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]);
+ ifd = pfd[0];
+ }
+ n = 4 * chans * pcm->length;
if(n > nbuf){
nbuf = n;
buf = realloc(buf, nbuf);
+ if(buf == nil)
+ sysfatal("realloc: %r");
+ }
+ p = buf;
+ for(j=0; j < chans; j++){
+ s = pcm->samples[j];
+ n = pcm->length;
+ p = buf + j*4;
+ for(i=0; i < n; i++){
+ v = *s++;
+ p[0] = v, v>>=8;
+ p[1] = v, v>>=8;
+ p[2] = v, v>>=8;
+ p[3] = v;
+ p += chans*4;
+ }
}
- if(pcm->channels == 2)
- resample(&c1, pcm->samples[1], buf+2, 0, delta, pcm->length);
- p = resample(&c0, pcm->samples[0], buf, pcm->channels == 1, delta, pcm->length);
- write(1, buf, p-buf);
+ if(p > buf)
+ write(ifd, buf, p - buf);
return MAD_FLOW_CONTINUE;
}
@@ -175,5 +143,11 @@ main(int argc, char **argv)
mad_decoder_init(&decoder, nil, input, nil, nil, output, error, nil);
mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
mad_decoder_finish(&decoder);
+
+ if(ifd >= 0){
+ close(ifd);
+ waitpid();
+ }
+
exits(0);
}
diff --git a/sys/src/cmd/audio/oggdec/mkfile b/sys/src/cmd/audio/oggdec/mkfile
index 77a042856..04c36366d 100644
--- a/sys/src/cmd/audio/oggdec/mkfile
+++ b/sys/src/cmd/audio/oggdec/mkfile
@@ -4,7 +4,7 @@
TARGET=oggdec
CC=pcc
-CFLAGS=-I../libvorbis -I../libogg
+CFLAGS=-I../libvorbis -I../libogg -D_POSIX_SOURCE
%.$O: %.c
$CC $CFLAGS -c $stem.c
diff --git a/sys/src/cmd/audio/oggdec/oggdec.c b/sys/src/cmd/audio/oggdec/oggdec.c
index 35a213279..300433bf8 100644
--- a/sys/src/cmd/audio/oggdec/oggdec.c
+++ b/sys/src/cmd/audio/oggdec/oggdec.c
@@ -22,85 +22,72 @@
/* Note that this is POSIX, not ANSI code */
#include <stdio.h>
+#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <vorbis/codec.h>
-int rate = 44100;
-
-enum {
- Max = 32767,
- Min = -32768,
-};
-
-typedef unsigned long ulong;
-typedef unsigned char uchar;
-typedef struct Chan Chan;
-
-struct Chan
-{
- unsigned long phase;
- float last;
-};
-
-static uchar*
-resample(Chan *c, float *src, uchar *dst, int mono, ulong delta, ulong count)
-{
- float f, last, val;
- ulong phase, pos;
- int out;
-
- last = c->last;
- phase = c->phase;
- pos = phase >> 16;
- while(pos < count){
- val = src[pos];
- if(pos)
- last = src[pos-1];
- f = (float)(phase&0xFFFF)/0x10000;
- out = (last + (val - last) * f) * 32767.f;
- /* cliping */
- if(out > Max)
- out = Max;
- else if(out < Min)
- out = Min;
- *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;
-}
-
static void
output(float **pcm, int samples, vorbis_info *vi)
{
- static uchar *buf;
- static int nbuf;
- static Chan c1, c0;
- ulong n, delta;
- uchar *p;
+ static int rate, chans;
+ static unsigned char *buf;
+ static int nbuf, ifd = -1;
+ unsigned char *p;
+ int i, j, n, v;
+ float *s;
+
+ /* start converter if format changed */
+ if(rate != vi->rate || chans != vi->channels){
+ int pid, pfd[2];
+ char fmt[32];
- delta = ((ulong)vi->rate << 16) / rate;
- n = 4 * ((ulong)vi->rate + samples * rate) / (ulong)vi->rate;
+ rate = vi->rate;
+ chans = vi->channels;
+ sprintf(fmt, "f%dr%dc%d", sizeof(float)*8, rate, chans);
+
+ if(ifd >= 0)
+ close(ifd);
+ if(pipe(pfd) < 0){
+ fprintf(stderr, "Error creating pipe\n");
+ exit(1);
+ }
+ pid = fork();
+ if(pid < 0){
+ fprintf(stderr, "Error forking\n");
+ exit(1);
+ }
+ if(pid == 0){
+ dup2(pfd[1], 0);
+ close(pfd[1]);
+ close(pfd[0]);
+ execl("/bin/audio/pcmconv", "pcmconv", "-i", fmt, 0);
+ fprintf(stderr, "Error executing converter\n");
+ exit(1);
+ }
+ close(pfd[1]);
+ ifd = pfd[0];
+ }
+ n = sizeof(float) * chans * samples;
if(n > nbuf){
nbuf = n;
buf = realloc(buf, nbuf);
+ if(buf == NULL){
+ fprintf(stderr, "Error allocating memory\n");
+ exit(1);
+ }
+ }
+ p = buf;
+ for(j=0; j < chans; j++){
+ s = pcm[j];
+ p = buf + j*sizeof(float);
+ for(i=0; i < samples; i++){
+ *((float*)p) = *s++;
+ p += chans*sizeof(float);
+ }
}
- if(vi->channels == 2)
- resample(&c1, pcm[1], buf+2, 0, delta, samples);
- p = resample(&c0, pcm[0], buf, vi->channels == 1, delta, samples);
- fwrite(buf, p-buf, 1, stdout);
+ if(p > buf)
+ write(ifd, buf, p - buf);
}
int main(){
diff --git a/sys/src/cmd/audio/pcmconv/mkfile b/sys/src/cmd/audio/pcmconv/mkfile
new file mode 100644
index 000000000..96eddfe69
--- /dev/null
+++ b/sys/src/cmd/audio/pcmconv/mkfile
@@ -0,0 +1,8 @@
+</$objtype/mkfile
+<../config
+
+OFILES=pcmconv.$O
+
+TARG=pcmconv
+
+</sys/src/cmd/mkone
diff --git a/sys/src/cmd/audio/pcmconv/pcmconv.c b/sys/src/cmd/audio/pcmconv/pcmconv.c
new file mode 100644
index 000000000..7ae6fb7b0
--- /dev/null
+++ b/sys/src/cmd/audio/pcmconv/pcmconv.c
@@ -0,0 +1,328 @@
+#include <u.h>
+#include <libc.h>
+
+typedef struct Desc Desc;
+typedef struct Chan Chan;
+
+struct Desc
+{
+ int rate;
+ int channels;
+ int framesz;
+ int bits;
+ int fmt;
+};
+
+struct Chan
+{
+ ulong phase;
+ int last;
+};
+
+int*
+resample(Chan *c, int *src, int *dst, ulong delta, ulong count)
+{
+ int last, val;
+ ulong phase, pos;
+ vlong v;
+
+ if(delta == 0x10000){
+ /* same frequency */
+ memmove(dst, src, count*sizeof(int));
+ return dst + count;
+ }
+
+ val = 0;
+ 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);
+ v >>= 16;
+ v += last;
+
+ /* clipping */
+ if(v > 0x7fffffffLL)
+ v = 0x7fffffff;
+ else if(v < -0x80000000LL)
+ v = -0x80000000;
+
+ *dst++ = v;
+
+ phase += delta;
+ pos = phase >> 16;
+ }
+ c->last = val;
+ if(delta < 0x10000)
+ c->phase = phase & 0xFFFF;
+ else
+ c->phase = phase - (count << 16);
+ return dst;
+}
+
+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 = b;
+ 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;
+ uint v;
+
+ b = (bits+7)/8;
+ s = sizeof(uint)*8-bits;
+ while(count--){
+ v = 0;
+ i = b;
+ 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)
+{
+ while(count--){
+ if(bits == 32)
+ *dst++ = *((float*)src) * 2147483647.f;
+ else
+ *dst++ = *((double*)src) * 2147483647.f;
+ src += skip;
+ }
+}
+
+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 = 0;
+ 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;
+ uint v;
+
+ b = (bits+7)/8;
+ s = sizeof(uint)*8-bits;
+ while(count--){
+ v = ((~0UL>>1) + *src++) >> s;
+ i = 0;
+ 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)
+{
+ while(count--){
+ if(bits == 32)
+ *((float*)dst) = *src++ / 2147483647.f;
+ else
+ *((double*)dst) = *src++ / 2147483647.f;
+ dst += skip;
+ }
+}
+
+Desc
+mkdesc(char *f)
+{
+ Desc d;
+ int c;
+ char *p;
+
+ memset(&d, 0, sizeof(d));
+ p = f;
+ while(c = *p++){
+ switch(c){
+ case 'r':
+ d.rate = strtol(p, &p, 10);
+ break;
+ case 'c':
+ d.channels = strtol(p, &p, 10);
+ break;
+ case 's':
+ case 'u':
+ case 'f':
+ d.fmt = c;
+ d.bits = strtol(p, &p, 10);
+ break;
+ default:
+ goto Bad;
+ }
+ }
+ if(d.rate <= 0)
+ goto Bad;
+ if(d.fmt == 'f'){
+ if(d.bits != 32 && d.bits != 64)
+ goto Bad;
+ } else if(d.bits <= 0 || d.bits > 32)
+ goto Bad;
+ d.framesz = ((d.bits+7)/8) * d.channels;
+ if(d.framesz <= 0)
+ goto Bad;
+ return d;
+Bad:
+ sysfatal("bad format: %s", f);
+ return d;
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [-i fmt] [-o fmt] [-l length]\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ uchar ibuf[8*1024], *obuf;
+ int *out, *in;
+ Chan ch[8];
+ Desc i, o;
+ ulong delta;
+ int k, r, n, m, p;
+ vlong l;
+
+ void (*oconv)(int *, uchar *, int, int, int) = nil;
+ void (*iconv)(int *, uchar *, int, int, int) = nil;
+
+ o = mkdesc("s16c2r44100");
+ i = o;
+ l = -1LL;
+ ARGBEGIN {
+ case 'i':
+ i = mkdesc(EARGF(usage()));
+ break;
+ case 'o':
+ o = mkdesc(EARGF(usage()));
+ break;
+ case 'l':
+ l = atoll(EARGF(usage()));
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ switch(i.fmt){
+ case 's': iconv = siconv; break;
+ case 'u': iconv = uiconv; break;
+ case 'f': iconv = ficonv; break;
+ }
+
+ switch(o.fmt){
+ case 's': oconv = soconv; break;
+ case 'u': oconv = uoconv; break;
+ case 'f': oconv = foconv; break;
+ }
+
+ delta = ((uvlong)i.rate << 16) / o.rate;
+ memset(ch, 0, sizeof(ch));
+ n = (sizeof(ibuf)-i.framesz)/i.framesz;
+ r = n*i.framesz;
+ m = (i.rate + n*o.rate)/i.rate;
+ in = sbrk(sizeof(int) * n);
+ out = sbrk(sizeof(int) * m);
+ obuf = sbrk(o.framesz * m);
+ if(in == nil || out == nil || obuf == nil)
+ sysfatal("out of memory");
+
+ for(;;){
+ if(l >= 0 && l < r)
+ r = l;
+ n = read(0, ibuf, r);
+ if(n < 0)
+ sysfatal("read: %r");
+ if(n == 0)
+ break;
+ if(l > 0)
+ l -= n;
+ n /= i.framesz;
+ (*iconv)(in, ibuf, i.bits, i.framesz, n);
+ m = resample(&ch[0], in, out, delta, n) - out;
+ if(m < 1)
+ continue;
+ (*oconv)(out, obuf, o.bits, o.framesz, m);
+ 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);
+ resample(&ch[k], in, out, delta, n);
+ (*oconv)(out, obuf + k*((o.bits+7)/8), o.bits, o.framesz, m);
+ }
+ } else {
+ for(k=1; k<o.channels; k++)
+ (*oconv)(out, obuf + k*((o.bits+7)/8), o.bits, o.framesz, m);
+ }
+ m *= o.framesz;
+ write(1, obuf, m);
+ }
+ exits(0);
+}
diff --git a/sys/src/cmd/audio/wavdec/mkfile b/sys/src/cmd/audio/wavdec/mkfile
index 658c8bf80..702f7d9fa 100644
--- a/sys/src/cmd/audio/wavdec/mkfile
+++ b/sys/src/cmd/audio/wavdec/mkfile
@@ -6,5 +6,3 @@ 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
index 5189a60f6..77a7e3e26 100644
--- a/sys/src/cmd/audio/wavdec/wavdec.c
+++ b/sys/src/cmd/audio/wavdec/wavdec.c
@@ -1,18 +1,7 @@
#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;
@@ -42,106 +31,22 @@ get4(void)
return buf[0] | buf[1]<<8 | buf[2]<<16 | buf[3]<<24;
}
-uchar*
-getcc(uchar tag[4])
+char*
+getcc(char 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)
+main(int, char *argv[])
{
- 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;
+ char buf[8*1024], fmt[32];
+ ulong len, n;
Wave wav;
- ulong delta, len;
- int n, z;
-
- ARGBEGIN {
- case 'd':
- debug++;
- break;
- default:
- usage();
- } ARGEND;
+ argv0 = argv[0];
if(memcmp(getcc(buf), "RIFF", 4) != 0)
sysfatal("no riff format");
get4();
@@ -177,39 +82,10 @@ main(int argc, char *argv[])
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);
+ snprint(fmt, sizeof(fmt), "%c%dr%dc%d",
+ wav.bits == 8 ? 'u' : 's', wav.bits,
+ wav.rate,
+ wav.channels);
+ snprint(buf, sizeof(buf), "%lud", len);
+ execl("/bin/audio/pcmconv", "pcmconv", "-i", fmt, "-l", buf, 0);
}