diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2012-12-08 08:26:50 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2012-12-08 08:26:50 +0100 |
commit | 0d84343fbc134763de86dc3d39af078eb183c86f (patch) | |
tree | bcded769d74fcc167992ca7cc2449b1bec76d089 /sys/src/cmd/audio | |
parent | 950706198644c4715efbc95ec79857fd4fa55353 (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.c | 170 | ||||
-rw-r--r-- | sys/src/cmd/audio/libFLAC/FLAC/stream_decoder.h | 2 | ||||
-rw-r--r-- | sys/src/cmd/audio/mkfile | 2 | ||||
-rw-r--r-- | sys/src/cmd/audio/mp3dec/main.c | 142 | ||||
-rw-r--r-- | sys/src/cmd/audio/oggdec/mkfile | 2 | ||||
-rw-r--r-- | sys/src/cmd/audio/oggdec/oggdec.c | 121 | ||||
-rw-r--r-- | sys/src/cmd/audio/pcmconv/mkfile | 8 | ||||
-rw-r--r-- | sys/src/cmd/audio/pcmconv/pcmconv.c | 328 | ||||
-rw-r--r-- | sys/src/cmd/audio/wavdec/mkfile | 2 | ||||
-rw-r--r-- | sys/src/cmd/audio/wavdec/wavdec.c | 148 |
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); } |