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

1.2     ! ratchov     1: /*     $OpenBSD: midi.c,v 1.1 2009/07/25 08:44:27 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:  *
                     20:  * use abuf->duplex to implement bidirectionnal sockets
                     21:  * that don't receive what they send
                     22:  *
                     23:  * use shadow variables in the midi merger
                     24:  *
                     25:  * make output and input identical when only one
                     26:  * input is used (fix running status)
                     27:  */
                     28: #include <stdio.h>
                     29: #include <stdlib.h>
                     30: #include <string.h>
                     31:
                     32: #include "conf.h"
                     33: #include "abuf.h"
                     34: #include "aproc.h"
                     35: #include "midi.h"
                     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:
                     44: unsigned voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
                     45: unsigned common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
                     46:
                     47: void
                     48: thru_flush(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
                     49: {
                     50:        unsigned ocount, itodo;
                     51:        unsigned char *odata, *idata;
                     52:
                     53:        itodo = ibuf->mused;
                     54:        idata = ibuf->mdata;
                     55:        DPRINTFN(4, "thru_flush: mused = %u\n", itodo);
                     56:        while (itodo > 0) {
                     57:                if (!ABUF_WOK(obuf)) {
                     58:                        abuf_rdiscard(obuf, obuf->used);
                     59:                        DPRINTFN(2, "thru_flush: discarded %u\n", obuf->used);
                     60:                        if (p->u.thru.owner == ibuf)
                     61:                                p->u.thru.owner = NULL;
                     62:                        return;
                     63:                }
                     64:                odata = abuf_wgetblk(obuf, &ocount, 0);
                     65:                if (ocount > itodo)
                     66:                        ocount = itodo;
                     67:                memcpy(odata, idata, ocount);
                     68:                abuf_wcommit(obuf, ocount);
                     69:                itodo -= ocount;
                     70:                idata += ocount;
                     71:        }
                     72:        ibuf->mused = 0;
                     73:        p->u.thru.owner = ibuf;
                     74: }
                     75:
                     76: void
                     77: thru_rt(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned c)
                     78: {
                     79:        unsigned ocount;
                     80:        unsigned char *odata;
                     81:
                     82:        DPRINTFN(4, "thru_rt:\n");
                     83:        if (!ABUF_WOK(obuf)) {
                     84:                DPRINTFN(2, "thru_rt: discarded %u\n", obuf->used);
                     85:                abuf_rdiscard(obuf, obuf->used);
                     86:                if (p->u.thru.owner == ibuf)
                     87:                        p->u.thru.owner = NULL;
                     88:        }
                     89:        odata = abuf_wgetblk(obuf, &ocount, 0);
                     90:        odata[0] = c;
                     91:        abuf_wcommit(obuf, 1);
                     92: }
                     93:
                     94:
                     95: void
                     96: thru_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned todo)
                     97: {
                     98:        unsigned char *idata;
                     99:        unsigned c, icount, ioffs;
                    100:
                    101:        idata = NULL;
                    102:        icount = ioffs = 0;
                    103:        for (;;) {
                    104:                if (icount == 0) {
                    105:                        if (todo == 0)
                    106:                                break;
                    107:                        idata = abuf_rgetblk(ibuf, &icount, ioffs);
                    108:                        if (icount > todo)
                    109:                                icount = todo;
                    110:                        if (icount == 0)
                    111:                                break;
                    112:                        todo -= icount;
                    113:                        ioffs += icount;
                    114:                }
                    115:                c = *idata++;
                    116:                icount--;
                    117:                if (c < 0x80) {
                    118:                        if (ibuf->mindex == 0 && ibuf->mstatus) {
                    119:                                ibuf->mdata[ibuf->mused++] = ibuf->mstatus;
                    120:                                ibuf->mindex++;
                    121:                        }
                    122:                        ibuf->mdata[ibuf->mused++] = c;
                    123:                        ibuf->mindex++;
                    124:                        if (ibuf->mindex == ibuf->mlen) {
                    125:                                thru_flush(p, ibuf, obuf);
                    126:                                if (ibuf->mstatus >= 0xf0)
                    127:                                        ibuf->mstatus = 0;
                    128:                                ibuf->mindex = 0;
                    129:                        }
                    130:                        if (ibuf->mused == MDATA_NMAX) {
                    131:                                if (ibuf->mused == ibuf->mindex ||
                    132:                                    p->u.thru.owner == ibuf)
                    133:                                        thru_flush(p, ibuf, obuf);
                    134:                                else
                    135:                                        ibuf->mused = 0;
                    136:                        }
                    137:                } else if (c < 0xf8) {
                    138:                        if (ibuf->mused == ibuf->mindex ||
                    139:                            p->u.thru.owner == ibuf) {
                    140:                                thru_flush(p, ibuf, obuf);
                    141:                        } else
                    142:                                ibuf->mused = 0;
                    143:                        ibuf->mdata[0] = c;
                    144:                        ibuf->mused = 1;
                    145:                        ibuf->mlen = (c >= 0xf0) ?
                    146:                            common_len[c & 7] :
                    147:                            voice_len[(c >> 4) & 7];
                    148:                        if (ibuf->mlen == 1) {
                    149:                                thru_flush(p, ibuf, obuf);
                    150:                                ibuf->mindex = 0;
                    151:                                ibuf->mstatus = 0;
                    152:                                ibuf->mlen = 0;
                    153:                        } else {
                    154:                                ibuf->mstatus = c;
                    155:                                ibuf->mindex = 1;
                    156:                        }
                    157:                } else {
                    158:                        thru_rt(p, ibuf, obuf, c);
                    159:                }
                    160:        }
                    161: }
                    162:
                    163: int
                    164: thru_in(struct aproc *p, struct abuf *ibuf)
                    165: {
                    166:        struct abuf *i, *inext;
                    167:        unsigned todo;
                    168:
                    169:        DPRINTFN(3, "thru_in: %s\n", p->name);
                    170:
                    171:        if (!ABUF_ROK(ibuf))
                    172:                return 0;
                    173:        if (ibuf->mtickets == 0) {
                    174:                DPRINTFN(2, "thru_in: out of tickets\n");
                    175:                return 0;
                    176:        }
                    177:        todo = ibuf->used;
                    178:        if (todo > ibuf->mtickets)
                    179:                todo = ibuf->mtickets;
                    180:        ibuf->mtickets -= todo;
                    181:        for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
                    182:                inext = LIST_NEXT(i, oent);
                    183:                if (ibuf->duplex == i)
                    184:                        continue;
                    185:                thru_bcopy(p, ibuf, i, todo);
                    186:                (void)abuf_flush(i);
                    187:        }
                    188:        abuf_rdiscard(ibuf, todo);
                    189:        return 1;
                    190: }
                    191:
                    192: int
                    193: thru_out(struct aproc *p, struct abuf *obuf)
                    194: {
                    195:        return 0;
                    196: }
                    197:
                    198: void
                    199: thru_eof(struct aproc *p, struct abuf *ibuf)
                    200: {
                    201:        DPRINTF("thru_eof: %s: eof\n", p->name);
                    202: }
                    203:
                    204: void
                    205: thru_hup(struct aproc *p, struct abuf *obuf)
                    206: {
                    207:        DPRINTF("thru_hup: %s: detached\n", p->name);
                    208: }
                    209:
                    210: void
                    211: thru_newin(struct aproc *p, struct abuf *ibuf)
                    212: {
                    213:        ibuf->mused = 0;
                    214:        ibuf->mlen = 0;
                    215:        ibuf->mindex = 0;
                    216:        ibuf->mstatus = 0;
                    217:        ibuf->mtickets = MIDITHRU_XFER;
                    218: }
                    219:
                    220: void
                    221: thru_done(struct aproc *p)
                    222: {
                    223:        timo_del(&p->u.thru.timo);
                    224: }
                    225:
                    226: struct aproc_ops thru_ops = {
                    227:        "thru",
                    228:        thru_in,
                    229:        thru_out,
                    230:        thru_eof,
                    231:        thru_hup,
                    232:        thru_newin,
                    233:        NULL, /* newout */
                    234:        NULL, /* ipos */
                    235:        NULL, /* opos */
                    236:        thru_done
                    237: };
                    238:
                    239: void
                    240: thru_cb(void *addr)
                    241: {
                    242:        struct aproc *p = (struct aproc *)addr;
                    243:        struct abuf *i, *inext;
                    244:        unsigned tickets;
                    245:
                    246:        timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
                    247:
                    248:        for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
                    249:                inext = LIST_NEXT(i, ient);
                    250:                tickets = i->mtickets;
                    251:                i->mtickets = MIDITHRU_XFER;
                    252:                if (tickets == 0)
                    253:                        abuf_run(i);
                    254:        }
                    255: }
                    256:
                    257: struct aproc *
                    258: thru_new(char *name)
                    259: {
                    260:        struct aproc *p;
                    261:
                    262:        p = aproc_new(&thru_ops, name);
                    263:        p->u.thru.owner = NULL;
                    264:        timo_set(&p->u.thru.timo, thru_cb, p);
                    265:        timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
                    266:        return p;
                    267: }
                    268: