[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.12

1.12    ! ratchov     1: /*     $OpenBSD: midi.c,v 1.11 2009/10/10 12:43:09 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: /*
1.10      ratchov    73:  * send the message stored in of ibuf->r.midi.msg to obuf
1.7       ratchov    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:
1.10      ratchov    81:        itodo = ibuf->r.midi.used;
                     82:        idata = ibuf->r.midi.msg;
1.1       ratchov    83:        while (itodo > 0) {
                     84:                if (!ABUF_WOK(obuf)) {
                     85:                        abuf_rdiscard(obuf, obuf->used);
                     86:                        if (p->u.thru.owner == ibuf)
                     87:                                p->u.thru.owner = NULL;
                     88:                        return;
                     89:                }
                     90:                odata = abuf_wgetblk(obuf, &ocount, 0);
                     91:                if (ocount > itodo)
                     92:                        ocount = itodo;
                     93:                memcpy(odata, idata, ocount);
                     94:                abuf_wcommit(obuf, ocount);
                     95:                itodo -= ocount;
                     96:                idata += ocount;
                     97:        }
1.10      ratchov    98:        ibuf->r.midi.used = 0;
1.1       ratchov    99:        p->u.thru.owner = ibuf;
                    100: }
                    101:
1.7       ratchov   102: /*
                    103:  * send the real-time message (one byte) to obuf, similar to thrui_flush()
                    104:  */
1.1       ratchov   105: void
                    106: thru_rt(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned c)
                    107: {
                    108:        unsigned ocount;
                    109:        unsigned char *odata;
                    110:
                    111:        if (!ABUF_WOK(obuf)) {
                    112:                abuf_rdiscard(obuf, obuf->used);
                    113:                if (p->u.thru.owner == ibuf)
                    114:                        p->u.thru.owner = NULL;
                    115:        }
                    116:        odata = abuf_wgetblk(obuf, &ocount, 0);
                    117:        odata[0] = c;
                    118:        abuf_wcommit(obuf, 1);
                    119: }
                    120:
1.7       ratchov   121: /*
                    122:  * parse ibuf contents and store each message into obuf,
                    123:  * use at most ``todo'' bytes (for throttling)
                    124:  */
1.1       ratchov   125: void
                    126: thru_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned todo)
                    127: {
                    128:        unsigned char *idata;
                    129:        unsigned c, icount, ioffs;
                    130:
                    131:        idata = NULL;
                    132:        icount = ioffs = 0;
                    133:        for (;;) {
                    134:                if (icount == 0) {
                    135:                        if (todo == 0)
                    136:                                break;
                    137:                        idata = abuf_rgetblk(ibuf, &icount, ioffs);
                    138:                        if (icount > todo)
                    139:                                icount = todo;
                    140:                        if (icount == 0)
                    141:                                break;
                    142:                        todo -= icount;
                    143:                        ioffs += icount;
                    144:                }
                    145:                c = *idata++;
                    146:                icount--;
                    147:                if (c < 0x80) {
1.10      ratchov   148:                        if (ibuf->r.midi.idx == 0 && ibuf->r.midi.st) {
                    149:                                ibuf->r.midi.msg[ibuf->r.midi.used++] = ibuf->r.midi.st;
                    150:                                ibuf->r.midi.idx++;
1.1       ratchov   151:                        }
1.10      ratchov   152:                        ibuf->r.midi.msg[ibuf->r.midi.used++] = c;
                    153:                        ibuf->r.midi.idx++;
                    154:                        if (ibuf->r.midi.idx == ibuf->r.midi.len) {
1.1       ratchov   155:                                thru_flush(p, ibuf, obuf);
1.10      ratchov   156:                                if (ibuf->r.midi.st >= 0xf0)
                    157:                                        ibuf->r.midi.st = 0;
                    158:                                ibuf->r.midi.idx = 0;
1.1       ratchov   159:                        }
1.10      ratchov   160:                        if (ibuf->r.midi.used == MIDI_MSGMAX) {
                    161:                                if (ibuf->r.midi.used == ibuf->r.midi.idx ||
1.1       ratchov   162:                                    p->u.thru.owner == ibuf)
                    163:                                        thru_flush(p, ibuf, obuf);
                    164:                                else
1.10      ratchov   165:                                        ibuf->r.midi.used = 0;
1.1       ratchov   166:                        }
                    167:                } else if (c < 0xf8) {
1.10      ratchov   168:                        if (ibuf->r.midi.used == ibuf->r.midi.idx ||
1.1       ratchov   169:                            p->u.thru.owner == ibuf) {
                    170:                                thru_flush(p, ibuf, obuf);
                    171:                        } else
1.10      ratchov   172:                                ibuf->r.midi.used = 0;
                    173:                        ibuf->r.midi.msg[0] = c;
                    174:                        ibuf->r.midi.used = 1;
                    175:                        ibuf->r.midi.len = (c >= 0xf0) ?
1.1       ratchov   176:                            common_len[c & 7] :
                    177:                            voice_len[(c >> 4) & 7];
1.10      ratchov   178:                        if (ibuf->r.midi.len == 1) {
1.1       ratchov   179:                                thru_flush(p, ibuf, obuf);
1.10      ratchov   180:                                ibuf->r.midi.idx = 0;
                    181:                                ibuf->r.midi.st = 0;
                    182:                                ibuf->r.midi.len = 0;
1.1       ratchov   183:                        } else {
1.10      ratchov   184:                                ibuf->r.midi.st = c;
                    185:                                ibuf->r.midi.idx = 1;
1.1       ratchov   186:                        }
                    187:                } else {
                    188:                        thru_rt(p, ibuf, obuf, c);
                    189:                }
                    190:        }
                    191: }
                    192:
                    193: int
                    194: thru_in(struct aproc *p, struct abuf *ibuf)
                    195: {
                    196:        struct abuf *i, *inext;
                    197:        unsigned todo;
                    198:
                    199:        if (!ABUF_ROK(ibuf))
                    200:                return 0;
1.10      ratchov   201:        if (ibuf->tickets == 0) {
1.1       ratchov   202:                return 0;
                    203:        }
                    204:        todo = ibuf->used;
1.10      ratchov   205:        if (todo > ibuf->tickets)
                    206:                todo = ibuf->tickets;
                    207:        ibuf->tickets -= todo;
1.1       ratchov   208:        for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
                    209:                inext = LIST_NEXT(i, oent);
                    210:                if (ibuf->duplex == i)
                    211:                        continue;
                    212:                thru_bcopy(p, ibuf, i, todo);
                    213:                (void)abuf_flush(i);
                    214:        }
                    215:        abuf_rdiscard(ibuf, todo);
                    216:        return 1;
                    217: }
                    218:
                    219: int
                    220: thru_out(struct aproc *p, struct abuf *obuf)
                    221: {
                    222:        return 0;
                    223: }
                    224:
                    225: void
                    226: thru_eof(struct aproc *p, struct abuf *ibuf)
                    227: {
1.11      ratchov   228:        if (!(p->u.thru.flags & THRU_AUTOQUIT))
                    229:                return;
                    230:        if (LIST_EMPTY(&p->obuflist) || LIST_EMPTY(&p->ibuflist))
                    231:                aproc_del(p);
1.1       ratchov   232: }
                    233:
                    234: void
                    235: thru_hup(struct aproc *p, struct abuf *obuf)
                    236: {
1.11      ratchov   237:        if (!(p->u.thru.flags & THRU_AUTOQUIT))
                    238:                return;
                    239:        if (LIST_EMPTY(&p->obuflist) || LIST_EMPTY(&p->ibuflist))
                    240:                aproc_del(p);
1.1       ratchov   241: }
                    242:
                    243: void
                    244: thru_newin(struct aproc *p, struct abuf *ibuf)
                    245: {
1.10      ratchov   246:        ibuf->r.midi.used = 0;
                    247:        ibuf->r.midi.len = 0;
                    248:        ibuf->r.midi.idx = 0;
                    249:        ibuf->r.midi.st = 0;
                    250:        ibuf->tickets = MIDITHRU_XFER;
1.1       ratchov   251: }
                    252:
                    253: void
                    254: thru_done(struct aproc *p)
                    255: {
                    256:        timo_del(&p->u.thru.timo);
                    257: }
                    258:
                    259: struct aproc_ops thru_ops = {
                    260:        "thru",
                    261:        thru_in,
                    262:        thru_out,
                    263:        thru_eof,
                    264:        thru_hup,
                    265:        thru_newin,
                    266:        NULL, /* newout */
                    267:        NULL, /* ipos */
                    268:        NULL, /* opos */
                    269:        thru_done
                    270: };
                    271:
1.7       ratchov   272: /*
                    273:  * call-back invoked periodically to implement throttling at each invocation
                    274:  * gain more ``tickets'' for processing.  If one of the buffer was blocked by
                    275:  * the throttelling mechanism, then run it
                    276:  */
1.1       ratchov   277: void
                    278: thru_cb(void *addr)
                    279: {
                    280:        struct aproc *p = (struct aproc *)addr;
                    281:        struct abuf *i, *inext;
                    282:        unsigned tickets;
                    283:
                    284:        timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
                    285:
                    286:        for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
                    287:                inext = LIST_NEXT(i, ient);
1.10      ratchov   288:                tickets = i->tickets;
                    289:                i->tickets = MIDITHRU_XFER;
1.1       ratchov   290:                if (tickets == 0)
                    291:                        abuf_run(i);
                    292:        }
                    293: }
                    294:
                    295: struct aproc *
                    296: thru_new(char *name)
                    297: {
                    298:        struct aproc *p;
                    299:
                    300:        p = aproc_new(&thru_ops, name);
                    301:        p->u.thru.owner = NULL;
                    302:        timo_set(&p->u.thru.timo, thru_cb, p);
                    303:        timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
1.3       ratchov   304:        return p;
                    305: }
                    306:
1.12    ! ratchov   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:                                abuf_rdiscard(i, i->used);
                    328:                        }
                    329:                        odata = abuf_wgetblk(i, &ocount, 0);
                    330:                        if (ocount > itodo)
                    331:                                ocount = itodo;
                    332:                        memcpy(odata, idata, ocount);
                    333:                        abuf_wcommit(i, ocount);
                    334:                        itodo -= ocount;
                    335:                        idata += ocount;
                    336:                }
                    337:                (void)abuf_flush(i);
                    338:        }
                    339: }
                    340:
1.7       ratchov   341: /*
1.12    ! ratchov   342:  * find the best matching free slot index (ie midi channel).
        !           343:  * return -1, if there are no free slots anymore
1.7       ratchov   344:  */
1.3       ratchov   345: int
1.12    ! ratchov   346: ctl_getidx(struct aproc *p, char *who)
1.3       ratchov   347: {
                    348:        char *s;
                    349:        struct ctl_slot *slot;
1.4       ratchov   350:        char name[CTL_NAMEMAX];
                    351:        unsigned i, unit, umap = 0;
1.6       ratchov   352:        unsigned ser, bestser, bestidx;
1.3       ratchov   353:
1.4       ratchov   354:        /*
                    355:         * create a ``valid'' control name (lowcase, remove [^a-z], trucate)
                    356:         */
1.5       ratchov   357:        for (i = 0, s = who; ; s++) {
1.4       ratchov   358:                if (i == CTL_NAMEMAX - 1 || *s == '\0') {
                    359:                        name[i] = '\0';
                    360:                        break;
                    361:                } else if (*s >= 'A' && *s <= 'Z') {
                    362:                        name[i++] = *s + 'a' - 'A';
                    363:                } else if (*s >= 'a' && *s <= 'z')
                    364:                        name[i++] = *s;
                    365:        }
                    366:        if (i == 0)
                    367:                strlcpy(name, "noname", CTL_NAMEMAX);
                    368:
                    369:        /*
                    370:         * find the instance number of the control name
                    371:         */
                    372:        for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.12    ! ratchov   373:                if (slot->ops == NULL)
1.4       ratchov   374:                        continue;
                    375:                if (strcmp(slot->name, name) == 0)
                    376:                        umap |= (1 << i);
                    377:        }
1.12    ! ratchov   378:        for (unit = 0; ; unit++) {
1.4       ratchov   379:                if (unit == CTL_NSLOT)
1.3       ratchov   380:                        return -1;
1.12    ! ratchov   381:                if ((umap & (1 << unit)) == 0)
1.3       ratchov   382:                        break;
                    383:        }
1.4       ratchov   384:        /*
                    385:         * find a free controller slot with the same name/unit
                    386:         */
                    387:        for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.12    ! ratchov   388:                if (slot->ops == NULL &&
1.4       ratchov   389:                    strcmp(slot->name, name) == 0 &&
                    390:                    slot->unit == unit) {
                    391:                        return i;
                    392:                }
                    393:        }
                    394:
                    395:        /*
1.6       ratchov   396:         * couldn't find a matching slot, pick oldest free slot
1.12    ! ratchov   397:         * and set its name/unit
1.4       ratchov   398:         */
1.6       ratchov   399:        bestser = 0;
                    400:        bestidx = CTL_NSLOT;
                    401:        for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.12    ! ratchov   402:                if (slot->ops != NULL)
