[BACK]Return to aproc.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / aucat

Annotation of src/usr.bin/aucat/aproc.c, Revision 1.10

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