mirror of
git://git.9front.org/plan9front/plan9front
synced 2025-01-12 11:10:06 +00:00
libpcm: audio/pcmconv-as-a-library
This commit is contained in:
parent
4834c3c19f
commit
0d84321e65
6 changed files with 982 additions and 0 deletions
27
sys/include/pcm.h
Normal file
27
sys/include/pcm.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma lib "libpcm.a"
|
||||
#pragma src "/sys/src/libpcm"
|
||||
|
||||
typedef struct Pcmconv Pcmconv;
|
||||
typedef struct Pcmdesc Pcmdesc;
|
||||
|
||||
#pragma incomplete Pcmconv
|
||||
|
||||
struct Pcmdesc
|
||||
{
|
||||
int rate;
|
||||
int channels;
|
||||
int framesz;
|
||||
int abits; /* bits after input conversion */
|
||||
int bits; /* bits in input stream per sample */
|
||||
Rune fmt;
|
||||
};
|
||||
|
||||
extern Pcmdesc pcmdescdef; /* s16c2r44100 */
|
||||
|
||||
int pcmdescfmt(Fmt*);
|
||||
int mkpcmdesc(char *f, Pcmdesc *d);
|
||||
|
||||
Pcmconv *allocpcmconv(Pcmdesc *in, Pcmdesc *out);
|
||||
void freepcmconv(Pcmconv *c);
|
||||
int pcmconv(Pcmconv *c, void *in0, void *out0, int insz);
|
||||
int pcmratio(Pcmconv *c, int insz);
|
729
sys/src/libpcm/conv.c
Normal file
729
sys/src/libpcm/conv.c
Normal file
|
@ -0,0 +1,729 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <pcm.h>
|
||||
|
||||
typedef struct Chan Chan;
|
||||
typedef struct Pcmconv Pcmconv;
|
||||
|
||||
struct Chan
|
||||
{
|
||||
ulong ρ; /* factor */
|
||||
|
||||
ulong t; /* time */
|
||||
|
||||
ulong tΔ; /* output step */
|
||||
ulong lΔ; /* filter step */
|
||||
ulong le; /* filter end */
|
||||
|
||||
int u; /* unity scale */
|
||||
int *h; /* filter coefficients */
|
||||
int *hΔ; /* coefficient deltas for interpolation */
|
||||
|
||||
int wx; /* extra samples */
|
||||
int ix; /* buffer index */
|
||||
int nx; /* buffer size */
|
||||
int *x; /* the buffer */
|
||||
};
|
||||
|
||||
struct Pcmconv
|
||||
{
|
||||
Pcmdesc idesc;
|
||||
Pcmdesc odesc;
|
||||
void (*iconv)(int *, uchar *, int, int, int);
|
||||
void (*oconv)(int *, uchar *, int, int, int);
|
||||
int *in;
|
||||
int *out;
|
||||
uchar *buf;
|
||||
int nbuf;
|
||||
ulong prnd;
|
||||
int flags;
|
||||
Chan ch[];
|
||||
};
|
||||
|
||||
enum {
|
||||
Nl = 8, /* 2^Nl samples per zero crossing in fir */
|
||||
Nη = 8, /* phase bits for filter interpolation */
|
||||
Np = Nl+Nη, /* phase bits (fract of fixed point) */
|
||||
One = 1<<Np,
|
||||
Fcopy = 1<<0,
|
||||
Nin = 2048,
|
||||
};
|
||||
|
||||
#define MAXINT ((int)(~0UL>>1))
|
||||
#define MININT (MAXINT+1)
|
||||
|
||||
#define clip(v) ((v) > MAXINT ? MAXINT : ((v) < MININT ? MININT : (v)))
|
||||
|
||||
static int
|
||||
chaninit(Chan *c, int irate, int orate, int count, uintptr caller)
|
||||
{
|
||||
static int h[] = {
|
||||
#include "fir.h"
|
||||
};
|
||||
static int hΔ[nelem(h)], init = 0;
|
||||
int n;
|
||||
|
||||
c->ρ = ((uvlong)orate<<Np)/irate;
|
||||
if(c->ρ == One)
|
||||
goto Done;
|
||||
|
||||
c->tΔ = ((uvlong)irate<<Np)/orate;
|
||||
c->lΔ = 1<<(Nl+Nη);
|
||||
c->le = nelem(h)<<Nη;
|
||||
c->wx = 1 + (c->le / c->lΔ);
|
||||
c->u = 13128; /* unity scale factor for fir */
|
||||
if(c->ρ < One){
|
||||
c->u *= c->ρ;
|
||||
c->u >>= Np;
|
||||
c->lΔ *= c->ρ;
|
||||
c->lΔ >>= Np;
|
||||
c->wx *= c->tΔ;
|
||||
c->wx >>= Np;
|
||||
}
|
||||
if(!init){
|
||||
for(n=0; n<nelem(hΔ)-1; n++)
|
||||
hΔ[n] = h[n+1] - h[n];
|
||||
init = 1;
|
||||
}
|
||||
c->h = h;
|
||||
c->hΔ = hΔ;
|
||||
c->ix = c->wx;
|
||||
c->t = c->ix<<Np;
|
||||
c->nx = c->wx*2 + count;
|
||||
c->x = mallocz(sizeof(c->x[0]) * c->nx, 1);
|
||||
if(c->x == nil){
|
||||
werrstr("memory");
|
||||
return -1;
|
||||
}
|
||||
setmalloctag(c->x, caller);
|
||||
count += c->nx; /* account for buffer accumulation */
|
||||
Done:
|
||||
return ((uvlong)count * c->ρ) >> Np;
|
||||
}
|
||||
|
||||
static int
|
||||
filter(Chan *c)
|
||||
{
|
||||
ulong l, lΔ, le, p, i;
|
||||
int *x, *h, *hΔ, a;
|
||||
vlong v;
|
||||
|
||||
v = 0;
|
||||
|
||||
h = c->h;
|
||||
hΔ = c->hΔ;
|
||||
lΔ = c->lΔ;
|
||||
le = c->le;
|
||||
|
||||
/* left side */
|
||||
x = &c->x[c->t>>Np];
|
||||
p = c->t & ((1<<Np)-1);
|
||||
l = c->ρ < One ? (c->ρ * p)>>Np : p;
|
||||
while(l < le){
|
||||
i = l >> Nη;
|
||||
a = l & ((1<<Nη)-1);
|
||||
l += lΔ;
|
||||
a *= hΔ[i];
|
||||
a >>= Nη;
|
||||
a += h[i];
|
||||
v += (vlong)*(--x) * a;
|
||||
}
|
||||
|
||||
/* right side */
|
||||
x = &c->x[c->t>>Np];
|
||||
p = (One - p) & ((1<<Np)-1);
|
||||
l = c->ρ < One ? (c->ρ * p)>>Np : p;
|
||||
if(p == 0) /* skip h[0] as it was already been summed above if p == 0 */
|
||||
l += c->lΔ;
|
||||
while(l < le){
|
||||
i = l >> Nη;
|
||||
a = l & ((1<<Nη)-1);
|
||||
l += lΔ;
|
||||
a *= hΔ[i];
|
||||
a >>= Nη;
|
||||
a += h[i];
|
||||
v += (vlong)*x++ * a;
|
||||
}
|
||||
|
||||
/* scale */
|
||||
v >>= 2;
|
||||
v *= c->u;
|
||||
v >>= 27;
|
||||
|
||||
return clip(v);
|
||||
}
|
||||
|
||||
static int*
|
||||
resample(Chan *c, int *x, int *y, int count)
|
||||
{
|
||||
ulong e;
|
||||
int i, n;
|
||||
|
||||
if(c->ρ == One){
|
||||
/* no rate conversion needed */
|
||||
if(count > 0)
|
||||
memmove(y, x, count*sizeof(int));
|
||||
return y+count;
|
||||
}
|
||||
|
||||
if(count == 0){
|
||||
/* stuff zeros to drain last samples out */
|
||||
while(c->ix < 2*c->wx)
|
||||
c->x[c->ix++] = 0;
|
||||
}
|
||||
|
||||
do {
|
||||
/* fill buffer */
|
||||
for(i = c->ix, n = c->nx; count > 0 && i < n; count--, i++)
|
||||
c->x[i] = *x++;
|
||||
c->ix = i;
|
||||
|
||||
/* need at least 2*wx samples in buffer for filter */
|
||||
if(i < 2*c->wx)
|
||||
break;
|
||||
|
||||
/* process buffer */
|
||||
e = (i - c->wx)<<Np;
|
||||
while(c->t < e){
|
||||
*y++ = filter(c);
|
||||
c->t += c->tΔ;
|
||||
}
|
||||
|
||||
/* check if we'r at the end of buffer and wrap it */
|
||||
e = c->t >> Np;
|
||||
if(e >= (c->nx - c->wx)){
|
||||
c->t -= e << Np;
|
||||
c->t += c->wx << Np;
|
||||
n = c->t >> Np;
|
||||
n -= c->wx;
|
||||
e -= c->wx;
|
||||
i -= e;
|
||||
if(i > 0){
|
||||
memmove(c->x + n, c->x + e, i*sizeof(int));
|
||||
n += i;
|
||||
}
|
||||
c->ix = n;
|
||||
}
|
||||
} while(count > 0);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
static ulong
|
||||
dither(int *y, int ibits, int obits, int count, ulong prnd)
|
||||
{
|
||||
if(ibits >= 32 || obits >= ibits)
|
||||
return prnd;
|
||||
|
||||
while(count--){
|
||||
prnd = (prnd*0x19660dL + 0x3c6ef35fL) & 0xffffffffL;
|
||||
*y = clip((vlong)*y + ((int)prnd >> ibits));
|
||||
y++;
|
||||
}
|
||||
return prnd;
|
||||
}
|
||||
|
||||
static void
|
||||
mixin(int *y, int *x, int count)
|
||||
{
|
||||
while(count--){
|
||||
*y = clip((vlong)*y + *x++);
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
}
|
||||
|
||||
static 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 = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
}
|
||||
|
||||
static 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 = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ficonv(int *dst, uchar *src, int bits, int skip, int count)
|
||||
{
|
||||
if(bits == 32){
|
||||
while(count--){
|
||||
float f;
|
||||
|
||||
f = *((float*)src), src += skip;
|
||||
if(f > 1.0)
|
||||
*dst++ = MAXINT;
|
||||
else if(f < -1.0)
|
||||
*dst++ = MININT;
|
||||
else
|
||||
*dst++ = f*((float)MAXINT);
|
||||
}
|
||||
} else {
|
||||
while(count--){
|
||||
double d;
|
||||
|
||||
d = *((double*)src), src += skip;
|
||||
if(d > 1.0)
|
||||
*dst++ = MAXINT;
|
||||
else if(d < -1.0)
|
||||
*dst++ = MININT;
|
||||
else
|
||||
*dst++ = d*((double)MAXINT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
aiconv(int *dst, uchar *src, int, int skip, int count)
|
||||
{
|
||||
int t, seg;
|
||||
uchar a;
|
||||
|
||||
while(count--){
|
||||
a = *src, src += skip;
|
||||
a ^= 0x55;
|
||||
t = (a & 0xf) << 4;
|
||||
seg = (a & 0x70) >> 4;
|
||||
switch(seg){
|
||||
case 0:
|
||||
t += 8;
|
||||
break;
|
||||
case 1:
|
||||
t += 0x108;
|
||||
break;
|
||||
default:
|
||||
t += 0x108;
|
||||
t <<= seg - 1;
|
||||
}
|
||||
t = (a & 0x80) ? t : -t;
|
||||
*dst++ = t << (sizeof(int)*8 - 16);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
µiconv(int *dst, uchar *src, int, int skip, int count)
|
||||
{
|
||||
int t;
|
||||
uchar u;
|
||||
|
||||
while(count--){
|
||||
u = *src, src += skip;
|
||||
u = ~u;
|
||||
t = ((u & 0xf) << 3) + 0x84;
|
||||
t <<= (u & 0x70) >> 4;
|
||||
t = u & 0x80 ? 0x84 - t: t - 0x84;
|
||||
*dst++ = t << (sizeof(int)*8 - 16);
|
||||
}
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
}
|
||||
|
||||
static 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 = b;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
}
|
||||
|
||||
static 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 = b;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
foconv(int *src, uchar *dst, int bits, int skip, int count)
|
||||
{
|
||||
if(bits == 32){
|
||||
while(count--){
|
||||
*((float*)dst) = *src++ / ((float)MAXINT);
|
||||
dst += skip;
|
||||
}
|
||||
} else {
|
||||
while(count--){
|
||||
*((double*)dst) = *src++ / ((double)MAXINT);
|
||||
dst += skip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pcmconv *
|
||||
allocpcmconv(Pcmdesc *i, Pcmdesc *o)
|
||||
{
|
||||
uintptr caller;
|
||||
Pcmconv *c;
|
||||
int k, nout;
|
||||
|
||||
if(i->channels < 1){
|
||||
werrstr("invalid number of input channels: %d", i->channels);
|
||||
return nil;
|
||||
}
|
||||
if(o->channels < 1){
|
||||
werrstr("invalid number of output channels: %d", o->channels);
|
||||
return nil;
|
||||
}
|
||||
|
||||
caller = getcallerpc(&i);
|
||||
c = mallocz(sizeof(*c) + i->channels*sizeof(Chan) + i->framesz, 1);
|
||||
if(c == nil){
|
||||
Nomem:
|
||||
werrstr("memory");
|
||||
goto Err;
|
||||
}
|
||||
setmalloctag(c, caller);
|
||||
memcpy(&c->idesc, i, sizeof(*i));
|
||||
memcpy(&c->odesc, o, sizeof(*o));
|
||||
c->buf = (uchar*)&c->ch[i->channels+1];
|
||||
|
||||
switch(i->fmt){
|
||||
case L's': c->iconv = siconv; break;
|
||||
case L'S': c->iconv = Siconv; break;
|
||||
case L'u': c->iconv = uiconv; break;
|
||||
case L'U': c->iconv = Uiconv; break;
|
||||
case L'f': c->iconv = ficonv; break;
|
||||
case L'a': c->iconv = aiconv; break;
|
||||
case L'µ': c->iconv = µiconv; break;
|
||||
default:
|
||||
werrstr("unsupported input format: %C", i->fmt);
|
||||
goto Err;
|
||||
}
|
||||
|
||||
switch(o->fmt){
|
||||
case L's': c->oconv = soconv; break;
|
||||
case L'S': c->oconv = Soconv; break;
|
||||
case L'u': c->oconv = uoconv; break;
|
||||
case L'U': c->oconv = Uoconv; break;
|
||||
case L'f': c->oconv = foconv; break;
|
||||
default:
|
||||
werrstr("unsupported output format: %C", o->fmt);
|
||||
goto Err;
|
||||
}
|
||||
|
||||
/* if same format, just copy */
|
||||
c->flags = (
|
||||
i->rate == o->rate
|
||||
&& i->bits == o->bits
|
||||
&& i->channels == o->channels
|
||||
&& i->framesz == o->framesz
|
||||
&& i->fmt == o->fmt
|
||||
) ? Fcopy : 0;
|
||||
|
||||
c->in = malloc(sizeof(int) * Nin);
|
||||
if(c->in == nil)
|
||||
goto Nomem;
|
||||
setmalloctag(c->in, caller);
|
||||
|
||||
nout = 0;
|
||||
for(k=0; k < i->channels; k++){
|
||||
nout = chaninit(&c->ch[k], i->rate, o->rate, Nin, caller);
|
||||
if(nout < 0)
|
||||
goto Err;
|
||||
}
|
||||
|
||||
/* out is also used for mixing before resampling, so needs to be max(Nin, nout) */
|
||||
c->out = malloc(sizeof(int) * (nout > Nin ? nout : Nin));
|
||||
if(c->out == nil)
|
||||
goto Nomem;
|
||||
setmalloctag(c->out, caller);
|
||||
|
||||
return c;
|
||||
Err:
|
||||
freepcmconv(c);
|
||||
return nil;
|
||||
}
|
||||
|
||||
void
|
||||
freepcmconv(Pcmconv *c)
|
||||
{
|
||||
int k;
|
||||
|
||||
if(c == nil)
|
||||
return;
|
||||
free(c->in);
|
||||
free(c->out);
|
||||
for(k=0; k < c->idesc.channels; k++)
|
||||
free(c->ch[k].x);
|
||||
free(c);
|
||||
}
|
||||
|
||||
static int
|
||||
conv(Pcmconv *c, uchar *in, uchar *out0, int insz)
|
||||
{
|
||||
uchar *out;
|
||||
Pcmdesc *i, *o;
|
||||
int k, n, m, nin;
|
||||
|
||||
i = &c->idesc;
|
||||
o = &c->odesc;
|
||||
out = out0;
|
||||
|
||||
nin = insz / i->framesz;
|
||||
for(;;){
|
||||
if((n = nin) > Nin)
|
||||
n = Nin;
|
||||
nin -= n;
|
||||
|
||||
c->iconv(c->in, in, i->bits, i->framesz, n);
|
||||
if(i->channels > o->channels){
|
||||
for(k=1; k<i->channels; k++){
|
||||
c->iconv(c->out, in + k*((i->bits+7)/8), i->bits, i->framesz, n);
|
||||
mixin(c->in, c->out, n);
|
||||
}
|
||||
}
|
||||
c->prnd = dither(c->in, i->abits, o->abits, n, c->prnd);
|
||||
m = resample(&c->ch[0], c->in, c->out, n) - c->out;
|
||||
if(m < 1){
|
||||
if(n == 0)
|
||||
break;
|
||||
} else
|
||||
c->oconv(c->out, out, o->bits, o->framesz, m);
|
||||
if(i->channels == o->channels){
|
||||
for(k=1; k<i->channels; k++){
|
||||
c->iconv(c->in, in + k*((i->bits+7)/8), i->bits, i->framesz, n);
|
||||
c->prnd = dither(c->in, i->abits, o->abits, n, c->prnd);
|
||||
resample(&c->ch[k], c->in, c->out, n);
|
||||
if(m > 0)
|
||||
c->oconv(c->out, out + k*((o->bits+7)/8), o->bits, o->framesz, m);
|
||||
}
|
||||
} else if(m > 0){
|
||||
for(k=1; k<o->channels; k++)
|
||||
c->oconv(c->out, out + k*((o->bits+7)/8), o->bits, o->framesz, m);
|
||||
}
|
||||
if(m > 0)
|
||||
out += m * o->framesz;
|
||||
if(n == 0)
|
||||
break;
|
||||
in += n * i->framesz;
|
||||
}
|
||||
|
||||
return out - (uchar*)out0;
|
||||
}
|
||||
|
||||
int
|
||||
pcmconv(Pcmconv *c, void *in0, void *out0, int insz)
|
||||
{
|
||||
uchar *in, *out;
|
||||
Pcmdesc *i;
|
||||
int n;
|
||||
|
||||
if(c->flags & Fcopy){
|
||||
memmove(out0, in0, insz);
|
||||
return insz;
|
||||
}
|
||||
i = &c->idesc;
|
||||
in = in0;
|
||||
out = out0;
|
||||
if(c->nbuf > 0){
|
||||
n = i->framesz - c->nbuf;
|
||||
if(n > insz)
|
||||
n = insz;
|
||||
memcpy(c->buf+c->nbuf, in, n);
|
||||
c->nbuf += n;
|
||||
in += n;
|
||||
insz -= n;
|
||||
if(c->nbuf < i->framesz)
|
||||
return 0;
|
||||
out += conv(c, c->buf, out, i->framesz);
|
||||
c->nbuf = 0;
|
||||
}
|
||||
|
||||
n = insz % i->framesz;
|
||||
insz -= n;
|
||||
out += conv(c, in, out, insz);
|
||||
if(n > 0){
|
||||
memcpy(c->buf, in+insz, n);
|
||||
c->nbuf += n;
|
||||
}
|
||||
|
||||
return out - (uchar*)out0;
|
||||
}
|
||||
|
||||
int
|
||||
pcmratio(Pcmconv *c, int insz)
|
||||
{
|
||||
int outsz;
|
||||
|
||||
if(insz < c->idesc.framesz)
|
||||
goto Bad;
|
||||
insz /= c->idesc.framesz;
|
||||
outsz = ((uvlong)insz * ((uvlong)c->odesc.rate<<Np)/c->idesc.rate) >> Np;
|
||||
if(outsz > 1)
|
||||
return outsz;
|
||||
Bad:
|
||||
werrstr("invalid buffer size: %d", insz);
|
||||
return -1;
|
||||
}
|
76
sys/src/libpcm/desc.c
Normal file
76
sys/src/libpcm/desc.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <pcm.h>
|
||||
|
||||
Pcmdesc pcmdescdef =
|
||||
{
|
||||
.rate = 44100,
|
||||
.channels = 2,
|
||||
.framesz = 4,
|
||||
.abits = 16,
|
||||
.bits = 16,
|
||||
.fmt = L's',
|
||||
};
|
||||
|
||||
int
|
||||
pcmdescfmt(Fmt *f)
|
||||
{
|
||||
Pcmdesc d;
|
||||
|
||||
d = va_arg(f->args, Pcmdesc);
|
||||
return fmtprint(f, "%C%dc%dr%d", d.fmt, d.bits, d.channels, d.rate);
|
||||
}
|
||||
|
||||
int
|
||||
mkpcmdesc(char *f, Pcmdesc *d)
|
||||
{
|
||||
Rune r;
|
||||
char *p;
|
||||
|
||||
memset(d, 0, sizeof(*d));
|
||||
p = f;
|
||||
while(*p != 0){
|
||||
p += chartorune(&r, p);
|
||||
switch(r){
|
||||
case L'r':
|
||||
d->rate = strtol(p, &p, 10);
|
||||
break;
|
||||
case L'c':
|
||||
d->channels = strtol(p, &p, 10);
|
||||
break;
|
||||
case L'm':
|
||||
r = L'µ';
|
||||
case L's':
|
||||
case L'S':
|
||||
case L'u':
|
||||
case L'U':
|
||||
case L'f':
|
||||
case L'a':
|
||||
case L'µ':
|
||||
d->fmt = r;
|
||||
d->bits = d->abits = strtol(p, &p, 10);
|
||||
break;
|
||||
default:
|
||||
goto Bad;
|
||||
}
|
||||
}
|
||||
if(d->rate <= 0 || d->channels <= 0)
|
||||
goto Bad;
|
||||
if(d->fmt == L'a' || d->fmt == L'µ'){
|
||||
if(d->bits != 8)
|
||||
goto Bad;
|
||||
d->abits = 16;
|
||||
} else if(d->fmt == L'f'){
|
||||
if(d->bits != 32 && d->bits != 64)
|
||||
goto Bad;
|
||||
d->abits = sizeof(int)*8;
|
||||
} 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 0;
|
||||
Bad:
|
||||
werrstr("bad format: %s", f);
|
||||
return -1;
|
||||
}
|
131
sys/src/libpcm/fir.h
Normal file
131
sys/src/libpcm/fir.h
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* FIR filter coefficients from resample-1.x smallfilter.h
|
||||
* see Digital Audio Resampling Home Page located at
|
||||
* http://ccrma.stanford.edu/~jos/resample/
|
||||
*/
|
||||
32767, 32766, 32764, 32760, 32755, 32749, 32741, 32731, 32721, 32708,
|
||||
32695, 32679, 32663, 32645, 32625, 32604, 32582, 32558, 32533, 32506,
|
||||
32478, 32448, 32417, 32385, 32351, 32316, 32279, 32241, 32202, 32161,
|
||||
32119, 32075, 32030, 31984, 31936, 31887, 31836, 31784, 31731, 31676,
|
||||
31620, 31563, 31504, 31444, 31383, 31320, 31256, 31191, 31124, 31056,
|
||||
30987, 30916, 30845, 30771, 30697, 30621, 30544, 30466, 30387, 30306,
|
||||
30224, 30141, 30057, 29971, 29884, 29796, 29707, 29617, 29525, 29433,
|
||||
29339, 29244, 29148, 29050, 28952, 28852, 28752, 28650, 28547, 28443,
|
||||
28338, 28232, 28125, 28017, 27908, 27797, 27686, 27574, 27461, 27346,
|
||||
27231, 27115, 26998, 26879, 26760, 26640, 26519, 26398, 26275, 26151,
|
||||
26027, 25901, 25775, 25648, 25520, 25391, 25262, 25131, 25000, 24868,
|
||||
24735, 24602, 24467, 24332, 24197, 24060, 23923, 23785, 23647, 23507,
|
||||
23368, 23227, 23086, 22944, 22802, 22659, 22515, 22371, 22226, 22081,
|
||||
21935, 21789, 21642, 21494, 21346, 21198, 21049, 20900, 20750, 20600,
|
||||
20449, 20298, 20146, 19995, 19842, 19690, 19537, 19383, 19230, 19076,
|
||||
18922, 18767, 18612, 18457, 18302, 18146, 17990, 17834, 17678, 17521,
|
||||
17365, 17208, 17051, 16894, 16737, 16579, 16422, 16264, 16106, 15949,
|
||||
15791, 15633, 15475, 15317, 15159, 15001, 14843, 14685, 14527, 14369,
|
||||
14212, 14054, 13896, 13739, 13581, 13424, 13266, 13109, 12952, 12795,
|
||||
12639, 12482, 12326, 12170, 12014, 11858, 11703, 11548, 11393, 11238,
|
||||
11084, 10929, 10776, 10622, 10469, 10316, 10164, 10011, 9860, 9708,
|
||||
9557, 9407, 9256, 9106, 8957, 8808, 8659, 8511, 8364, 8216, 8070,
|
||||
7924, 7778, 7633, 7488, 7344, 7200, 7057, 6914, 6773, 6631, 6490,
|
||||
6350, 6210, 6071, 5933, 5795, 5658, 5521, 5385, 5250, 5115, 4981,
|
||||
4848, 4716, 4584, 4452, 4322, 4192, 4063, 3935, 3807, 3680, 3554,
|
||||
3429, 3304, 3180, 3057, 2935, 2813, 2692, 2572, 2453, 2335, 2217,
|
||||
2101, 1985, 1870, 1755, 1642, 1529, 1418, 1307, 1197, 1088, 979, 872,
|
||||
765, 660, 555, 451, 348, 246, 145, 44, -54, -153, -250, -347, -443,
|
||||
-537, -631, -724, -816, -908, -998, -1087, -1175, -1263, -1349, -1435,
|
||||
-1519, -1603, -1685, -1767, -1848, -1928, -2006, -2084, -2161, -2237,
|
||||
-2312, -2386, -2459, -2531, -2603, -2673, -2742, -2810, -2878, -2944,
|
||||
-3009, -3074, -3137, -3200, -3261, -3322, -3381, -3440, -3498, -3554,
|
||||
-3610, -3665, -3719, -3772, -3824, -3875, -3925, -3974, -4022, -4069,
|
||||
-4116, -4161, -4205, -4249, -4291, -4333, -4374, -4413, -4452, -4490,
|
||||
-4527, -4563, -4599, -4633, -4666, -4699, -4730, -4761, -4791, -4820,
|
||||
-4848, -4875, -4901, -4926, -4951, -4974, -4997, -5019, -5040, -5060,
|
||||
-5080, -5098, -5116, -5133, -5149, -5164, -5178, -5192, -5205, -5217,
|
||||
-5228, -5238, -5248, -5257, -5265, -5272, -5278, -5284, -5289, -5293,
|
||||
-5297, -5299, -5301, -5303, -5303, -5303, -5302, -5300, -5298, -5295,
|
||||
-5291, -5287, -5282, -5276, -5270, -5263, -5255, -5246, -5237, -5228,
|
||||
-5217, -5206, -5195, -5183, -5170, -5157, -5143, -5128, -5113, -5097,
|
||||
-5081, -5064, -5047, -5029, -5010, -4991, -4972, -4952, -4931, -4910,
|
||||
-4889, -4867, -4844, -4821, -4797, -4774, -4749, -4724, -4699, -4673,
|
||||
-4647, -4620, -4593, -4566, -4538, -4510, -4481, -4452, -4422, -4393,
|
||||
-4363, -4332, -4301, -4270, -4238, -4206, -4174, -4142, -4109, -4076,
|
||||
-4042, -4009, -3975, -3940, -3906, -3871, -3836, -3801, -3765, -3729,
|
||||
-3693, -3657, -3620, -3584, -3547, -3510, -3472, -3435, -3397, -3360,
|
||||
-3322, -3283, -3245, -3207, -3168, -3129, -3091, -3052, -3013, -2973,
|
||||
-2934, -2895, -2855, -2816, -2776, -2736, -2697, -2657, -2617, -2577,
|
||||
-2537, -2497, -2457, -2417, -2377, -2337, -2297, -2256, -2216, -2176,
|
||||
-2136, -2096, -2056, -2016, -1976, -1936, -1896, -1856, -1817, -1777,
|
||||
-1737, -1698, -1658, -1619, -1579, -1540, -1501, -1462, -1423, -1384,
|
||||
-1345, -1306, -1268, -1230, -1191, -1153, -1115, -1077, -1040, -1002,
|
||||
-965, -927, -890, -854, -817, -780, -744, -708, -672, -636, -600,
|
||||
-565, -530, -494, -460, -425, -391, -356, -322, -289, -255, -222,
|
||||
-189, -156, -123, -91, -59, -27, 4, 35, 66, 97, 127, 158, 188, 218,
|
||||
247, 277, 306, 334, 363, 391, 419, 447, 474, 501, 528, 554, 581, 606,
|
||||
632, 657, 683, 707, 732, 756, 780, 803, 827, 850, 872, 895, 917, 939,
|
||||
960, 981, 1002, 1023, 1043, 1063, 1082, 1102, 1121, 1139, 1158, 1176,
|
||||
1194, 1211, 1228, 1245, 1262, 1278, 1294, 1309, 1325, 1340, 1354,
|
||||
1369, 1383, 1397, 1410, 1423, 1436, 1448, 1461, 1473, 1484, 1496,
|
||||
1507, 1517, 1528, 1538, 1548, 1557, 1566, 1575, 1584, 1592, 1600,
|
||||
1608, 1616, 1623, 1630, 1636, 1643, 1649, 1654, 1660, 1665, 1670,
|
||||
1675, 1679, 1683, 1687, 1690, 1694, 1697, 1700, 1702, 1704, 1706,
|
||||
1708, 1709, 1711, 1712, 1712, 1713, 1713, 1713, 1713, 1712, 1711,
|
||||
1710, 1709, 1708, 1706, 1704, 1702, 1700, 1697, 1694, 1691, 1688,
|
||||
1685, 1681, 1677, 1673, 1669, 1664, 1660, 1655, 1650, 1644, 1639,
|
||||
1633, 1627, 1621, 1615, 1609, 1602, 1596, 1589, 1582, 1575, 1567,
|
||||
1560, 1552, 1544, 1536, 1528, 1520, 1511, 1503, 1494, 1485, 1476,
|
||||
1467, 1458, 1448, 1439, 1429, 1419, 1409, 1399, 1389, 1379, 1368,
|
||||
1358, 1347, 1337, 1326, 1315, 1304, 1293, 1282, 1271, 1260, 1248,
|
||||
1237, 1225, 1213, 1202, 1190, 1178, 1166, 1154, 1142, 1130, 1118,
|
||||
1106, 1094, 1081, 1069, 1057, 1044, 1032, 1019, 1007, 994, 981, 969,
|
||||
956, 943, 931, 918, 905, 892, 879, 867, 854, 841, 828, 815, 802, 790,
|
||||
777, 764, 751, 738, 725, 713, 700, 687, 674, 662, 649, 636, 623, 611,
|
||||
598, 585, 573, 560, 548, 535, 523, 510, 498, 486, 473, 461, 449, 437,
|
||||
425, 413, 401, 389, 377, 365, 353, 341, 330, 318, 307, 295, 284, 272,
|
||||
261, 250, 239, 228, 217, 206, 195, 184, 173, 163, 152, 141, 131, 121,
|
||||
110, 100, 90, 80, 70, 60, 51, 41, 31, 22, 12, 3, -5, -14, -23, -32,
|
||||
-41, -50, -59, -67, -76, -84, -93, -101, -109, -117, -125, -133, -140,
|
||||
-148, -156, -163, -170, -178, -185, -192, -199, -206, -212, -219,
|
||||
-226, -232, -239, -245, -251, -257, -263, -269, -275, -280, -286,
|
||||
-291, -297, -302, -307, -312, -317, -322, -327, -332, -336, -341,
|
||||
-345, -349, -354, -358, -362, -366, -369, -373, -377, -380, -384,
|
||||
-387, -390, -394, -397, -400, -402, -405, -408, -411, -413, -416,
|
||||
-418, -420, -422, -424, -426, -428, -430, -432, -433, -435, -436,
|
||||
-438, -439, -440, -442, -443, -444, -445, -445, -446, -447, -447,
|
||||
-448, -448, -449, -449, -449, -449, -449, -449, -449, -449, -449,
|
||||
-449, -449, -448, -448, -447, -447, -446, -445, -444, -443, -443,
|
||||
-442, -441, -440, -438, -437, -436, -435, -433, -432, -430, -429,
|
||||
-427, -426, -424, -422, -420, -419, -417, -415, -413, -411, -409,
|
||||
-407, -405, -403, -400, -398, -396, -393, -391, -389, -386, -384,
|
||||
-381, -379, -376, -374, -371, -368, -366, -363, -360, -357, -355,
|
||||
-352, -349, -346, -343, -340, -337, -334, -331, -328, -325, -322,
|
||||
-319, -316, -313, -310, -307, -304, -301, -298, -294, -291, -288,
|
||||
-285, -282, -278, -275, -272, -269, -265, -262, -259, -256, -252,
|
||||
-249, -246, -243, -239, -236, -233, -230, -226, -223, -220, -217,
|
||||
-213, -210, -207, -204, -200, -197, -194, -191, -187, -184, -181,
|
||||
-178, -175, -172, -168, -165, -162, -159, -156, -153, -150, -147,
|
||||
-143, -140, -137, -134, -131, -128, -125, -122, -120, -117, -114,
|
||||
-111, -108, -105, -102, -99, -97, -94, -91, -88, -86, -83, -80, -78,
|
||||
-75, -72, -70, -67, -65, -62, -59, -57, -55, -52, -50, -47, -45, -43,
|
||||
-40, -38, -36, -33, -31, -29, -27, -25, -22, -20, -18, -16, -14, -12,
|
||||
-10, -8, -6, -4, -2, 0, 0, 2, 4, 6, 8, 9, 11, 13, 14, 16, 17, 19, 21,
|
||||
22, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 37, 38, 40, 41, 42, 43,
|
||||
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
|
||||
59, 60, 61, 62, 62, 63, 63, 64, 64, 65, 66, 66, 66, 67, 67, 68, 68,
|
||||
69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72,
|
||||
72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
|
||||
72, 71, 71, 71, 71, 71, 70, 70, 70, 70, 69, 69, 69, 69, 68, 68, 68,
|
||||
67, 67, 67, 66, 66, 66, 65, 65, 64, 64, 64, 63, 63, 62, 62, 62, 61,
|
||||
61, 60, 60, 59, 59, 58, 58, 58, 57, 57, 56, 56, 55, 55, 54, 54, 53,
|
||||
53, 52, 52, 51, 51, 50, 50, 49, 48, 48, 47, 47, 46, 46, 45, 45, 44,
|
||||
44, 43, 43, 42, 42, 41, 41, 40, 39, 39, 38, 38, 37, 37, 36, 36, 35,
|
||||
35, 34, 34, 33, 33, 32, 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27,
|
||||
26, 26, 25, 25, 24, 24, 23, 23, 23, 22, 22, 21, 21, 20, 20, 20, 19,
|
||||
19, 18, 18, 17, 17, 17, 16, 16, 15, 15, 15, 14, 14, 14, 13, 13, 12,
|
||||
12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 7, 7, 7, 7, 6, 6,
|
||||
6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1,
|
||||
1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
18
sys/src/libpcm/mkfile
Normal file
18
sys/src/libpcm/mkfile
Normal file
|
@ -0,0 +1,18 @@
|
|||
</$objtype/mkfile
|
||||
|
||||
LIB=/$objtype/lib/libpcm.a
|
||||
OFILES=\
|
||||
conv.$O\
|
||||
desc.$O\
|
||||
|
||||
HFILES=\
|
||||
/sys/include/pcm.h\
|
||||
fir.h\
|
||||
|
||||
UPDATE=\
|
||||
mkfile\
|
||||
$HFILES\
|
||||
${OFILES:%.$O=%.c}\
|
||||
${LIB:/$objtype/%=/386/%}\
|
||||
|
||||
</sys/src/cmd/mksyslib
|
|
@ -28,6 +28,7 @@ LIBS=\
|
|||
libmemlayer\
|
||||
libmp\
|
||||
libndb\
|
||||
libpcm\
|
||||
libplumb\
|
||||
libregexp\
|
||||
libsat\
|
||||
|
|
Loading…
Reference in a new issue