Annotation of src/usr.bin/aucat/aproc.c, Revision 1.1
1.1 ! ratchov 1: /* $OpenBSD$ */
! 2: /*
! 3: * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17: /*
! 18: * aproc structures are simple audio processing units. They are
! 19: * interconnected by abuf structures and form a kind of circuit. aproc
! 20: * structure have call-backs that do the actual processing.
! 21: *
! 22: * This module implements the following processing units:
! 23: *
! 24: * - rpipe: read end of an unix file (pipe, socket, device...)
! 25: *
! 26: * - wpipe: write end of an unix file (pipe, socket, device...)
! 27: *
! 28: * - mix: mix N inputs -> 1 output
! 29: *
! 30: * - sub: from 1 input -> extract/copy N outputs
! 31: *
! 32: * - conv: converts/resamples/remaps a single stream
! 33: *
! 34: * TODO
! 35: *
! 36: * (easy) split the "conv" into 2 converters: one for input (that
! 37: * convers anything to 16bit signed) and one for the output (that
! 38: * converts 16bit signed to anything)
! 39: *
! 40: * (hard) handle underruns in rpipe and mix
! 41: *
! 42: * (hard) handle overruns in wpipe and sub
! 43: *
! 44: * (hard) add a lowpass filter for the resampler. Quality is
! 45: * not acceptable as is.
! 46: */
! 47: #include <err.h>
! 48: #include <limits.h>
! 49: #include <stdio.h>
! 50: #include <stdlib.h>
! 51: #include <string.h>
! 52:
! 53: #include "conf.h"
! 54: #include "aparams.h"
! 55: #include "abuf.h"
! 56: #include "aproc.h"
! 57: #include "file.h"
! 58:
! 59: struct aproc *
! 60: aproc_new(struct aproc_ops *ops, char *name)
! 61: {
! 62: struct aproc *p;
! 63:
! 64: p = malloc(sizeof(struct aproc));
! 65: if (p == NULL)
! 66: err(1, name);
! 67: LIST_INIT(&p->ibuflist);
! 68: LIST_INIT(&p->obuflist);
! 69: p->name = name;
! 70: p->ops = ops;
! 71: return p;
! 72: }
! 73:
! 74: void
! 75: aproc_del(struct aproc *p)
! 76: {
! 77: DPRINTF("aproc_del: %s: %s: deleted\n", p->ops->name, p->name);
! 78: free(p);
! 79: }
! 80:
! 81: void
! 82: aproc_setin(struct aproc *p, struct abuf *ibuf)
! 83: {
! 84: LIST_INSERT_HEAD(&p->ibuflist, ibuf, ient);
! 85: ibuf->rproc = p;
! 86: if (p->ops->newin)
! 87: p->ops->newin(p, ibuf);
! 88: }
! 89:
! 90: void
! 91: aproc_setout(struct aproc *p, struct abuf *obuf)
! 92: {
! 93: LIST_INSERT_HEAD(&p->obuflist, obuf, oent);
! 94: obuf->wproc = p;
! 95: if (p->ops->newout)
! 96: p->ops->newout(p, obuf);
! 97: }
! 98:
! 99: int
! 100: rpipe_in(struct aproc *p, struct abuf *ibuf_dummy)
! 101: {
! 102: struct abuf *obuf = LIST_FIRST(&p->obuflist);
! 103: struct file *f = p->u.io.file;
! 104: unsigned char *data;
! 105: unsigned count;
! 106:
! 107: if (!(f->state & FILE_RFLOW) && ABUF_FULL(obuf))
! 108: errx(1, "%s: overrun, unimplemented", f->name);
! 109:
! 110: if (ABUF_FULL(obuf))
! 111: return 0;
! 112: data = abuf_wgetblk(obuf, &count, 0);
! 113: obuf->used += file_read(f, data, count);
! 114: abuf_flush(obuf);
! 115: return !ABUF_FULL(obuf);
! 116: }
! 117:
! 118: int
! 119: rpipe_out(struct aproc *p, struct abuf *obuf)
! 120: {
! 121: struct file *f = p->u.io.file;
! 122: unsigned char *data;
! 123: unsigned count;
! 124:
! 125: if (!(f->state & FILE_ROK))
! 126: return 0;
! 127: data = abuf_wgetblk(obuf, &count, 0);
! 128: obuf->used += file_read(f, data, count);
! 129: return f->state & FILE_ROK;
! 130: }
! 131:
! 132: void
! 133: rpipe_del(struct aproc *p)
! 134: {
! 135: struct file *f = p->u.io.file;
! 136:
! 137: f->rproc = NULL;
! 138: f->events &= ~POLLIN;
! 139: aproc_del(p);
! 140: }
! 141:
! 142: void
! 143: rpipe_eof(struct aproc *p, struct abuf *ibuf_dummy)
! 144: {
! 145: DPRINTFN(3, "rpipe_eof: %s\n", p->name);
! 146: abuf_eof(LIST_FIRST(&p->obuflist));
! 147: rpipe_del(p);
! 148: }
! 149:
! 150: void
! 151: rpipe_hup(struct aproc *p, struct abuf *obuf)
! 152: {
! 153: DPRINTFN(3, "rpipe_hup: %s\n", p->name);
! 154: rpipe_del(p);
! 155: }
! 156:
! 157: struct aproc_ops rpipe_ops = {
! 158: "rpipe", rpipe_in, rpipe_out, rpipe_eof, rpipe_hup, NULL, NULL
! 159: };
! 160:
! 161: struct aproc *
! 162: rpipe_new(struct file *f)
! 163: {
! 164: struct aproc *p;
! 165:
! 166: p = aproc_new(&rpipe_ops, f->name);
! 167: p->u.io.file = f;
! 168: f->rproc = p;
! 169: f->events |= POLLIN;
! 170: f->state |= FILE_RFLOW;
! 171: return p;
! 172: }
! 173:
! 174: void
! 175: wpipe_del(struct aproc *p)
! 176: {
! 177: struct file *f = p->u.io.file;
! 178:
! 179: f->wproc = NULL;
! 180: f->events &= ~POLLOUT;
! 181: aproc_del(p);
! 182: }
! 183:
! 184: int
! 185: wpipe_in(struct aproc *p, struct abuf *ibuf)
! 186: {
! 187: struct file *f = p->u.io.file;
! 188: unsigned char *data;
! 189: unsigned count;
! 190:
! 191: if (!(f->state & FILE_WOK))
! 192: return 0;
! 193:
! 194: data = abuf_rgetblk(ibuf, &count, 0);
! 195: count = file_write(f, data, count);
! 196: ibuf->used -= count;
! 197: ibuf->start += count;
! 198: if (ibuf->start >= ibuf->len)
! 199: ibuf->start -= ibuf->len;
! 200: return f->state & FILE_WOK;
! 201: }
! 202:
! 203: int
! 204: wpipe_out(struct aproc *p, struct abuf *obuf_dummy)
! 205: {
! 206: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
! 207: struct file *f = p->u.io.file;
! 208: unsigned char *data;
! 209: unsigned count;
! 210:
! 211: if (!(f->state & FILE_WFLOW) && ABUF_EMPTY(ibuf))
! 212: errx(1, "%s: underrun, unimplemented", f->name);
! 213:
! 214: if (ABUF_EMPTY(ibuf))
! 215: return 0;
! 216: data = abuf_rgetblk(ibuf, &count, 0);
! 217: count = file_write(f, data, count);
! 218: ibuf->used -= count;
! 219: ibuf->start += count;
! 220: if (ibuf->start >= ibuf->len)
! 221: ibuf->start -= ibuf->len;
! 222: if (ABUF_EOF(ibuf)) {
! 223: abuf_hup(ibuf);
! 224: wpipe_del(p);
! 225: return 0;
! 226: }
! 227: abuf_fill(ibuf);
! 228: return 1;
! 229: }
! 230:
! 231: void
! 232: wpipe_eof(struct aproc *p, struct abuf *ibuf)
! 233: {
! 234: DPRINTFN(3, "wpipe_eof: %s\n", p->name);
! 235: wpipe_del(p);
! 236: }
! 237:
! 238: void
! 239: wpipe_hup(struct aproc *p, struct abuf *obuf_dummy)
! 240: {
! 241: DPRINTFN(3, "wpipe_hup: %s\n", p->name);
! 242: abuf_hup(LIST_FIRST(&p->ibuflist));
! 243: wpipe_del(p);
! 244: }
! 245:
! 246: struct aproc_ops wpipe_ops = {
! 247: "wpipe", wpipe_in, wpipe_out, wpipe_eof, wpipe_hup, NULL, NULL
! 248: };
! 249:
! 250: struct aproc *
! 251: wpipe_new(struct file *f)
! 252: {
! 253: struct aproc *p;
! 254:
! 255: p = aproc_new(&wpipe_ops, f->name);
! 256: p->u.io.file = f;
! 257: f->wproc = p;
! 258: f->events |= POLLOUT;
! 259: f->state |= FILE_WFLOW;
! 260: return p;
! 261: }
! 262:
! 263: /*
! 264: * Fill an output block with silence.
! 265: */
! 266: void
! 267: mix_bzero(struct aproc *p)
! 268: {
! 269: struct abuf *obuf = LIST_FIRST(&p->obuflist);
! 270: short *odata;
! 271: unsigned ocount;
! 272:
! 273: DPRINTFN(4, "mix_bzero: used = %u, zero = %u\n",
! 274: obuf->used, obuf->mixtodo);
! 275: odata = (short *)abuf_wgetblk(obuf, &ocount, obuf->mixtodo);
! 276: if (ocount == 0)
! 277: return;
! 278: memset(odata, 0, ocount);
! 279: obuf->mixtodo += ocount;
! 280: DPRINTFN(4, "mix_bzero: ocount %u, todo %u\n", ocount, obuf->mixtodo);
! 281: }
! 282:
! 283: /*
! 284: * Mix an input block over an output block.
! 285: */
! 286: void
! 287: mix_badd(struct abuf *ibuf, struct abuf *obuf)
! 288: {
! 289: short *idata, *odata;
! 290: unsigned i, scount, icount, ocount;
! 291: int vol = ibuf->mixvol;
! 292:
! 293: DPRINTFN(4, "mix_badd: zero = %u, done = %u\n",
! 294: obuf->mixtodo, ibuf->mixdone);
! 295:
! 296: idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
! 297: if (icount == 0)
! 298: return;
! 299:
! 300: odata = (short *)abuf_wgetblk(obuf, &ocount, ibuf->mixdone);
! 301: if (ocount == 0)
! 302: return;
! 303:
! 304: scount = (icount < ocount) ? icount : ocount;
! 305: for (i = scount / sizeof(short); i > 0; i--) {
! 306: *odata += (*idata * vol) >> ADATA_SHIFT;
! 307: idata++;
! 308: odata++;
! 309: }
! 310:
! 311: ibuf->used -= scount;
! 312: ibuf->mixdone += scount;
! 313: ibuf->start += scount;
! 314: if (ibuf->start >= ibuf->len)
! 315: ibuf->start -= ibuf->len;
! 316:
! 317: DPRINTFN(4, "mix_badd: added %u, done = %u, zero = %u\n",
! 318: scount, ibuf->mixdone, obuf->mixtodo);
! 319: }
! 320:
! 321: /*
! 322: * Remove an input stream from the mixer.
! 323: */
! 324: void
! 325: mix_rm(struct aproc *p, struct abuf *ibuf)
! 326: {
! 327: LIST_REMOVE(ibuf, ient);
! 328: DPRINTF("mix_rm: %s\n", p->name);
! 329: }
! 330:
! 331: int
! 332: mix_in(struct aproc *p, struct abuf *ibuf)
! 333: {
! 334: struct abuf *i, *inext, *obuf = LIST_FIRST(&p->obuflist);
! 335: unsigned ocount;
! 336:
! 337: DPRINTFN(4, "mix_in: used = %u, done = %u, zero = %u\n",
! 338: ibuf->used, ibuf->mixdone, obuf->mixtodo);
! 339:
! 340: if (ibuf->mixdone >= obuf->mixtodo)
! 341: return 0;
! 342: mix_badd(ibuf, obuf);
! 343: ocount = obuf->mixtodo;
! 344: LIST_FOREACH(i, &p->ibuflist, ient) {
! 345: if (ocount > i->mixdone)
! 346: ocount = i->mixdone;
! 347: }
! 348: if (ocount == 0)
! 349: return 0;
! 350:
! 351: obuf->used += ocount;
! 352: obuf->mixtodo -= ocount;
! 353: abuf_flush(obuf);
! 354: mix_bzero(p);
! 355: for (i = LIST_FIRST(&p->ibuflist); i != LIST_END(); i = inext) {
! 356: inext = LIST_NEXT(i, ient);
! 357: i->mixdone -= ocount;
! 358: if (i != ibuf && i->mixdone < obuf->mixtodo) {
! 359: if (ABUF_EOF(i)) {
! 360: mix_rm(p, i);
! 361: abuf_hup(i);
! 362: continue;
! 363: }
! 364: mix_badd(i, obuf);
! 365: abuf_fill(i);
! 366: }
! 367: }
! 368: return 1;
! 369: }
! 370:
! 371: int
! 372: mix_out(struct aproc *p, struct abuf *obuf)
! 373: {
! 374: struct abuf *i, *inext;
! 375: unsigned ocount;
! 376:
! 377: DPRINTFN(4, "mix_out: used = %u, zero = %u\n",
! 378: obuf->used, obuf->mixtodo);
! 379:
! 380: /*
! 381: * XXX: should handle underruns here, currently if one input is
! 382: * blocked, then the output block can underrun.
! 383: */
! 384: mix_bzero(p);
! 385: ocount = obuf->mixtodo;
! 386: for (i = LIST_FIRST(&p->ibuflist); i != LIST_END(); i = inext) {
! 387: inext = LIST_NEXT(i, ient);
! 388: mix_badd(i, obuf);
! 389: if (ocount > i->mixdone)
! 390: ocount = i->mixdone;
! 391: if (ABUF_EOF(i)) {
! 392: mix_rm(p, i);
! 393: abuf_hup(i);
! 394: continue;
! 395: }
! 396: abuf_fill(i);
! 397: }
! 398: if (ocount == 0)
! 399: return 0;
! 400: if (LIST_EMPTY(&p->ibuflist)) {
! 401: DPRINTF("mix_out: nothing more to do...\n");
! 402: obuf->wproc = NULL;
! 403: aproc_del(p);
! 404: return 0;
! 405: }
! 406: obuf->used += ocount;
! 407: obuf->mixtodo -= ocount;
! 408: LIST_FOREACH(i, &p->ibuflist, ient) {
! 409: i->mixdone -= ocount;
! 410: }
! 411: return 1;
! 412: }
! 413:
! 414: void
! 415: mix_eof(struct aproc *p, struct abuf *ibuf)
! 416: {
! 417: struct abuf *obuf = LIST_FIRST(&p->obuflist);
! 418:
! 419: DPRINTF("mix_eof: %s: detached\n", p->name);
! 420: mix_rm(p, ibuf);
! 421: /*
! 422: * If there's no more inputs, abuf_run() will trigger the eof
! 423: * condition and propagate it, so no need to handle it here.
! 424: */
! 425: abuf_run(obuf);
! 426: DPRINTF("mix_eof: done\n");
! 427: }
! 428:
! 429: void
! 430: mix_hup(struct aproc *p, struct abuf *obuf)
! 431: {
! 432: struct abuf *ibuf;
! 433:
! 434: while (!LIST_EMPTY(&p->ibuflist)) {
! 435: ibuf = LIST_FIRST(&p->ibuflist);
! 436: mix_rm(p, ibuf);
! 437: abuf_hup(ibuf);
! 438: }
! 439: DPRINTF("mix_hup: %s: done\n", p->name);
! 440: aproc_del(p);
! 441: }
! 442:
! 443: void
! 444: mix_newin(struct aproc *p, struct abuf *ibuf)
! 445: {
! 446: ibuf->mixdone = 0;
! 447: ibuf->mixvol = ADATA_UNIT;
! 448: }
! 449:
! 450: void
! 451: mix_newout(struct aproc *p, struct abuf *obuf)
! 452: {
! 453: obuf->mixtodo = 0;
! 454: mix_bzero(p);
! 455: }
! 456:
! 457: struct aproc_ops mix_ops = {
! 458: "mix", mix_in, mix_out, mix_eof, mix_hup, mix_newin, mix_newout
! 459: };
! 460:
! 461: struct aproc *
! 462: mix_new(void)
! 463: {
! 464: struct aproc *p;
! 465:
! 466: p = aproc_new(&mix_ops, "softmix");
! 467: return p;
! 468: }
! 469:
! 470: /*
! 471: * Copy data from ibuf to obuf.
! 472: */
! 473: void
! 474: sub_bcopy(struct abuf *ibuf, struct abuf *obuf)
! 475: {
! 476: unsigned char *idata, *odata;
! 477: unsigned icount, ocount, scount;
! 478:
! 479: idata = abuf_rgetblk(ibuf, &icount, obuf->subdone);
! 480: if (icount == 0)
! 481: return;
! 482: odata = abuf_wgetblk(obuf, &ocount, 0);
! 483: if (ocount == 0)
! 484: return;
! 485: scount = (icount < ocount) ? icount : ocount;
! 486: memcpy(odata, idata, scount);
! 487: obuf->subdone += scount;
! 488: obuf->used += scount;
! 489: DPRINTFN(4, "sub_bcopy: %u bytes\n", scount);
! 490: }
! 491:
! 492: void
! 493: sub_rm(struct aproc *p, struct abuf *obuf)
! 494: {
! 495: LIST_REMOVE(obuf, oent);
! 496: DPRINTF("sub_rm: %s\n", p->name);
! 497: }
! 498:
! 499: void
! 500: sub_del(struct aproc *p)
! 501: {
! 502: aproc_del(p);
! 503: }
! 504:
! 505: int
! 506: sub_in(struct aproc *p, struct abuf *ibuf)
! 507: {
! 508: struct abuf *i, *inext;
! 509: unsigned done;
! 510: int again;
! 511:
! 512: again = 1;
! 513: done = ibuf->used;
! 514: for (i = LIST_FIRST(&p->obuflist); i != LIST_END(); i = inext) {
! 515: inext = LIST_NEXT(i, oent);
! 516: if (ABUF_WOK(i)) {
! 517: sub_bcopy(ibuf, i);
! 518: abuf_flush(i);
! 519: }
! 520: if (!ABUF_WOK(i))
! 521: again = 0;
! 522: if (done > i->subdone)
! 523: done = i->subdone;
! 524: }
! 525: LIST_FOREACH(i, &p->obuflist, oent) {
! 526: i->subdone -= done;
! 527: }
! 528: ibuf->used -= done;
! 529: ibuf->start += done;
! 530: if (ibuf->start >= ibuf->len)
! 531: ibuf->start -= ibuf->len;
! 532: return again;
! 533: }
! 534:
! 535: int
! 536: sub_out(struct aproc *p, struct abuf *obuf)
! 537: {
! 538: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
! 539: struct abuf *i, *inext;
! 540: unsigned done;
! 541:
! 542: if (obuf->subdone >= ibuf->used)
! 543: return 0;
! 544:
! 545: sub_bcopy(ibuf, obuf);
! 546:
! 547: done = ibuf->used;
! 548: LIST_FOREACH(i, &p->obuflist, oent) {
! 549: if (i != obuf && ABUF_WOK(i)) {
! 550: sub_bcopy(ibuf, i);
! 551: abuf_flush(i);
! 552: }
! 553: if (done > i->subdone)
! 554: done = i->subdone;
! 555: }
! 556: if (done == 0)
! 557: return 0;
! 558: LIST_FOREACH(i, &p->obuflist, oent) {
! 559: i->subdone -= done;
! 560: }
! 561: ibuf->used -= done;
! 562: ibuf->start += done;
! 563: if (ibuf->start >= ibuf->len)
! 564: ibuf->start -= ibuf->len;
! 565: if (ABUF_EOF(ibuf)) {
! 566: abuf_hup(ibuf);
! 567: for (i = LIST_FIRST(&p->obuflist);
! 568: i != LIST_END();
! 569: i = inext) {
! 570: inext = LIST_NEXT(i, oent);
! 571: if (i != ibuf)
! 572: abuf_eof(i);
! 573: }
! 574: ibuf->wproc = NULL;
! 575: sub_del(p);
! 576: return 0;
! 577: }
! 578: abuf_fill(ibuf);
! 579: return 1;
! 580: }
! 581:
! 582: void
! 583: sub_eof(struct aproc *p, struct abuf *ibuf)
! 584: {
! 585: struct abuf *obuf;
! 586:
! 587: while (!LIST_EMPTY(&p->obuflist)) {
! 588: obuf = LIST_FIRST(&p->obuflist);
! 589: sub_rm(p, obuf);
! 590: abuf_eof(obuf);
! 591: }
! 592: sub_del(p);
! 593: }
! 594:
! 595: void
! 596: sub_hup(struct aproc *p, struct abuf *obuf)
! 597: {
! 598: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
! 599:
! 600: DPRINTF("sub_hup: %s: detached\n", p->name);
! 601: sub_rm(p, obuf);
! 602: if (LIST_EMPTY(&p->obuflist)) {
! 603: abuf_hup(ibuf);
! 604: sub_del(p);
! 605: } else
! 606: abuf_run(ibuf);
! 607: DPRINTF("sub_hup: done\n");
! 608: }
! 609:
! 610: void
! 611: sub_newout(struct aproc *p, struct abuf *obuf)
! 612: {
! 613: obuf->subdone = 0;
! 614: }
! 615:
! 616: struct aproc_ops sub_ops = {
! 617: "sub", sub_in, sub_out, sub_eof, sub_hup, NULL, sub_newout
! 618: };
! 619:
! 620: struct aproc *
! 621: sub_new(void)
! 622: {
! 623: struct aproc *p;
! 624:
! 625: p = aproc_new(&sub_ops, "copy");
! 626: return p;
! 627: }
! 628:
! 629:
! 630: /*
! 631: * Convert one block.
! 632: */
! 633: void
! 634: conv_bcopy(struct aconv *ist, struct aconv *ost,
! 635: struct abuf *ibuf, struct abuf *obuf)
! 636: {
! 637: int *ictx;
! 638: unsigned inch, ibps;
! 639: unsigned char *idata;
! 640: int ibnext, isigbit;
! 641: unsigned ishift;
! 642: int isnext;
! 643: unsigned ipos, orate;
! 644: unsigned ifr;
! 645: int *octx;
! 646: unsigned onch, oshift;
! 647: int osigbit;
! 648: unsigned obps;
! 649: unsigned char *odata;
! 650: int obnext, osnext;
! 651: unsigned opos, irate;
! 652: unsigned ofr;
! 653: unsigned c, i;
! 654: int s, *ctx;
! 655: unsigned icount, ocount;
! 656:
! 657: /*
! 658: * It's ok to have s uninitialized, but we dont want the compiler to
! 659: * complain about it.
! 660: */
! 661: s = (int)0xdeadbeef;
! 662:
! 663: /*
! 664: * Calculate max frames readable at once from the input buffer.
! 665: */
! 666: idata = abuf_rgetblk(ibuf, &icount, 0);
! 667: ifr = icount / ibuf->bpf;
! 668:
! 669: odata = abuf_wgetblk(obuf, &ocount, 0);
! 670: ofr = ocount / obuf->bpf;
! 671:
! 672: /*
! 673: * Partially copy structures into local variables, to avoid
! 674: * unnecessary indirections; this also allows the compiler to
! 675: * order local variables more "cache-friendly".
! 676: */
! 677: ictx = ist->ctx + ist->cmin;
! 678: octx = ist->ctx + ost->cmin;
! 679: inch = ist->nch;
! 680: ibps = ist->bps;
! 681: ibnext = ist->bnext;
! 682: isigbit = ist->sigbit;
! 683: ishift = ist->shift;
! 684: isnext = ist->snext;
! 685: ipos = ist->pos;
! 686: irate = ist->rate;
! 687: onch = ost->nch;
! 688: oshift = ost->shift;
! 689: osigbit = ost->sigbit;
! 690: obps = ost->bps;
! 691: obnext = ost->bnext;
! 692: osnext = ost->snext;
! 693: opos = ost->pos;
! 694: orate = ost->rate;
! 695:
! 696: /*
! 697: * Start conversion.
! 698: */
! 699: idata += ist->bfirst;
! 700: odata += ost->bfirst;
! 701: DPRINTFN(4, "conv_bcopy: ifr=%d ofr=%d\n", ifr, ofr);
! 702: for (;;) {
! 703: if ((int)(ipos - opos) > 0) {
! 704: if (ofr == 0)
! 705: break;
! 706: ctx = octx;
! 707: for (c = onch; c > 0; c--) {
! 708: s = *ctx++ << 16;
! 709: s >>= oshift;
! 710: s ^= osigbit;
! 711: for (i = obps; i > 0; i--) {
! 712: *odata = (unsigned char)s;
! 713: s >>= 8;
! 714: odata += obnext;
! 715: }
! 716: odata += osnext;
! 717: }
! 718: opos += irate;
! 719: ofr--;
! 720: } else {
! 721: if (ifr == 0)
! 722: break;
! 723: ctx = ictx;
! 724: for (c = inch; c > 0; c--) {
! 725: for (i = ibps; i > 0; i--) {
! 726: s <<= 8;
! 727: s |= *idata;
! 728: idata += ibnext;
! 729: }
! 730: s ^= isigbit;
! 731: s <<= ishift;
! 732: *ctx++ = (short)(s >> 16);
! 733: idata += isnext;
! 734: }
! 735: ipos += orate;
! 736: ifr--;
! 737: }
! 738: }
! 739: ist->pos = ipos;
! 740: ost->pos = opos;
! 741: DPRINTFN(4, "conv_bcopy: done, ifr=%d ofr=%d\n", ifr, ofr);
! 742:
! 743: /*
! 744: * Update FIFO pointers.
! 745: */
! 746: icount -= ifr * ist->bpf;
! 747: ibuf->used -= icount;
! 748: ibuf->start += icount;
! 749: if (ibuf->start >= ibuf->len)
! 750: ibuf->start -= ibuf->len;
! 751:
! 752: ocount -= ofr * ost->bpf;
! 753: obuf->used += ocount;
! 754: }
! 755:
! 756: void
! 757: conv_del(struct aproc *p)
! 758: {
! 759: aproc_del(p);
! 760: }
! 761:
! 762: int
! 763: conv_in(struct aproc *p, struct abuf *ibuf)
! 764: {
! 765: struct abuf *obuf = LIST_FIRST(&p->obuflist);
! 766:
! 767: if (!ABUF_WOK(obuf))
! 768: return 0;
! 769: conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
! 770: abuf_flush(obuf);
! 771: return ABUF_WOK(obuf);
! 772: }
! 773:
! 774: int
! 775: conv_out(struct aproc *p, struct abuf *obuf)
! 776: {
! 777: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
! 778:
! 779: if (!ABUF_ROK(ibuf))
! 780: return 0;
! 781: conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
! 782: if (ABUF_EOF(ibuf)) {
! 783: obuf->wproc = NULL;
! 784: abuf_hup(ibuf);
! 785: conv_del(p);
! 786: return 0;
! 787: }
! 788: abuf_fill(ibuf);
! 789: return 1;
! 790: }
! 791:
! 792: void
! 793: conv_eof(struct aproc *p, struct abuf *ibuf)
! 794: {
! 795: abuf_eof(LIST_FIRST(&p->obuflist));
! 796: conv_del(p);
! 797: }
! 798:
! 799: void
! 800: conv_hup(struct aproc *p, struct abuf *obuf)
! 801: {
! 802: abuf_hup(LIST_FIRST(&p->ibuflist));
! 803: conv_del(p);
! 804: }
! 805:
! 806: void
! 807: aconv_init(struct aconv *st, struct aparams *par, int input)
! 808: {
! 809: unsigned i;
! 810:
! 811: st->bps = par->bps;
! 812: st->sigbit = par->sig ? 0 : 1 << (par->bits - 1);
! 813: if (par->msb) {
! 814: st->shift = 32 - par->bps * 8;
! 815: } else {
! 816: st->shift = 32 - par->bits;
! 817: }
! 818: if ((par->le && input) || (!par->le && !input)) {
! 819: st->bfirst = st->bps - 1;
! 820: st->bnext = -1;
! 821: st->snext = 2 * st->bps;
! 822: } else {
! 823: st->bfirst = 0;
! 824: st->bnext = 1;
! 825: st->snext = 0;
! 826: }
! 827: st->cmin = par->cmin;
! 828: st->nch = par->cmax - par->cmin + 1;
! 829: st->bpf = st->nch * st->bps;
! 830: st->rate = par->rate;
! 831: st->pos = 0;
! 832:
! 833: for (i = 0; i < CHAN_MAX; i++)
! 834: st->ctx[i] = 0;
! 835: }
! 836:
! 837: struct aproc_ops conv_ops = {
! 838: "conv", conv_in, conv_out, conv_eof, conv_hup, NULL, NULL
! 839: };
! 840:
! 841: struct aproc *
! 842: conv_new(char *name, struct aparams *ipar, struct aparams *opar)
! 843: {
! 844: struct aproc *p;
! 845:
! 846: p = aproc_new(&conv_ops, name);
! 847: aconv_init(&p->u.conv.ist, ipar, 1);
! 848: aconv_init(&p->u.conv.ost, opar, 0);
! 849: return p;
! 850: }