1.6       ratchov   403:                        continue;
                    404:                ser = p->u.ctl.serial - slot->serial;
                    405:                if (ser > bestser) {
                    406:                        bestser = ser;
                    407:                        bestidx = i;
                    408:                }
1.3       ratchov   409:        }
1.6       ratchov   410:        if (bestidx == CTL_NSLOT)
                    411:                return -1;
                    412:        slot = p->u.ctl.slot + bestidx;
1.4       ratchov   413:        strlcpy(slot->name, name, CTL_NAMEMAX);
1.6       ratchov   414:        slot->serial = p->u.ctl.serial++;
1.4       ratchov   415:        slot->unit = unit;
1.7       ratchov   416:        slot->vol = MIDI_MAXCTL;
1.6       ratchov   417:        return bestidx;
1.3       ratchov   418: }
                    419:
1.7       ratchov   420: /*
1.12    ! ratchov   421:  * allocate a new slot and register the given call-backs
        !           422:  */
        !           423: int
        !           424: ctl_slotnew(struct aproc *p, char *who, struct ctl_ops *ops, void *arg)
        !           425: {
        !           426:        int idx;
        !           427:        struct ctl_slot *s;
        !           428:
        !           429:        idx = ctl_getidx(p, who);
        !           430:        if (idx < 0)
        !           431:                return -1;
        !           432:
        !           433:        s = p->u.ctl.slot + idx;
        !           434:        s->ops = ops;
        !           435:        s->arg = arg;
        !           436:        s->ops->vol(s->arg, s->vol);
        !           437:        ctl_slotvol(p, idx, s->vol);
        !           438:        return idx;
        !           439: }
        !           440:
        !           441: /*
1.7       ratchov   442:  * release the given slot
                    443:  */
1.3       ratchov   444: void
                    445: ctl_slotdel(struct aproc *p, int index)
                    446: {
1.12    ! ratchov   447:        p->u.ctl.slot[index].ops = NULL;
1.3       ratchov   448: }
                    449:
1.7       ratchov   450: /*
                    451:  * notifty the mixer that volume changed, called by whom allocad the slot using
                    452:  * ctl_slotnew(). Note: it doesn't make sens to call this from within the
                    453:  * call-back.
                    454:  */
1.3       ratchov   455: void
                    456: ctl_slotvol(struct aproc *p, int slot, unsigned vol)
                    457: {
                    458:        unsigned char msg[3];
                    459:
1.7       ratchov   460:        p->u.ctl.slot[slot].vol = vol;
1.3       ratchov   461:        msg[0] = MIDI_CTL | slot;
                    462:        msg[1] = MIDI_CTLVOL;
                    463:        msg[2] = vol;
                    464:        ctl_sendmsg(p, NULL, msg, 3);
                    465: }
                    466:
1.7       ratchov   467: /*
                    468:  * handle a MIDI event received from ibuf
                    469:  */
1.3       ratchov   470: void
                    471: ctl_ev(struct aproc *p, struct abuf *ibuf)
                    472: {
                    473:        unsigned chan;
1.5       ratchov   474:        struct ctl_slot *slot;
1.10      ratchov   475:        if ((ibuf->r.midi.msg[0] & MIDI_CMDMASK) == MIDI_CTL &&
                    476:            ibuf->r.midi.msg[1] == MIDI_CTLVOL) {
                    477:                chan = ibuf->r.midi.msg[0] & MIDI_CHANMASK;
1.3       ratchov   478:                if (chan >= CTL_NSLOT)
                    479:                        return;
1.5       ratchov   480:                slot = p->u.ctl.slot + chan;
1.12    ! ratchov   481:                if (slot->ops == NULL)
1.3       ratchov   482:                        return;
1.10      ratchov   483:                slot->vol = ibuf->r.midi.msg[2];
1.12    ! ratchov   484:                slot->ops->vol(slot->arg, slot->vol);
1.10      ratchov   485:                ctl_sendmsg(p, ibuf, ibuf->r.midi.msg, ibuf->r.midi.len);
1.3       ratchov   486:        }
                    487: }
                    488:
                    489: int
                    490: ctl_in(struct aproc *p, struct abuf *ibuf)
                    491: {
                    492:        unsigned char *idata;
                    493:        unsigned c, i, icount;
                    494:
                    495:        if (!ABUF_ROK(ibuf))
                    496:                return 0;
                    497:        idata = abuf_rgetblk(ibuf, &icount, 0);
                    498:        for (i = 0; i < icount; i++) {
                    499:                c = *idata++;
1.8       ratchov   500:                if (c >= 0xf8) {
                    501:                        /* clock events not used yet */
                    502:                } else if (c >= 0xf0) {
1.10      ratchov   503:                        if (ibuf->r.midi.st == 0xf0 && c == 0xf7 &&
                    504:                            ibuf->r.midi.idx < MIDI_MSGMAX) {
                    505:                                ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
1.8       ratchov   506:                                ctl_ev(p, ibuf);
                    507:                                continue;
                    508:                        }
1.10      ratchov   509:                        ibuf->r.midi.msg[0] = c;
                    510:                        ibuf->r.midi.len = common_len[c & 7];
                    511:                        ibuf->r.midi.st = c;
                    512:                        ibuf->r.midi.idx = 1;
1.3       ratchov   513:                } else if (c >= 0x80) {
1.10      ratchov   514:                        ibuf->r.midi.msg[0] = c;
                    515:                        ibuf->r.midi.len = voice_len[(c >> 4) & 7];
                    516:                        ibuf->r.midi.st = c;
                    517:                        ibuf->r.midi.idx = 1;
                    518:                } else if (ibuf->r.midi.st) {
                    519:                        if (ibuf->r.midi.idx == MIDI_MSGMAX)
1.8       ratchov   520:                                continue;
1.10      ratchov   521:                        if (ibuf->r.midi.idx == 0)
                    522:                                ibuf->r.midi.msg[ibuf->r.midi.idx++] = ibuf->r.midi.st;
                    523:                        ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
                    524:                        if (ibuf->r.midi.idx == ibuf->r.midi.len) {
1.3       ratchov   525:                                ctl_ev(p, ibuf);
1.10      ratchov   526:                                ibuf->r.midi.idx = 0;
1.3       ratchov   527:                        }
                    528:                }
                    529:        }
                    530:        abuf_rdiscard(ibuf, icount);
                    531:        return 1;
                    532: }
                    533:
                    534: int
                    535: ctl_out(struct aproc *p, struct abuf *obuf)
                    536: {
                    537:        return 0;
                    538: }
                    539:
                    540: void
                    541: ctl_eof(struct aproc *p, struct abuf *ibuf)
                    542: {
                    543: }
                    544:
                    545: void
                    546: ctl_hup(struct aproc *p, struct abuf *obuf)
                    547: {
                    548: }
                    549:
                    550: void
                    551: ctl_newin(struct aproc *p, struct abuf *ibuf)
                    552: {
1.10      ratchov   553:        ibuf->r.midi.used = 0;
                    554:        ibuf->r.midi.len = 0;
                    555:        ibuf->r.midi.idx = 0;
                    556:        ibuf->r.midi.st = 0;
1.3       ratchov   557: }
                    558:
                    559: void
                    560: ctl_done(struct aproc *p)
                    561: {
                    562: }
                    563:
                    564: struct aproc_ops ctl_ops = {
                    565:        "ctl",
                    566:        ctl_in,
                    567:        ctl_out,
                    568:        ctl_eof,
                    569:        ctl_hup,
                    570:        ctl_newin,
                    571:        NULL, /* newout */
                    572:        NULL, /* ipos */
                    573:        NULL, /* opos */
                    574:        ctl_done
                    575: };
                    576:
                    577: struct aproc *
                    578: ctl_new(char *name)
                    579: {
                    580:        struct aproc *p;
1.5       ratchov   581:        struct ctl_slot *s;
1.3       ratchov   582:        unsigned i;
                    583:
                    584:        p = aproc_new(&ctl_ops, name);
1.6       ratchov   585:        p->u.ctl.serial = 0;
1.5       ratchov   586:        for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
1.3       ratchov   587:                p->u.ctl.slot[i].unit = i;
1.12    ! ratchov   588:                p->u.ctl.slot[i].ops = NULL;
1.7       ratchov   589:                p->u.ctl.slot[i].vol = MIDI_MAXCTL;
1.6       ratchov   590:                p->u.ctl.slot[i].serial = p->u.ctl.serial++;
1.3       ratchov   591:                strlcpy(p->u.ctl.slot[i].name, "unknown", CTL_NAMEMAX);
                    592:        }
1.1       ratchov   593:        return p;
                    594: }
                    595: