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

Annotation of src/usr.bin/aucat/midi.c, Revision 1.8

1.8     ! ratchov     1: /*     $OpenBSD: midi.c,v 1.7 2009/08/27 06:31:13 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:  * TODO
                     19:  *
1.7       ratchov    20:  * use shadow variables (to save NRPNs, LSB of controller)
                     21:  * in the midi merger
1.1       ratchov    22:  *
                     23:  * make output and input identical when only one
                     24:  * input is used (fix running status)
                     25:  */
                     26: #include <stdio.h>
                     27: #include <stdlib.h>
                     28: #include <string.h>
                     29:
                     30: #include "abuf.h"
                     31: #include "aproc.h"
1.3       ratchov    32: #include "conf.h"
                     33: #include "dev.h"
1.1       ratchov    34: #include "midi.h"
                     35:
                     36: /*
                     37:  * input data rate is XFER / TIMO (in bytes per microsecond),
                     38:  * it must be slightly larger than the MIDI standard 3125 bytes/s
                     39:  */
                     40: #define MIDITHRU_XFER 340
                     41: #define MIDITHRU_TIMO 100000
                     42:
1.3       ratchov    43: /*
                     44:  * masks to extract command and channel of status byte
                     45:  */
                     46: #define MIDI_CMDMASK   0xf0
                     47: #define MIDI_CHANMASK  0x0f
                     48:
                     49: /*
                     50:  * MIDI status bytes of voice messages
                     51:  */
                     52: #define MIDI_NOFF      0x80            /* note off */
                     53: #define MIDI_NON       0x90            /* note on */
                     54: #define MIDI_KAT       0xa0            /* key after touch */
                     55: #define MIDI_CTL       0xb0            /* controller */
                     56: #define MIDI_PC                0xc0            /* program change */
                     57: #define MIDI_CAT       0xd0            /* channel after touch */
                     58: #define MIDI_BEND      0xe0            /* pitch bend */
                     59:
                     60: /*
                     61:  * MIDI controller numbers
                     62:  */
                     63: #define MIDI_CTLVOL    7               /* volume */
                     64: #define MIDI_CTLPAN    11              /* pan */
                     65:
                     66: /*
                     67:  * length of voice and common messages (status byte included)
                     68:  */
1.1       ratchov    69: unsigned voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
                     70: unsigned common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
                     71:
1.7       ratchov    72: /*
                     73:  * send the message stored in of ibuf->mdata to obuf
                     74:  */
1.1       ratchov    75: void
                     76: thru_flush(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
                     77: {
                     78:        unsigned ocount, itodo;
                     79:        unsigned char *odata, *idata;
                     80:
                     81:        itodo = ibuf->mused;
                     82:        idata = ibuf->mdata;
                     83:        DPRINTFN(4, "thru_flush: mused = %u\n", itodo);
                     84:        while (itodo > 0) {
                     85:                if (!ABUF_WOK(obuf)) {
                     86:                        abuf_rdiscard(obuf, obuf->used);
                     87:                        DPRINTFN(2, "thru_flush: discarded %u\n", obuf->used);
                     88:                        if (p->u.thru.owner == ibuf)
                     89:                                p->u.thru.owner = NULL;
                     90:                        return;
                     91:                }
                     92:                odata = abuf_wgetblk(obuf, &ocount, 0);
                     93:                if (ocount > itodo)
                     94:                        ocount = itodo;
                     95:                memcpy(odata, idata, ocount);
                     96:                abuf_wcommit(obuf, ocount);
                     97:                itodo -= ocount;
                     98:                idata += ocount;
                     99:        }
                    100:        ibuf->mused = 0;
                    101:        p->u.thru.owner = ibuf;
                    102: }
                    103:
1.7       ratchov   104: /*
                    105:  * send the real-time message (one byte) to obuf, similar to thrui_flush()
                    106:  */
1.1       ratchov   107: void
                    108: thru_rt(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned c)
                    109: {
                    110:        unsigned ocount;
                    111:        unsigned char *odata;
                    112:
                    113:        DPRINTFN(4, "thru_rt:\n");
                    114:        if (!ABUF_WOK(obuf)) {
                    115:                DPRINTFN(2, "thru_rt: discarded %u\n", obuf->used);
                    116:                abuf_rdiscard(obuf, obuf->used);
                    117:                if (p->u.thru.owner == ibuf)
                    118:                        p->u.thru.owner = NULL;
                    119:        }
                    120:        odata = abuf_wgetblk(obuf, &ocount, 0);
                    121:        odata[0] = c;
                    122:        abuf_wcommit(obuf, 1);
                    123: }
                    124:
1.7       ratchov   125: /*
                    126:  * parse ibuf contents and store each message into obuf,
                    127:  * use at most ``todo'' bytes (for throttling)
                    128:  */
1.1       ratchov   129: void
                    130: thru_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned todo)
                    131: {
                    132:        unsigned char *idata;
                    133:        unsigned c, icount, ioffs;
                    134:
                    135:        idata = NULL;
                    136:        icount = ioffs = 0;
                    137:        for (;;) {
                    138:                if (icount == 0) {
                    139:                        if (todo == 0)
                    140:                                break;
                    141:                        idata = abuf_rgetblk(ibuf, &icount, ioffs);
                    142:                        if (icount > todo)
                    143:                                icount = todo;
                    144:                        if (icount == 0)
                    145:                                break;
                    146:                        todo -= icount;
                    147:                        ioffs += icount;
                    148:                }
                    149:                c = *idata++;
                    150:                icount--;
                    151:                if (c < 0x80) {
                    152:                        if (ibuf->mindex == 0 && ibuf->mstatus) {
                    153:                                ibuf->mdata[ibuf->mused++] = ibuf->mstatus;
                    154:                                ibuf->mindex++;
                    155:                        }
                    156:                        ibuf->mdata[ibuf->mused++] = c;
                    157:                        ibuf->mindex++;
                    158:                        if (ibuf->mindex == ibuf->mlen) {
                    159:                                thru_flush(p, ibuf, obuf);
                    160:                                if (ibuf->mstatus >= 0xf0)
                    161:                                        ibuf->mstatus = 0;
                    162:                                ibuf->mindex = 0;
                    163:                        }
                    164:                        if (ibuf->mused == MDATA_NMAX) {
                    165:                                if (ibuf->mused == ibuf->mindex ||
                    166:                                    p->u.thru.owner == ibuf)
                    167:                                        thru_flush(p, ibuf, obuf);
                    168:                                else
                    169:                                        ibuf->mused = 0;
                    170:                        }
                    171:                } else if (c < 0xf8) {
                    172:                        if (ibuf->mused == ibuf->mindex ||
                    173:                            p->u.thru.owner == ibuf) {
                    174:                                thru_flush(p, ibuf, obuf);
                    175:                        } else
                    176:                                ibuf->mused = 0;
                    177:                        ibuf->mdata[0] = c;
                    178:                        ibuf->mused = 1;
                    179:                        ibuf->mlen = (c >= 0xf0) ?
                    180:                            common_len[c & 7] :
                    181:                            voice_len[(c >> 4) & 7];
                    182:                        if (ibuf->mlen == 1) {
                    183:                                thru_flush(p, ibuf, obuf);
                    184:                                ibuf->mindex = 0;
                    185:                                ibuf->mstatus = 0;
                    186:                                ibuf->mlen = 0;
                    187:                        } else {
                    188:                                ibuf->mstatus = c;
                    189:                                ibuf->mindex = 1;
                    190:                        }
                    191:                } else {
                    192:                        thru_rt(p, ibuf, obuf, c);
                    193:                }
                    194:        }
                    195: }
                    196:
                    197: int
                    198: thru_in(struct aproc *p, struct abuf *ibuf)
                    199: {
                    200:        struct abuf *i, *inext;
                    201:        unsigned todo;
                    202:
                    203:        DPRINTFN(3, "thru_in: %s\n", p->name);
                    204:
                    205:        if (!ABUF_ROK(ibuf))
                    206:                return 0;
                    207:        if (ibuf->mtickets == 0) {
                    208:                DPRINTFN(2, "thru_in: out of tickets\n");
                    209:                return 0;
                    210:        }
                    211:        todo = ibuf->used;
                    212:        if (todo > ibuf->mtickets)
                    213:                todo = ibuf->mtickets;
                    214:        ibuf->mtickets -= todo;
                    215:        for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
                    216:                inext = LIST_NEXT(i, oent);
                    217:                if (ibuf->duplex == i)
                    218:                        continue;
                    219:                thru_bcopy(p, ibuf, i, todo);
                    220:                (void)abuf_flush(i);
                    221:        }
                    222:        abuf_rdiscard(ibuf, todo);
                    223:        return 1;
                    224: }
                    225:
                    226: int
                    227: thru_out(struct aproc *p, struct abuf *obuf)
                    228: {
                    229:        return 0;
                    230: }
                    231:
                    232: void
                    233: thru_eof(struct aproc *p, struct abuf *ibuf)
                    234: {
                    235:        DPRINTF("thru_eof: %s: eof\n", p->name);
                    236: }
                    237:
                    238: void
                    239: thru_hup(struct aproc *p, struct abuf *obuf)
                    240: {
                    241:        DPRINTF("thru_hup: %s: detached\n", p->name);
                    242: }
                    243:
                    244: void
                    245: thru_newin(struct aproc *p, struct abuf *ibuf)
                    246: {
                    247:        ibuf->mused = 0;
                    248:        ibuf->mlen = 0;
                    249:        ibuf->mindex = 0;
                    250:        ibuf->mstatus = 0;
                    251:        ibuf->mtickets = MIDITHRU_XFER;
                    252: }
                    253:
                    254: void
                    255: thru_done(struct aproc *p)
                    256: {
                    257:        timo_del(&p->u.thru.timo);
                    258: }
                    259:
                    260: struct aproc_ops thru_ops = {
                    261:        "thru",
                    262:        thru_in,
                    263:        thru_out,
                    264:        thru_eof,
                    265:        thru_hup,
                    266:        thru_newin,
                    267:        NULL, /* newout */
                    268:        NULL, /* ipos */
                    269:        NULL, /* opos */
                    270:        thru_done
                    271: };
                    272:
1.7       ratchov   273: /*
                    274:  * call-back invoked periodically to implement throttling at each invocation
                    275:  * gain more ``tickets'' for processing.  If one of the buffer was blocked by
                    276:  * the throttelling mechanism, then run it
                    277:  */
1.1       ratchov   278: void
                    279: thru_cb(void *addr)
                    280: {
                    281:        struct aproc *p = (struct aproc *)addr;
                    282:        struct abuf *i, *inext;
                    283:        unsigned tickets;
                    284:
                    285:        timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
                    286:
                    287:        for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
                    288:                inext = LIST_NEXT(i, ient);
                    289:                tickets = i->mtickets;
                    290:                i->mtickets = MIDITHRU_XFER;
                    291:                if (tickets == 0)
                    292:                        abuf_run(i);
                    293:        }
                    294: }
                    295:
                    296: struct aproc *
                    297: thru_new(char *name)
                    298: {
                    299:        struct aproc *p;
                    300:
                    301:        p = aproc_new(&thru_ops, name);
                    302:        p->u.thru.owner = NULL;
                    303:        timo_set(&p->u.thru.timo, thru_cb, p);
                    304:        timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
1.3       ratchov   305:        return p;
                    306: }
                    307:
1.7       ratchov   308: /*
                    309:  * broadcast a message to all output buffers on the behalf of ibuf.
                    310:  * ie. don't sent back the message to the sender
                    311:  */
1.3       ratchov   312: void
                    313: ctl_sendmsg(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len)
                    314: {
                    315:        unsigned ocount, itodo;
                    316:        unsigned char *odata, *idata;
                    317:        struct abuf *i, *inext;
                    318:
                    319:        for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
                    320:                inext = LIST_NEXT(i, oent);
                    321:                if (i->duplex == ibuf)
                    322:                        continue;
                    323:                itodo = len;
                    324:                idata = msg;
                    325:                while (itodo > 0) {
                    326:                        if (!ABUF_WOK(i)) {
                    327:                                DPRINTFN(2, "ctl_sendmsg: lost %u\n", i->used);
                    328:                                abuf_rdiscard(i, i->used);
                    329:                        }
                    330:                        odata = abuf_wgetblk(i, &ocount, 0);
                    331:                        if (ocount > itodo)
                    332:                                ocount = itodo;
                    333:                        DPRINTFN(2, "ctl_sendmsg: xfer %u\n", ocount);
                    334:                        memcpy(odata, idata, ocount);
                    335:                        abuf_wcommit(i, ocount);
                    336:                        itodo -= ocount;
                    337:                        idata += ocount;
                    338:                }
                    339:                (void)abuf_flush(i);
                    340:        }
                    341: }
                    342:
1.7       ratchov   343: /*
                    344:  * allocate a new slot (ie midi channel), register the given call-back
                    345:  * to be called volume is changed by MIDI. The call-back is invoked at
                    346:  * initialization to restore the saved volume.
                    347:  */
1.3       ratchov   348: int
1.5       ratchov   349: ctl_slotnew(struct aproc *p, char *who, void (*cb)(void *, unsigned), void *arg)
1.3       ratchov   350: {
                    351:        char *s;
                    352:        struct ctl_slot *slot;
1.4       ratchov   353:        char name[CTL_NAMEMAX];
                    354:        unsigned i, unit, umap = 0;
1.6       ratchov   355:        unsigned ser, bestser, bestidx;
1.3       ratchov   356:
1.4       ratchov   357:        /*
                    358:         * create a ``valid'' control name (lowcase, remove [^a-z], trucate)
                    359:         */
1.5       ratchov   360:        for (i = 0, s = who; ; s++) {
1.4       ratchov   361:                if (i == CTL_NAMEMAX - 1 || *s == '\0') {
                    362:                        name[i] = '\0';
                    363:                        break;
                    364:                } else if (*s >= 'A' && *s <= 'Z') {
                    365:                        name[i++] = *s + 'a' - 'A';
                    366:                } else if (*s >= 'a' && *s <= 'z')
                    367:                        name[i++] = *s;
                    368:        }
                    369:        if (i == 0)
                    370:                strlcpy(name, "noname", CTL_NAMEMAX);
                    371:
                    372:        /*
                    373:         * find the instance number of the control name
                    374:         */
                    375:        for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.5       ratchov   376:                if (slot->cb == NULL)
1.4       ratchov   377:                        continue;
                    378:                if (strcmp(slot->name, name) == 0)
                    379:                        umap |= (1 << i);
                    380:        }
                    381:        for (unit = 0; unit < CTL_NSLOT; unit++) {
                    382:                if (unit == CTL_NSLOT)
1.3       ratchov   383:                        return -1;
1.4       ratchov   384:                if ((umap & (1 << i)) == 0)
1.3       ratchov   385:                        break;
                    386:        }
1.4       ratchov   387:
                    388:        DPRINTF("ctl_newslot: using %s%u as control name\n", name, unit);
                    389:
                    390:        /*
                    391:         * find a free controller slot with the same name/unit
                    392:         */
                    393:        for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.5       ratchov   394:                if (slot->cb == NULL &&
1.4       ratchov   395:                    strcmp(slot->name, name) == 0 &&
                    396:                    slot->unit == unit) {
1.7       ratchov   397:                        DPRINTFN(1, "ctl_newslot: reusing %u\n", i);
1.5       ratchov   398:                        slot->cb = cb;
                    399:                        slot->arg = arg;
1.7       ratchov   400:                        slot->cb(slot->arg, slot->vol);
                    401:                        ctl_slotvol(p, i, slot->vol);
1.4       ratchov   402:                        return i;
                    403:                }
                    404:        }
                    405:
                    406:        /*
1.6       ratchov   407:         * couldn't find a matching slot, pick oldest free slot
1.4       ratchov   408:         */
1.6       ratchov   409:        bestser = 0;
                    410:        bestidx = CTL_NSLOT;
                    411:        for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
                    412:                if (slot->cb != NULL)
                    413:                        continue;
                    414:                ser = p->u.ctl.serial - slot->serial;
                    415:                if (ser > bestser) {
                    416:                        bestser = ser;
                    417:                        bestidx = i;
                    418:                }
1.3       ratchov   419:        }
1.6       ratchov   420:        if (bestidx == CTL_NSLOT)
                    421:                return -1;
                    422:        slot = p->u.ctl.slot + bestidx;
1.4       ratchov   423:        strlcpy(slot->name, name, CTL_NAMEMAX);
1.6       ratchov   424:        slot->serial = p->u.ctl.serial++;
1.4       ratchov   425:        slot->unit = unit;
1.7       ratchov   426:        slot->vol = MIDI_MAXCTL;
                    427:        DPRINTFN(1, "ctl_newslot: %u overwritten)\n", bestidx);
1.5       ratchov   428:        slot->cb = cb;
                    429:        slot->arg = arg;
1.7       ratchov   430:        slot->cb(slot->arg, slot->vol);
                    431:        ctl_slotvol(p, bestidx, slot->vol);
1.6       ratchov   432:        return bestidx;
1.3       ratchov   433: }
                    434:
1.7       ratchov   435: /*
                    436:  * release the given slot
                    437:  */
1.3       ratchov   438: void
                    439: ctl_slotdel(struct aproc *p, int index)
                    440: {
1.5       ratchov   441:        p->u.ctl.slot[index].cb = NULL;
1.3       ratchov   442: }
                    443:
1.7       ratchov   444: /*
                    445:  * notifty the mixer that volume changed, called by whom allocad the slot using
                    446:  * ctl_slotnew(). Note: it doesn't make sens to call this from within the
                    447:  * call-back.
                    448:  */
1.3       ratchov   449: void
                    450: ctl_slotvol(struct aproc *p, int slot, unsigned vol)
                    451: {
                    452:        unsigned char msg[3];
                    453:
                    454:        DPRINTFN(1, "ctl_slotvol: [%u] -> %u\n", slot, vol);
1.7       ratchov   455:        p->u.ctl.slot[slot].vol = vol;
1.3       ratchov   456:        msg[0] = MIDI_CTL | slot;
                    457:        msg[1] = MIDI_CTLVOL;
                    458:        msg[2] = vol;
                    459:        ctl_sendmsg(p, NULL, msg, 3);
                    460: }
                    461:
1.7       ratchov   462: /*
                    463:  * handle a MIDI event received from ibuf
                    464:  */
1.3       ratchov   465: void
                    466: ctl_ev(struct aproc *p, struct abuf *ibuf)
                    467: {
                    468:        unsigned i;
                    469:        unsigned chan;
1.5       ratchov   470:        struct ctl_slot *slot;
1.3       ratchov   471:
                    472: #ifdef DEBUG
                    473:        if (debug_level > 0) {
                    474:                fprintf(stderr, "ctl_ev:");
1.8     ! ratchov   475:                for (i = 0; i < ibuf->mindex; i++)
1.3       ratchov   476:                        fprintf(stderr, " %02x", ibuf->mdata[i]);
                    477:                fprintf(stderr, "\n");
                    478:        }
                    479: #endif
                    480:        if ((ibuf->mdata[0] & MIDI_CMDMASK) == MIDI_CTL &&
                    481:            ibuf->mdata[1] == MIDI_CTLVOL) {
                    482:                chan = ibuf->mdata[0] & MIDI_CHANMASK;
                    483:                if (chan >= CTL_NSLOT)
                    484:                        return;
1.5       ratchov   485:                slot = p->u.ctl.slot + chan;
                    486:                if (slot->cb == NULL)
1.3       ratchov   487:                        return;
1.7       ratchov   488:                slot->vol = ibuf->mdata[2];
                    489:                slot->cb(slot->arg, slot->vol);
1.3       ratchov   490:                ctl_sendmsg(p, ibuf, ibuf->mdata, ibuf->mlen);
                    491:        }
                    492: }
                    493:
                    494: int
                    495: ctl_in(struct aproc *p, struct abuf *ibuf)
                    496: {
                    497:        unsigned char *idata;
                    498:        unsigned c, i, icount;
                    499:
                    500:        if (!ABUF_ROK(ibuf))
                    501:                return 0;
                    502:        idata = abuf_rgetblk(ibuf, &icount, 0);
                    503:        for (i = 0; i < icount; i++) {
                    504:                c = *idata++;
1.8     ! ratchov   505:                if (c >= 0xf8) {
        !           506:                        /* clock events not used yet */
        !           507:                } else if (c >= 0xf0) {
        !           508:                        if (ibuf->mstatus == 0xf0 && c == 0xf7 &&
        !           509:                            ibuf->mindex < MDATA_NMAX) {
        !           510:                                ibuf->mdata[ibuf->mindex++] = c;
        !           511:                                ctl_ev(p, ibuf);
        !           512:                                continue;
        !           513:                        }
        !           514:                        ibuf->mdata[0] = c;
        !           515:                        ibuf->mlen = common_len[c & 7];
        !           516:                        ibuf->mstatus = c;
        !           517:                        ibuf->mindex = 1;
1.3       ratchov   518:                } else if (c >= 0x80) {
                    519:                        ibuf->mdata[0] = c;
                    520:                        ibuf->mlen = voice_len[(c >> 4) & 7];
                    521:                        ibuf->mstatus = c;
                    522:                        ibuf->mindex = 1;
                    523:                } else if (ibuf->mstatus) {
1.8     ! ratchov   524:                        if (ibuf->mindex == MDATA_NMAX)
        !           525:                                continue;
1.3       ratchov   526:                        if (ibuf->mindex == 0)
                    527:                                ibuf->mdata[ibuf->mindex++] = ibuf->mstatus;
                    528:                        ibuf->mdata[ibuf->mindex++] = c;
                    529:                        if (ibuf->mindex == ibuf->mlen) {
                    530:                                ctl_ev(p, ibuf);
                    531:                                ibuf->mindex = 0;
                    532:                        }
                    533:                }
                    534:        }
                    535:        abuf_rdiscard(ibuf, icount);
                    536:        return 1;
                    537: }
                    538:
                    539: int
                    540: ctl_out(struct aproc *p, struct abuf *obuf)
                    541: {
                    542:        return 0;
                    543: }
                    544:
                    545: void
                    546: ctl_eof(struct aproc *p, struct abuf *ibuf)
                    547: {
                    548:        DPRINTF("ctl_eof: %s: eof\n", p->name);
                    549: }
                    550:
                    551: void
                    552: ctl_hup(struct aproc *p, struct abuf *obuf)
                    553: {
                    554:        DPRINTF("ctl_hup: %s: detached\n", p->name);
                    555: }
                    556:
                    557: void
                    558: ctl_newin(struct aproc *p, struct abuf *ibuf)
                    559: {
                    560:        ibuf->mused = 0;
                    561:        ibuf->mlen = 0;
                    562:        ibuf->mindex = 0;
                    563:        ibuf->mstatus = 0;
                    564: }
                    565:
                    566: void
                    567: ctl_done(struct aproc *p)
                    568: {
                    569:        unsigned i;
                    570:        struct ctl_slot *s;
                    571:
                    572:        for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
1.7       ratchov   573:                /*
                    574:                 * XXX: shouldn't we abord() here ?
                    575:                 */
1.5       ratchov   576:                if (s->cb != NULL)
1.6       ratchov   577:                        DPRINTF("ctl_done: %s%u in use\n", s->name, s->unit);
1.3       ratchov   578:        }
                    579: }
                    580:
                    581: struct aproc_ops ctl_ops = {
                    582:        "ctl",
                    583:        ctl_in,
                    584:        ctl_out,
                    585:        ctl_eof,
                    586:        ctl_hup,
                    587:        ctl_newin,
                    588:        NULL, /* newout */
                    589:        NULL, /* ipos */
                    590:        NULL, /* opos */
                    591:        ctl_done
                    592: };
                    593:
                    594: struct aproc *
                    595: ctl_new(char *name)
                    596: {
                    597:        struct aproc *p;
1.5       ratchov   598:        struct ctl_slot *s;
1.3       ratchov   599:        unsigned i;
                    600:
                    601:        p = aproc_new(&ctl_ops, name);
1.6       ratchov   602:        p->u.ctl.serial = 0;
1.5       ratchov   603:        for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
1.3       ratchov   604:                p->u.ctl.slot[i].unit = i;
1.5       ratchov   605:                p->u.ctl.slot[i].cb = NULL;
1.7       ratchov   606:                p->u.ctl.slot[i].vol = MIDI_MAXCTL;
1.6       ratchov   607:                p->u.ctl.slot[i].serial = p->u.ctl.serial++;
1.3       ratchov   608:                strlcpy(p->u.ctl.slot[i].name, "unknown", CTL_NAMEMAX);
                    609:        }
1.1       ratchov   610:        return p;
                    611: }
                    612: