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

1.40    ! ratchov     1: /*     $OpenBSD: midi.c,v 1.39 2011/11/20 22:54: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:  * 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: #include <stdio.h>
                     24: #include <stdlib.h>
                     25: #include <string.h>
                     26:
                     27: #include "abuf.h"
                     28: #include "aproc.h"
1.3       ratchov    29: #include "conf.h"
                     30: #include "dev.h"
1.1       ratchov    31: #include "midi.h"
1.33      ratchov    32: #include "sysex.h"
1.14      ratchov    33: #ifdef DEBUG
                     34: #include "dbg.h"
                     35: #endif
1.1       ratchov    36:
                     37: /*
                     38:  * input data rate is XFER / TIMO (in bytes per microsecond),
                     39:  * it must be slightly larger than the MIDI standard 3125 bytes/s
                     40:  */
                     41: #define MIDITHRU_XFER 340
                     42: #define MIDITHRU_TIMO 100000
                     43:
1.3       ratchov    44: /*
                     45:  * masks to extract command and channel of status byte
                     46:  */
                     47: #define MIDI_CMDMASK   0xf0
                     48: #define MIDI_CHANMASK  0x0f
                     49:
                     50: /*
                     51:  * MIDI status bytes of voice messages
                     52:  */
                     53: #define MIDI_NOFF      0x80            /* note off */
                     54: #define MIDI_NON       0x90            /* note on */
                     55: #define MIDI_KAT       0xa0            /* key after touch */
                     56: #define MIDI_CTL       0xb0            /* controller */
                     57: #define MIDI_PC                0xc0            /* program change */
                     58: #define MIDI_CAT       0xd0            /* channel after touch */
                     59: #define MIDI_BEND      0xe0            /* pitch bend */
1.16      ratchov    60: #define MIDI_ACK       0xfe            /* active sensing message */
1.3       ratchov    61:
                     62: /*
                     63:  * MIDI controller numbers
                     64:  */
                     65: #define MIDI_CTLVOL    7               /* volume */
                     66: #define MIDI_CTLPAN    11              /* pan */
                     67:
                     68: /*
                     69:  * length of voice and common messages (status byte included)
                     70:  */
1.1       ratchov    71: unsigned voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
                     72: unsigned common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
                     73:
1.7       ratchov    74: /*
1.40    ! ratchov    75:  * call-back invoked periodically to implement throttling; at each invocation
1.7       ratchov    76:  * gain more ``tickets'' for processing.  If one of the buffer was blocked by
                     77:  * the throttelling mechanism, then run it
                     78:  */
1.1       ratchov    79: void
1.40    ! ratchov    80: midi_cb(void *addr)
1.1       ratchov    81: {
                     82:        struct aproc *p = (struct aproc *)addr;
                     83:        struct abuf *i, *inext;
                     84:        unsigned tickets;
                     85:
1.40    ! ratchov    86:        timo_add(&p->u.midi.timo, MIDITHRU_TIMO);
1.1       ratchov    87:
1.20      ratchov    88:        for (i = LIST_FIRST(&p->ins); i != NULL; i = inext) {
1.1       ratchov    89:                inext = LIST_NEXT(i, ient);
1.10      ratchov    90:                tickets = i->tickets;
                     91:                i->tickets = MIDITHRU_XFER;
1.1       ratchov    92:                if (tickets == 0)
                     93:                        abuf_run(i);
                     94:        }
                     95: }
                     96:
1.40    ! ratchov    97: void
        !            98: midi_msg_info(struct aproc *p, int slot, char *msg)
        !            99: {
        !           100:        struct ctl_slot *s;
        !           101:        struct sysex *x = (struct sysex *)msg;
        !           102:
        !           103:        s = p->u.midi.dev->slot + slot;
        !           104:        memset(x, 0, sizeof(struct sysex));
        !           105:        x->start = SYSEX_START;
        !           106:        x->type = SYSEX_TYPE_EDU;
        !           107:        x->id0 = SYSEX_AUCAT;
        !           108:        x->id1 = SYSEX_AUCAT_MIXINFO;
        !           109:        if (*s->name != '\0') {
        !           110:                snprintf(x->u.mixinfo.name,
        !           111:                    SYSEX_NAMELEN, "%s%u", s->name, s->unit);
        !           112:        }
        !           113:        x->u.mixinfo.chan = slot;
        !           114:        x->u.mixinfo.end = SYSEX_END;
        !           115: }
        !           116:
        !           117: void
        !           118: midi_msg_vol(struct aproc *p, int slot, char *msg)
1.1       ratchov   119: {
1.40    ! ratchov   120:        struct ctl_slot *s;
1.1       ratchov   121:
1.40    ! ratchov   122:        s = p->u.midi.dev->slot + slot;
        !           123:        msg[0] = MIDI_CTL | slot;
        !           124:        msg[1] = MIDI_CTLVOL;
        !           125:        msg[2] = s->vol;
1.3       ratchov   126: }
                    127:
1.7       ratchov   128: /*
1.33      ratchov   129:  * send a message to the given output
                    130:  */
                    131: void
1.40    ! ratchov   132: midi_copy(struct abuf *ibuf, struct abuf *obuf, unsigned char *msg, unsigned len)
1.33      ratchov   133: {
1.40    ! ratchov   134:        unsigned ocount;
        !           135:        unsigned char *odata;
1.33      ratchov   136:
1.40    ! ratchov   137:        if (msg[0] == SYSEX_START)
        !           138:                obuf->w.midi.owner = ibuf;
        !           139:        while (len > 0) {
1.33      ratchov   140:                if (!ABUF_WOK(obuf)) {
                    141: #ifdef DEBUG
                    142:                        if (debug_level >= 3) {
                    143:                                abuf_dbg(obuf);
                    144:                                dbg_puts(": overrun, discarding ");
                    145:                                dbg_putu(obuf->used);
                    146:                                dbg_puts(" bytes\n");
                    147:                        }
                    148: #endif
                    149:                        abuf_rdiscard(obuf, obuf->used);
1.40    ! ratchov   150:                        if (obuf->w.midi.owner == ibuf)
        !           151:                                obuf->w.midi.owner = NULL;
        !           152:                        return;
1.33      ratchov   153:                }
                    154:                odata = abuf_wgetblk(obuf, &ocount, 0);
1.40    ! ratchov   155:                if (ocount > len)
        !           156:                        ocount = len;
1.33      ratchov   157: #ifdef DEBUG
                    158:                if (debug_level >= 4) {
                    159:                        abuf_dbg(obuf);
                    160:                        dbg_puts(": stored ");
                    161:                        dbg_putu(ocount);
                    162:                        dbg_puts(" bytes\n");
                    163:                }
                    164: #endif
1.40    ! ratchov   165:                memcpy(odata, msg, ocount);
1.33      ratchov   166:                abuf_wcommit(obuf, ocount);
1.40    ! ratchov   167:                len -= ocount;
        !           168:                msg += ocount;
        !           169:        }
        !           170: }
        !           171:
        !           172: /*
        !           173:  * flush all buffers. Since most of the MIDI traffic is broadcasted to
        !           174:  * all outputs, the flush is delayed to avoid flushing all outputs for
        !           175:  * each message.
        !           176:  */
        !           177: void
        !           178: midi_flush(struct aproc *p)
        !           179: {
        !           180:        struct abuf *i, *inext;
        !           181:
        !           182:        for (i = LIST_FIRST(&p->outs); i != NULL; i = inext) {
        !           183:                inext = LIST_NEXT(i, oent);
        !           184:                if (ABUF_ROK(i))
        !           185:                        (void)abuf_flush(i);
1.33      ratchov   186:        }
                    187: }
                    188:
                    189: /*
1.7       ratchov   190:  * broadcast a message to all output buffers on the behalf of ibuf.
                    191:  * ie. don't sent back the message to the sender
                    192:  */
