diff options
author | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2008-11-04 14:16:10 +0000 |
---|---|---|
committer | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2008-11-04 14:16:10 +0000 |
commit | 33056b5e06726f76b0a697a60e98d251795cbda6 (patch) | |
tree | 6df6d8623ceff1d26a317e901cb65aa6e7429d33 | |
parent | f912c843363d65a63ac18dfaef1e1f1ceb12733a (diff) |
optimization: add "new" resampling code (actually based on the existing
conversion bits) and use it when resampling only is required (ie for
clients using s16 encoding), this is the most common case. Reduces CPU
usage by ~50%. No functional change.
-rw-r--r-- | usr.bin/aucat/aproc.c | 201 | ||||
-rw-r--r-- | usr.bin/aucat/aproc.h | 9 | ||||
-rw-r--r-- | usr.bin/aucat/dev.c | 28 |
3 files changed, 223 insertions, 15 deletions
diff --git a/usr.bin/aucat/aproc.c b/usr.bin/aucat/aproc.c index ad903758a62..7a97646e111 100644 --- a/usr.bin/aucat/aproc.c +++ b/usr.bin/aucat/aproc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aproc.c,v 1.14 2008/11/03 22:55:34 ratchov Exp $ */ +/* $OpenBSD: aproc.c,v 1.15 2008/11/04 14:16:09 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -31,6 +31,8 @@ * * - conv: converts/resamples/remaps a single stream * + * - resamp: resample streams in native format + * * TODO * * (easy) split the "conv" into 2 converters: one for input (that @@ -1047,3 +1049,200 @@ conv_new(char *name, struct aparams *ipar, struct aparams *opar) } return p; } + +/* + * Convert one block. + */ +void +resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) +{ + unsigned inch; + short *idata; + unsigned ipos, orate; + unsigned ifr; + unsigned onch; + short *odata; + unsigned opos, irate; + unsigned ofr; + unsigned c; + short *ctxbuf, *ctx; + unsigned icount, ocount; + + /* + * Calculate max frames readable at once from the input buffer. + */ + idata = (short *)abuf_rgetblk(ibuf, &icount, 0); + ifr = icount / ibuf->bpf; + icount = ifr * ibuf->bpf; + + odata = (short *)abuf_wgetblk(obuf, &ocount, 0); + ofr = ocount / obuf->bpf; + ocount = ofr * obuf->bpf; + + /* + * Partially copy structures into local variables, to avoid + * unnecessary indirections; this also allows the compiler to + * order local variables more "cache-friendly". + */ + inch = ibuf->cmax - ibuf->cmin + 1; + ipos = p->u.resamp.ipos; + irate = p->u.resamp.irate; + onch = obuf->cmax - obuf->cmin + 1; + opos = p->u.resamp.opos; + orate = p->u.resamp.orate; + ctxbuf = p->u.resamp.ctx; + + /* + * Start conversion. + */ + DPRINTFN(4, "resamp_bcopy: ifr=%d ofr=%d\n", ifr, ofr); + for (;;) { + if ((int)(ipos - opos) > 0) { + if (ofr == 0) + break; + ctx = ctxbuf; + for (c = onch; c > 0; c--) { + *odata = *ctx; + odata++; + ctx++; + } + opos += irate; + ofr--; + } else { + if (ifr == 0) + break; + ctx = ctxbuf; + for (c = inch; c > 0; c--) { + *ctx = *idata; + idata++; + ctx++; + } + ipos += orate; + ifr--; + } + } + p->u.resamp.ipos = ipos; + p->u.resamp.opos = opos; + DPRINTFN(4, "resamp_bcopy: done, ifr=%d ofr=%d\n", ifr, ofr); + + /* + * Update FIFO pointers. + */ + icount -= ifr * ibuf->bpf; + ocount -= ofr * obuf->bpf; + abuf_rdiscard(ibuf, icount); + abuf_wcommit(obuf, ocount); +} + +int +resamp_in(struct aproc *p, struct abuf *ibuf) +{ + struct abuf *obuf = LIST_FIRST(&p->obuflist); + + DPRINTFN(4, "resamp_in: %s\n", p->name); + + if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf)) + return 0; + resamp_bcopy(p, ibuf, obuf); + if (!abuf_flush(obuf)) + return 0; + return 1; +} + +int +resamp_out(struct aproc *p, struct abuf *obuf) +{ + struct abuf *ibuf = LIST_FIRST(&p->ibuflist); + + DPRINTFN(4, "resamp_out: %s\n", p->name); + + if (!abuf_fill(ibuf)) + return 0; + if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf)) + return 0; + resamp_bcopy(p, ibuf, obuf); + return 1; +} + +void +resamp_eof(struct aproc *p, struct abuf *ibuf) +{ + DPRINTFN(4, "resamp_eof: %s\n", p->name); + + aproc_del(p); +} + +void +resamp_hup(struct aproc *p, struct abuf *obuf) +{ + DPRINTFN(4, "resamp_hup: %s\n", p->name); + + aproc_del(p); +} + +void +resamp_ipos(struct aproc *p, struct abuf *ibuf, int delta) +{ + struct abuf *obuf = LIST_FIRST(&p->obuflist); + long long ipos; + int ifac, ofac; + + DPRINTFN(3, "resamp_ipos: %d\n", delta); + + ifac = p->u.resamp.irate; + ofac = p->u.resamp.orate; + ipos = p->u.resamp.idelta + (long long)delta * ofac; + delta = (ipos + ifac - 1) / ifac; + p->u.resamp.idelta = ipos - (long long)delta * ifac; + abuf_ipos(obuf, delta); +} + +void +resamp_opos(struct aproc *p, struct abuf *obuf, int delta) +{ + struct abuf *ibuf = LIST_FIRST(&p->ibuflist); + long long opos; + int ifac, ofac; + + DPRINTFN(3, "resamp_opos: %d\n", delta); + + ifac = p->u.resamp.irate; + ofac = p->u.resamp.orate; + opos = p->u.resamp.odelta + (long long)delta * ifac; + delta = (opos + ofac - 1) / ofac; + p->u.resamp.odelta = opos - (long long)delta * ofac; + abuf_opos(ibuf, delta); +} + +struct aproc_ops resamp_ops = { + "resamp", + resamp_in, + resamp_out, + resamp_eof, + resamp_hup, + NULL, + NULL, + resamp_ipos, + resamp_opos, + NULL +}; + +struct aproc * +resamp_new(char *name, struct aparams *ipar, struct aparams *opar) +{ + struct aproc *p; + + p = aproc_new(&resamp_ops, name); + p->u.resamp.irate = ipar->rate; + p->u.resamp.orate = opar->rate; + p->u.resamp.ipos = 0; + p->u.resamp.opos = 0; + p->u.resamp.idelta = 0; + p->u.resamp.odelta = 0; + if (debug_level > 0) { + DPRINTF("resamp_new: %s: ", p->name); + aparams_print2(ipar, opar); + DPRINTF("\n"); + } + return p; +} diff --git a/usr.bin/aucat/aproc.h b/usr.bin/aucat/aproc.h index cdf97965c3f..48bc4985c31 100644 --- a/usr.bin/aucat/aproc.h +++ b/usr.bin/aucat/aproc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: aproc.h,v 1.6 2008/10/26 08:49:43 ratchov Exp $ */ +/* $OpenBSD: aproc.h,v 1.7 2008/11/04 14:16:09 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -162,6 +162,12 @@ struct aproc { int lat; /* current latency */ int maxlat; /* max latency allowed*/ } sub; + struct { + short ctx[NCHAN_MAX]; + unsigned irate, orate; + int ipos, opos; + int idelta, odelta; /* reminder of conv_[io]pos */ + } resamp; } u; }; @@ -187,6 +193,7 @@ void wpipe_hup(struct aproc *, struct abuf *); struct aproc *mix_new(char *, int); struct aproc *sub_new(char *, int); struct aproc *conv_new(char *, struct aparams *, struct aparams *); +struct aproc *resamp_new(char *, struct aparams *, struct aparams *); void mix_pushzero(struct aproc *); void mix_setmaster(struct aproc *); diff --git a/usr.bin/aucat/dev.c b/usr.bin/aucat/dev.c index 70391760653..72e8d0c19ed 100644 --- a/usr.bin/aucat/dev.c +++ b/usr.bin/aucat/dev.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dev.c,v 1.4 2008/11/03 22:25:13 ratchov Exp $ */ +/* $OpenBSD: dev.c,v 1.5 2008/11/04 14:16:09 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -383,13 +383,7 @@ dev_attach(char *name, if (ibuf) { pbuf = LIST_FIRST(&dev_mix->obuflist); if (!aparams_eqenc(ipar, &dev_opar) || - !aparams_eqrate(ipar, &dev_opar) || !aparams_subset(ipar, &dev_opar)) { - if (debug_level > 1) { - fprintf(stderr, "dev_attach: %s: ", name); - aparams_print2(ipar, &dev_opar); - fprintf(stderr, "\n"); - } nfr = (dev_bufsz + 3) / 4 + dev_round - 1; nfr -= nfr % dev_round; conv = conv_new(name, ipar, &dev_opar); @@ -397,6 +391,13 @@ dev_attach(char *name, ibuf = abuf_new(nfr, &dev_opar); aproc_setout(conv, ibuf); /* XXX: call abuf_fill() here ? */ + } else if (!aparams_eqrate(ipar, &dev_opar)) { + nfr = (dev_bufsz + 3) / 4 + dev_round - 1; + nfr -= nfr % dev_round; + conv = resamp_new(name, ipar, &dev_opar); + aproc_setin(conv, ibuf); + ibuf = abuf_new(nfr, &dev_opar); + aproc_setout(conv, ibuf); } aproc_setin(dev_mix, ibuf); abuf_opos(ibuf, -dev_mix->u.mix.lat); @@ -405,19 +406,20 @@ dev_attach(char *name, if (obuf) { rbuf = LIST_FIRST(&dev_sub->ibuflist); if (!aparams_eqenc(opar, &dev_ipar) || - !aparams_eqrate(opar, &dev_ipar) || !aparams_subset(opar, &dev_ipar)) { - if (debug_level > 1) { - fprintf(stderr, "dev_attach: %s: ", name); - aparams_print2(&dev_ipar, opar); - fprintf(stderr, "\n"); - } nfr = (dev_bufsz + 3) / 4 + dev_round - 1; nfr -= nfr % dev_round; conv = conv_new(name, &dev_ipar, opar); aproc_setout(conv, obuf); obuf = abuf_new(nfr, &dev_ipar); aproc_setin(conv, obuf); + } else if (!aparams_eqrate(opar, &dev_ipar)) { + nfr = (dev_bufsz + 3) / 4 + dev_round - 1; + nfr -= nfr % dev_round; + conv = resamp_new(name, &dev_ipar, opar); + aproc_setout(conv, obuf); + obuf = abuf_new(nfr, &dev_ipar); + aproc_setin(conv, obuf); } aproc_setout(dev_sub, obuf); abuf_ipos(obuf, -dev_sub->u.sub.lat); |