1.3       ratchov   193: void
1.40    ! ratchov   194: midi_send(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len)
1.3       ratchov   195: {
                    196:        struct abuf *i, *inext;
                    197:
1.20      ratchov   198:        for (i = LIST_FIRST(&p->outs); i != NULL; i = inext) {
1.3       ratchov   199:                inext = LIST_NEXT(i, oent);
1.19      ratchov   200:                if (i->duplex && i->duplex == ibuf)
1.3       ratchov   201:                        continue;
1.40    ! ratchov   202:                midi_copy(ibuf, i, msg, len);
1.3       ratchov   203:        }
                    204: }
                    205:
1.7       ratchov   206: /*
1.13      ratchov   207:  * send a quarter frame MTC message
                    208:  */
                    209: void
1.40    ! ratchov   210: midi_send_qfr(struct aproc *p, unsigned rate, int delta)
1.13      ratchov   211: {
                    212:        unsigned char buf[2];
                    213:        unsigned data;
1.39      ratchov   214:        int qfrlen;
                    215:
1.40    ! ratchov   216:        p->u.midi.delta += delta * MTC_SEC;
        !           217:        qfrlen = rate * (MTC_SEC / (4 * p->u.midi.fps));
        !           218:        while (p->u.midi.delta >= qfrlen) {
        !           219:                switch (p->u.midi.qfr) {
1.39      ratchov   220:                case 0:
1.40    ! ratchov   221:                        data = p->u.midi.fr & 0xf;
1.39      ratchov   222:                        break;
                    223:                case 1:
1.40    ! ratchov   224:                        data = p->u.midi.fr >> 4;
1.39      ratchov   225:                        break;
                    226:                case 2:
1.40    ! ratchov   227:                        data = p->u.midi.sec & 0xf;
1.39      ratchov   228:                        break;
                    229:                case 3:
1.40    ! ratchov   230:                        data = p->u.midi.sec >> 4;
1.39      ratchov   231:                        break;
                    232:                case 4:
1.40    ! ratchov   233:                        data = p->u.midi.min & 0xf;
1.39      ratchov   234:                        break;
                    235:                case 5:
1.40    ! ratchov   236:                        data = p->u.midi.min >> 4;
1.39      ratchov   237:                        break;
                    238:                case 6:
1.40    ! ratchov   239:                        data = p->u.midi.hr & 0xf;
1.39      ratchov   240:                        break;
                    241:                case 7:
1.40    ! ratchov   242:                        data = (p->u.midi.hr >> 4) | (p->u.midi.fps_id << 1);
1.39      ratchov   243:                        /*
                    244:                         * tick messages are sent 2 frames ahead
                    245:                         */
1.40    ! ratchov   246:                        p->u.midi.fr += 2;
        !           247:                        if (p->u.midi.fr < p->u.midi.fps)
1.39      ratchov   248:                                break;
1.40    ! ratchov   249:                        p->u.midi.fr -= p->u.midi.fps;
        !           250:                        p->u.midi.sec++;
        !           251:                        if (p->u.midi.sec < 60)
1.39      ratchov   252:                                break;
1.40    ! ratchov   253:                        p->u.midi.sec = 0;
        !           254:                        p->u.midi.min++;
        !           255:                        if (p->u.midi.min < 60)
1.39      ratchov   256:                                break;
1.40    ! ratchov   257:                        p->u.midi.min = 0;
        !           258:                        p->u.midi.hr++;
        !           259:                        if (p->u.midi.hr < 24)
1.39      ratchov   260:                                break;
1.40    ! ratchov   261:                        p->u.midi.hr = 0;
1.13      ratchov   262:                        break;
1.39      ratchov   263:                default:
                    264:                        /* NOTREACHED */
                    265:                        data = 0;
                    266:                }
                    267:                buf[0] = 0xf1;
1.40    ! ratchov   268:                buf[1] = (p->u.midi.qfr << 4) | data;
        !           269:                p->u.midi.qfr++;
        !           270:                p->u.midi.qfr &= 7;
        !           271:                midi_send(p, NULL, buf, 2);
        !           272:                p->u.midi.delta -= qfrlen;
1.13      ratchov   273:        }
                    274: }
                    275:
                    276: /*
                    277:  * send a full frame MTC message
                    278:  */
                    279: void
1.40    ! ratchov   280: midi_send_full(struct aproc *p, unsigned origin, unsigned rate, unsigned round, unsigned pos)
1.13      ratchov   281: {
                    282:        unsigned char buf[10];
1.39      ratchov   283:        unsigned fps;
1.13      ratchov   284:
1.40    ! ratchov   285:        p->u.midi.delta = MTC_SEC * pos;
1.39      ratchov   286:        if (rate % (30 * 4 * round) == 0) {
1.40    ! ratchov   287:                p->u.midi.fps_id = MTC_FPS_30;
        !           288:                p->u.midi.fps = 30;
1.39      ratchov   289:        } else if (rate % (25 * 4 * round) == 0) {
1.40    ! ratchov   290:                p->u.midi.fps_id = MTC_FPS_25;
        !           291:                p->u.midi.fps = 25;
1.39      ratchov   292:        } else {
1.40    ! ratchov   293:                p->u.midi.fps_id = MTC_FPS_24;
        !           294:                p->u.midi.fps = 24;
1.39      ratchov   295:        }
                    296: #ifdef DEBUG
                    297:        if (debug_level >= 3) {
                    298:                aproc_dbg(p);
                    299:                dbg_puts(": mtc full frame at ");
1.40    ! ratchov   300:                dbg_puti(p->u.midi.delta);
1.39      ratchov   301:                dbg_puts(", ");
1.40    ! ratchov   302:                dbg_puti(p->u.midi.fps);
1.39      ratchov   303:                dbg_puts(" fps\n");
                    304:        }
                    305: #endif
1.40    ! ratchov   306:        fps = p->u.midi.fps;
        !           307:        p->u.midi.hr =  (origin / (3600 * MTC_SEC)) % 24;
        !           308:        p->u.midi.min = (origin / (60 * MTC_SEC))   % 60;
        !           309:        p->u.midi.sec = (origin / MTC_SEC)          % 60;
        !           310:        p->u.midi.fr =  (origin / (MTC_SEC / fps))  % fps;
1.13      ratchov   311:
                    312:        buf[0] = 0xf0;
                    313:        buf[1] = 0x7f;
                    314:        buf[2] = 0x7f;
                    315:        buf[3] = 0x01;
                    316:        buf[4] = 0x01;
1.40    ! ratchov   317:        buf[5] = p->u.midi.hr | (p->u.midi.fps_id << 5);
        !           318:        buf[6] = p->u.midi.min;
        !           319:        buf[7] = p->u.midi.sec;
        !           320:        buf[8] = p->u.midi.fr;
1.13      ratchov   321:        buf[9] = 0xf7;
1.40    ! ratchov   322:        p->u.midi.qfr = 0;
        !           323:        midi_send(p, NULL, buf, 10);
1.13      ratchov   324: }
                    325:
1.33      ratchov   326: void
1.40    ! ratchov   327: midi_copy_dump(struct aproc *p, struct abuf *obuf)
1.35      ratchov   328: {
                    329:        unsigned i;
                    330:        unsigned char msg[sizeof(struct sysex)];
                    331:        struct ctl_slot *s;
                    332:
1.40    ! ratchov   333:        for (i = 0, s = p->u.midi.dev->slot; i < CTL_NSLOT; i++, s++) {
        !           334:                midi_msg_info(p, i, msg);
        !           335:                midi_copy(NULL, obuf, msg, SYSEX_SIZE(mixinfo));
        !           336:                midi_msg_vol(p, i, msg);
        !           337:                midi_copy(NULL, obuf, msg, 3);
1.35      ratchov   338:        }
                    339:        msg[0] = SYSEX_START;
                    340:        msg[1] = SYSEX_TYPE_EDU;
                    341:        msg[2] = 0;
                    342:        msg[3] = SYSEX_AUCAT;
                    343:        msg[4] = SYSEX_AUCAT_DUMPEND;
                    344:        msg[5] = SYSEX_END;
1.40    ! ratchov   345:        midi_copy(NULL, obuf, msg, 6);
1.35      ratchov   346: }
                    347:
1.13      ratchov   348: /*
1.7       ratchov   349:  * notifty the mixer that volume changed, called by whom allocad the slot using
                    350:  * ctl_slotnew(). Note: it doesn't make sens to call this from within the
                    351:  * call-back.
                    352:  */
1.3       ratchov   353: void
1.40    ! ratchov   354: midi_send_vol(struct aproc *p, int slot, unsigned vol)
1.3       ratchov   355: {
                    356:        unsigned char msg[3];
                    357:
1.40    ! ratchov   358:        midi_msg_vol(p, slot, msg);
        !           359:        midi_send(p, NULL, msg, 3);
1.3       ratchov   360: }
                    361:
1.13      ratchov   362: void
1.40    ! ratchov   363: midi_send_slot(struct aproc *p, int slot)
1.13      ratchov   364: {
1.39      ratchov   365:        unsigned char msg[sizeof(struct sysex)];
1.13      ratchov   366:
1.40    ! ratchov   367:        midi_msg_info(p, slot, msg);
        !           368:        midi_send(p, NULL, msg, SYSEX_SIZE(mixinfo));
1.19      ratchov   369: }
                    370:
                    371: /*
1.40    ! ratchov   372:  * handle a MIDI voice event received from ibuf
1.7       ratchov   373:  */
1.3       ratchov   374: void
1.40    ! ratchov   375: midi_onvoice(struct aproc *p, struct abuf *ibuf)
1.3       ratchov   376: {
1.40    ! ratchov   377:        struct ctl_slot *slot;
1.3       ratchov   378:        unsigned chan;
1.14      ratchov   379: #ifdef DEBUG
                    380:        unsigned i;
                    381:
                    382:        if (debug_level >= 3) {
                    383:                abuf_dbg(ibuf);
1.40    ! ratchov   384:                dbg_puts(": got voice event:");
1.14      ratchov   385:                for (i = 0; i < ibuf->r.midi.idx; i++) {
                    386:                        dbg_puts(" ");
                    387:                        dbg_putx(ibuf->r.midi.msg[i]);
                    388:                }
                    389:                dbg_puts("\n");
                    390:        }
                    391: #endif
1.10      ratchov   392:        if ((ibuf->r.midi.msg[0] & MIDI_CMDMASK) == MIDI_CTL &&
1.33      ratchov   393:            (ibuf->r.midi.msg[1] == MIDI_CTLVOL)) {
1.10      ratchov   394:                chan = ibuf->r.midi.msg[0] & MIDI_CHANMASK;
1.3       ratchov   395:                if (chan >= CTL_NSLOT)
                    396:                        return;
1.40    ! ratchov   397:                slot = p->u.midi.dev->slot + chan;
1.22      ratchov   398:                slot->vol = ibuf->r.midi.msg[2];
1.12      ratchov   399:                if (slot->ops == NULL)
1.3       ratchov   400:                        return;
1.12      ratchov   401:                slot->ops->vol(slot->arg, slot->vol);
1.3       ratchov   402:        }
1.40    ! ratchov   403: }
        !           404:
        !           405: /*
        !           406:  * handle a MIDI sysex received from ibuf
        !           407:  */
        !           408: void
        !           409: midi_onsysex(struct aproc *p, struct abuf *ibuf)
        !           410: {
        !           411:        struct sysex *x;
        !           412:        unsigned fps, len;
        !           413: #ifdef DEBUG
        !           414:        unsigned i;
        !           415:
        !           416:        if (debug_level >= 3) {
        !           417:                abuf_dbg(ibuf);
        !           418:                dbg_puts(": got sysex:");
        !           419:                for (i = 0; i < ibuf->r.midi.idx; i++) {
        !           420:                        dbg_puts(" ");
        !           421:                        dbg_putx(ibuf->r.midi.msg[i]);
        !           422:                }
        !           423:                dbg_puts("\n");
        !           424:        }
        !           425: #endif
1.33      ratchov   426:        x = (struct sysex *)ibuf->r.midi.msg;
                    427:        len = ibuf->r.midi.idx;
                    428:        if (x->start != SYSEX_START)
                    429:                return;
                    430:        if (len < SYSEX_SIZE(empty))
                    431:                return;
                    432:        switch (x->type) {
                    433:        case SYSEX_TYPE_RT:
                    434:                if (x->id0 != SYSEX_MMC)
                    435:                        return;
                    436:                switch (x->id1) {
                    437:                case SYSEX_MMC_STOP:
                    438:                        if (len != SYSEX_SIZE(stop))
                    439:                                return;
1.14      ratchov   440: #ifdef DEBUG
1.19      ratchov   441:                        if (debug_level >= 3) {
1.14      ratchov   442:                                abuf_dbg(ibuf);
                    443:                                dbg_puts(": mmc stop\n");
                    444:                        }
                    445: #endif
1.40    ! ratchov   446:                        dev_mmcstop(p->u.midi.dev);
1.13      ratchov   447:                        break;
1.33      ratchov   448:                case SYSEX_MMC_START:
                    449:                        if (len != SYSEX_SIZE(start))
                    450:                                return;
1.14      ratchov   451: #ifdef DEBUG
1.19      ratchov   452:                        if (debug_level >= 3) {
1.14      ratchov   453:                                abuf_dbg(ibuf);
                    454:                                dbg_puts(": mmc start\n");
                    455:                        }
                    456: #endif
1.40    ! ratchov   457:                        dev_mmcstart(p->u.midi.dev);
1.13      ratchov   458:                        break;
1.33      ratchov   459:                case SYSEX_MMC_LOC:
                    460:                        if (len != SYSEX_SIZE(loc) ||
                    461:                            x->u.loc.len != SYSEX_MMC_LOC_LEN ||
                    462:                            x->u.loc.cmd != SYSEX_MMC_LOC_CMD)
                    463:                                return;
                    464:                        switch (x->u.loc.hr >> 5) {
                    465:                        case MTC_FPS_24:
                    466:                                fps = 24;
                    467:                                break;
                    468:                        case MTC_FPS_25:
                    469:                                fps = 25;
                    470:                                break;
                    471:                        case MTC_FPS_30:
                    472:                                fps = 30;
                    473:                                break;
                    474:                        default:
1.39      ratchov   475:                                /* XXX: should dev_mmcstop() here */
1.33      ratchov   476:                                return;
                    477:                        }
1.40    ! ratchov   478:                        dev_loc(p->u.midi.dev,
1.33      ratchov   479:                            (x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
                    480:                             x->u.loc.min * 60 * MTC_SEC +
                    481:                             x->u.loc.sec * MTC_SEC +
                    482:                             x->u.loc.fr * (MTC_SEC / fps) +
                    483:                             x->u.loc.cent * (MTC_SEC / 100 / fps));
1.13      ratchov   484:                        break;
                    485:                }
1.35      ratchov   486:                break;
                    487:        case SYSEX_TYPE_EDU:
                    488:                if (x->id0 != SYSEX_AUCAT || x->id1 != SYSEX_AUCAT_DUMPREQ)
                    489:                        return;
                    490:                if (len != SYSEX_SIZE(dumpreq))
                    491:                        return;
                    492:                if (ibuf->duplex)
1.40    ! ratchov   493:                        midi_copy_dump(p, ibuf->duplex);
1.33      ratchov   494:                break;
1.13      ratchov   495:        }
1.3       ratchov   496: }
                    497:
                    498: int
1.40    ! ratchov   499: midi_in(struct aproc *p, struct abuf *ibuf)
1.3       ratchov   500: {
1.40    ! ratchov   501:        unsigned char c, *idata;
        !           502:        unsigned i, icount;
1.3       ratchov   503:
                    504:        if (!ABUF_ROK(ibuf))
                    505:                return 0;
1.40    ! ratchov   506:        if (ibuf->tickets == 0) {
        !           507: #ifdef DEBUG
        !           508:                if (debug_level >= 4) {
        !           509:                        abuf_dbg(ibuf);
        !           510:                        dbg_puts(": out of tickets, blocking\n");
        !           511:                }
        !           512: #endif
        !           513:                return 0;
        !           514:        }
1.3       ratchov   515:        idata = abuf_rgetblk(ibuf, &icount, 0);
1.40    ! ratchov   516:        if (icount > ibuf->tickets)
        !           517:                icount = ibuf->tickets;
        !           518:        ibuf->tickets -= icount;
1.3       ratchov   519:        for (i = 0; i < icount; i++) {
                    520:                c = *idata++;
1.8       ratchov   521:                if (c >= 0xf8) {
1.40    ! ratchov   522:                        if (!p->u.midi.dev && c != MIDI_ACK)
        !           523:                                midi_send(p, ibuf, &c, 1);
        !           524:                } else if (c == SYSEX_END) {
        !           525:                        if (ibuf->r.midi.st == SYSEX_START) {
1.10      ratchov   526:                                ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
1.40    ! ratchov   527:                                if (!p->u.midi.dev) {
        !           528:                                        midi_send(p, ibuf,
        !           529:                                            ibuf->r.midi.msg, ibuf->r.midi.idx);
        !           530:                                } else
        !           531:                                        midi_onsysex(p, ibuf);
1.8       ratchov   532:                        }
1.40    ! ratchov   533:                        ibuf->r.midi.st = 0;
        !           534:                        ibuf->r.midi.idx = 0;
        !           535:                } else if (c >= 0xf0) {
1.10      ratchov   536:                        ibuf->r.midi.msg[0] = c;
                    537:                        ibuf->r.midi.len = common_len[c & 7];
                    538:                        ibuf->r.midi.st = c;
                    539:                        ibuf->r.midi.idx = 1;
1.3       ratchov   540:                } else if (c >= 0x80) {
1.10      ratchov   541:                        ibuf->r.midi.msg[0] = c;
                    542:                        ibuf->r.midi.len = voice_len[(c >> 4) & 7];
                    543:                        ibuf->r.midi.st = c;
                    544:                        ibuf->r.midi.idx = 1;
                    545:                } else if (ibuf->r.midi.st) {
1.40    ! ratchov   546:                        if (ibuf->r.midi.idx == 0 &&
        !           547:                            ibuf->r.midi.st != SYSEX_START) {
        !           548:                                ibuf->r.midi.msg[ibuf->r.midi.idx++] =
        !           549:                                    ibuf->r.midi.st;
        !           550:                        }
1.10      ratchov   551:                        ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
                    552:                        if (ibuf->r.midi.idx == ibuf->r.midi.len) {
1.40    ! ratchov   553:                                if (!p->u.midi.dev) {
        !           554:                                        midi_send(p, ibuf,
        !           555:                                            ibuf->r.midi.msg, ibuf->r.midi.idx);
        !           556:                                } else
        !           557:                                        midi_onvoice(p, ibuf);
        !           558:                                if (ibuf->r.midi.st >= 0xf0)
        !           559:                                        ibuf->r.midi.st = 0;
        !           560:                                ibuf->r.midi.idx = 0;
        !           561:                        } else if (ibuf->r.midi.idx == MIDI_MSGMAX) {
        !           562:                                if (!p->u.midi.dev) {
        !           563:                                        midi_send(p, ibuf,
        !           564:                                            ibuf->r.midi.msg, ibuf->r.midi.idx);
        !           565:                                }
1.10      ratchov   566:                                ibuf->r.midi.idx = 0;
1.3       ratchov   567:                        }
                    568:                }
                    569:        }
1.40    ! ratchov   570:        /*
        !           571:         * XXX: if the sysex is received byte by byte, partial messages
        !           572:         * won't be sent until the end byte is received. On the other
        !           573:         * hand we can't flush it here, since we would loose messages
        !           574:         * we parse
        !           575:         */
1.3       ratchov   576:        abuf_rdiscard(ibuf, icount);
1.40    ! ratchov   577:        midi_flush(p);
1.3       ratchov   578:        return 1;
                    579: }
                    580:
                    581: int
1.40    ! ratchov   582: midi_out(struct aproc *p, struct abuf *obuf)
1.3       ratchov   583: {
                    584:        return 0;
                    585: }
                    586:
                    587: void
1.40    ! ratchov   588: midi_eof(struct aproc *p, struct abuf *ibuf)
1.3       ratchov   589: {
1.39      ratchov   590:        if ((p->flags & APROC_QUIT) && LIST_EMPTY(&p->ins))
1.13      ratchov   591:                aproc_del(p);
1.3       ratchov   592: }
                    593:
                    594: void
1.40    ! ratchov   595: midi_hup(struct aproc *p, struct abuf *obuf)
1.3       ratchov   596: {
1.39      ratchov   597:        if ((p->flags & APROC_QUIT) && LIST_EMPTY(&p->ins))
1.13      ratchov   598:                aproc_del(p);
1.3       ratchov   599: }
                    600:
                    601: void
1.40    ! ratchov   602: midi_newin(struct aproc *p, struct abuf *ibuf)
1.3       ratchov   603: {
1.10      ratchov   604:        ibuf->r.midi.used = 0;
                    605:        ibuf->r.midi.len = 0;
                    606:        ibuf->r.midi.idx = 0;
                    607:        ibuf->r.midi.st = 0;
1.40    ! ratchov   608:        ibuf->tickets = MIDITHRU_XFER;
        !           609: }
        !           610:
        !           611: void
        !           612: midi_done(struct aproc *p)
        !           613: {
        !           614:        timo_del(&p->u.midi.timo);
1.3       ratchov   615: }
                    616:
1.40    ! ratchov   617: struct aproc_ops midi_ops = {
        !           618:        "midi",
        !           619:        midi_in,
        !           620:        midi_out,
        !           621:        midi_eof,
        !           622:        midi_hup,
        !           623:        midi_newin,
1.3       ratchov   624:        NULL, /* newout */
                    625:        NULL, /* ipos */
                    626:        NULL, /* opos */
1.40    ! ratchov   627:        midi_done,
1.3       ratchov   628: };
                    629:
                    630: struct aproc *
1.40    ! ratchov   631: midi_new(char *name, struct dev *dev)
1.3       ratchov   632: {
                    633:        struct aproc *p;
                    634:
1.40    ! ratchov   635:        p = aproc_new(&midi_ops, name);
        !           636:        timo_set(&p->u.midi.timo, midi_cb, p);
        !           637:        timo_add(&p->u.midi.timo, MIDITHRU_TIMO);
        !           638:        p->u.midi.dev = dev;
1.1       ratchov   639:        return p;
                    640: }