Annotation of src/usr.bin/aucat/midi.c, Revision 1.41
1.41 ! ratchov 1: /* $OpenBSD: midi.c,v 1.40 2011/12/02 10:34:50 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.41 ! ratchov 128: void
! 129: midi_msg_master(struct aproc *p, char *msg)
! 130: {
! 131: struct sysex *x = (struct sysex *)msg;
! 132:
! 133: memset(x, 0, sizeof(struct sysex));
! 134: x->start = SYSEX_START;
! 135: x->type = SYSEX_TYPE_RT;
! 136: x->id0 = SYSEX_CONTROL;
! 137: x->id1 = SYSEX_MASTER;
! 138: x->u.master.fine = 0;
! 139: x->u.master.coarse = p->u.midi.dev->master;
! 140: x->u.master.end = SYSEX_END;
! 141: }
! 142:
1.7 ratchov 143: /*
1.33 ratchov 144: * send a message to the given output
145: */
146: void
1.40 ratchov 147: midi_copy(struct abuf *ibuf, struct abuf *obuf, unsigned char *msg, unsigned len)
1.33 ratchov 148: {
1.40 ratchov 149: unsigned ocount;
150: unsigned char *odata;
1.33 ratchov 151:
1.40 ratchov 152: if (msg[0] == SYSEX_START)
153: obuf->w.midi.owner = ibuf;
154: while (len > 0) {
1.33 ratchov 155: if (!ABUF_WOK(obuf)) {
156: #ifdef DEBUG
157: if (debug_level >= 3) {
158: abuf_dbg(obuf);
159: dbg_puts(": overrun, discarding ");
160: dbg_putu(obuf->used);
161: dbg_puts(" bytes\n");
162: }
163: #endif
164: abuf_rdiscard(obuf, obuf->used);
1.40 ratchov 165: if (obuf->w.midi.owner == ibuf)
166: obuf->w.midi.owner = NULL;
167: return;
1.33 ratchov 168: }
169: odata = abuf_wgetblk(obuf, &ocount, 0);
1.40 ratchov 170: if (ocount > len)
171: ocount = len;
1.33 ratchov 172: #ifdef DEBUG
173: if (debug_level >= 4) {
174: abuf_dbg(obuf);
175: dbg_puts(": stored ");
176: dbg_putu(ocount);
177: dbg_puts(" bytes\n");
178: }
179: #endif
1.40 ratchov 180: memcpy(odata, msg, ocount);
1.33 ratchov 181: abuf_wcommit(obuf, ocount);
1.40 ratchov 182: len -= ocount;
183: msg += ocount;
184: }
185: }
186:
187: /*
188: * flush all buffers. Since most of the MIDI traffic is broadcasted to
189: * all outputs, the flush is delayed to avoid flushing all outputs for
190: * each message.
191: */
192: void
193: midi_flush(struct aproc *p)
194: {
195: struct abuf *i, *inext;
196:
197: for (i = LIST_FIRST(&p->outs); i != NULL; i = inext) {
198: inext = LIST_NEXT(i, oent);
199: if (ABUF_ROK(i))
200: (void)abuf_flush(i);
1.33 ratchov 201: }
202: }
203:
204: /*
1.7 ratchov 205: * broadcast a message to all output buffers on the behalf of ibuf.
206: * ie. don't sent back the message to the sender
207: */
1.3 ratchov 208: void
1.40 ratchov 209: midi_send(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len)
1.3 ratchov 210: {
211: struct abuf *i, *inext;
212:
1.20 ratchov 213: for (i = LIST_FIRST(&p->outs); i != NULL; i = inext) {
1.3 ratchov 214: inext = LIST_NEXT(i, oent);
1.19 ratchov 215: if (i->duplex && i->duplex == ibuf)
1.3 ratchov 216: continue;
1.40 ratchov 217: midi_copy(ibuf, i, msg, len);
1.3 ratchov 218: }
219: }
220:
1.7 ratchov 221: /*
1.13 ratchov 222: * send a quarter frame MTC message
223: */
224: void
1.40 ratchov 225: midi_send_qfr(struct aproc *p, unsigned rate, int delta)
1.13 ratchov 226: {
227: unsigned char buf[2];
228: unsigned data;
1.39 ratchov 229: int qfrlen;
230:
1.40 ratchov 231: p->u.midi.delta += delta * MTC_SEC;
232: qfrlen = rate * (MTC_SEC / (4 * p->u.midi.fps));
233: while (p->u.midi.delta >= qfrlen) {
234: switch (p->u.midi.qfr) {
1.39 ratchov 235: case 0:
1.40 ratchov 236: data = p->u.midi.fr & 0xf;
1.39 ratchov 237: break;
238: case 1:
1.40 ratchov 239: data = p->u.midi.fr >> 4;
1.39 ratchov 240: break;
241: case 2:
1.40 ratchov 242: data = p->u.midi.sec & 0xf;
1.39 ratchov 243: break;
244: case 3:
1.40 ratchov 245: data = p->u.midi.sec >> 4;
1.39 ratchov 246: break;
247: case 4:
1.40 ratchov 248: data = p->u.midi.min & 0xf;
1.39 ratchov 249: break;
250: case 5:
1.40 ratchov 251: data = p->u.midi.min >> 4;
1.39 ratchov 252: break;
253: case 6:
1.40 ratchov 254: data = p->u.midi.hr & 0xf;
1.39 ratchov 255: break;
256: case 7:
1.40 ratchov 257: data = (p->u.midi.hr >> 4) | (p->u.midi.fps_id << 1);
1.39 ratchov 258: /*
259: * tick messages are sent 2 frames ahead
260: */
1.40 ratchov 261: p->u.midi.fr += 2;
262: if (p->u.midi.fr < p->u.midi.fps)
1.39 ratchov 263: break;
1.40 ratchov 264: p->u.midi.fr -= p->u.midi.fps;
265: p->u.midi.sec++;
266: if (p->u.midi.sec < 60)
1.39 ratchov 267: break;
1.40 ratchov 268: p->u.midi.sec = 0;
269: p->u.midi.min++;
270: if (p->u.midi.min < 60)
1.39 ratchov 271: break;
1.40 ratchov 272: p->u.midi.min = 0;
273: p->u.midi.hr++;
274: if (p->u.midi.hr < 24)
1.39 ratchov 275: break;
1.40 ratchov 276: p->u.midi.hr = 0;
1.13 ratchov 277: break;
1.39 ratchov 278: default:
279: /* NOTREACHED */
280: data = 0;
281: }
282: buf[0] = 0xf1;
1.40 ratchov 283: buf[1] = (p->u.midi.qfr << 4) | data;
284: p->u.midi.qfr++;
285: p->u.midi.qfr &= 7;
286: midi_send(p, NULL, buf, 2);
287: p->u.midi.delta -= qfrlen;
1.13 ratchov 288: }
289: }
290:
291: /*
292: * send a full frame MTC message
293: */
294: void
1.40 ratchov 295: midi_send_full(struct aproc *p, unsigned origin, unsigned rate, unsigned round, unsigned pos)
1.13 ratchov 296: {
297: unsigned char buf[10];
1.39 ratchov 298: unsigned fps;
1.13 ratchov 299:
1.40 ratchov 300: p->u.midi.delta = MTC_SEC * pos;
1.39 ratchov 301: if (rate % (30 * 4 * round) == 0) {
1.40 ratchov 302: p->u.midi.fps_id = MTC_FPS_30;
303: p->u.midi.fps = 30;
1.39 ratchov 304: } else if (rate % (25 * 4 * round) == 0) {
1.40 ratchov 305: p->u.midi.fps_id = MTC_FPS_25;
306: p->u.midi.fps = 25;
1.39 ratchov 307: } else {
1.40 ratchov 308: p->u.midi.fps_id = MTC_FPS_24;
309: p->u.midi.fps = 24;
1.39 ratchov 310: }
311: #ifdef DEBUG
312: if (debug_level >= 3) {
313: aproc_dbg(p);
314: dbg_puts(": mtc full frame at ");
1.40 ratchov 315: dbg_puti(p->u.midi.delta);
1.39 ratchov 316: dbg_puts(", ");
1.40 ratchov 317: dbg_puti(p->u.midi.fps);
1.39 ratchov 318: dbg_puts(" fps\n");
319: }
320: #endif
1.40 ratchov 321: fps = p->u.midi.fps;
322: p->u.midi.hr = (origin / (3600 * MTC_SEC)) % 24;
323: p->u.midi.min = (origin / (60 * MTC_SEC)) % 60;
324: p->u.midi.sec = (origin / MTC_SEC) % 60;
325: p->u.midi.fr = (origin / (MTC_SEC / fps)) % fps;
1.13 ratchov 326:
327: buf[0] = 0xf0;
328: buf[1] = 0x7f;
329: buf[2] = 0x7f;
330: buf[3] = 0x01;
331: buf[4] = 0x01;
1.40 ratchov 332: buf[5] = p->u.midi.hr | (p->u.midi.fps_id << 5);
333: buf[6] = p->u.midi.min;
334: buf[7] = p->u.midi.sec;
335: buf[8] = p->u.midi.fr;
1.13 ratchov 336: buf[9] = 0xf7;
1.40 ratchov 337: p->u.midi.qfr = 0;
338: midi_send(p, NULL, buf, 10);
1.13 ratchov 339: }
340:
1.33 ratchov 341: void
1.40 ratchov 342: midi_copy_dump(struct aproc *p, struct abuf *obuf)
1.35 ratchov 343: {
344: unsigned i;
345: unsigned char msg[sizeof(struct sysex)];
346: struct ctl_slot *s;
347:
1.41 ! ratchov 348: midi_msg_master(p, msg);
! 349: midi_copy(NULL, obuf, msg, SYSEX_SIZE(master));
1.40 ratchov 350: for (i = 0, s = p->u.midi.dev->slot; i < CTL_NSLOT; i++, s++) {
351: midi_msg_info(p, i, msg);
352: midi_copy(NULL, obuf, msg, SYSEX_SIZE(mixinfo));
353: midi_msg_vol(p, i, msg);
354: midi_copy(NULL, obuf, msg, 3);
1.35 ratchov 355: }
356: msg[0] = SYSEX_START;
357: msg[1] = SYSEX_TYPE_EDU;
358: msg[2] = 0;
359: msg[3] = SYSEX_AUCAT;
360: msg[4] = SYSEX_AUCAT_DUMPEND;
361: msg[5] = SYSEX_END;
1.40 ratchov 362: midi_copy(NULL, obuf, msg, 6);
1.35 ratchov 363: }
364:
1.13 ratchov 365: /*
1.7 ratchov 366: * notifty the mixer that volume changed, called by whom allocad the slot using
367: * ctl_slotnew(). Note: it doesn't make sens to call this from within the
368: * call-back.
369: */
1.3 ratchov 370: void
1.40 ratchov 371: midi_send_vol(struct aproc *p, int slot, unsigned vol)
1.3 ratchov 372: {
373: unsigned char msg[3];
374:
1.40 ratchov 375: midi_msg_vol(p, slot, msg);
376: midi_send(p, NULL, msg, 3);
1.3 ratchov 377: }
378:
1.13 ratchov 379: void
1.41 ! ratchov 380: midi_send_master(struct aproc *p)
! 381: {
! 382: unsigned char msg[sizeof(struct sysex)];
! 383:
! 384: midi_msg_master(p, msg);
! 385: midi_send(p, NULL, msg, SYSEX_SIZE(master));
! 386: }
! 387:
! 388: void
1.40 ratchov 389: midi_send_slot(struct aproc *p, int slot)
1.13 ratchov 390: {
1.39 ratchov 391: unsigned char msg[sizeof(struct sysex)];
1.13 ratchov 392:
1.40 ratchov 393: midi_msg_info(p, slot, msg);
394: midi_send(p, NULL, msg, SYSEX_SIZE(mixinfo));
1.19 ratchov 395: }
396:
397: /*
1.40 ratchov 398: * handle a MIDI voice event received from ibuf
1.7 ratchov 399: */
1.3 ratchov 400: void
1.40 ratchov 401: midi_onvoice(struct aproc *p, struct abuf *ibuf)
1.3 ratchov 402: {
1.40 ratchov 403: struct ctl_slot *slot;
1.3 ratchov 404: unsigned chan;
1.14 ratchov 405: #ifdef DEBUG
406: unsigned i;
407:
408: if (debug_level >= 3) {
409: abuf_dbg(ibuf);
1.40 ratchov 410: dbg_puts(": got voice event:");
1.14 ratchov 411: for (i = 0; i < ibuf->r.midi.idx; i++) {
412: dbg_puts(" ");
413: dbg_putx(ibuf->r.midi.msg[i]);
414: }
415: dbg_puts("\n");
416: }
417: #endif
1.10 ratchov 418: if ((ibuf->r.midi.msg[0] & MIDI_CMDMASK) == MIDI_CTL &&
1.33 ratchov 419: (ibuf->r.midi.msg[1] == MIDI_CTLVOL)) {
1.10 ratchov 420: chan = ibuf->r.midi.msg[0] & MIDI_CHANMASK;
1.3 ratchov 421: if (chan >= CTL_NSLOT)
422: return;
1.40 ratchov 423: slot = p->u.midi.dev->slot + chan;
1.22 ratchov 424: slot->vol = ibuf->r.midi.msg[2];
1.12 ratchov 425: if (slot->ops == NULL)
1.3 ratchov 426: return;
1.12 ratchov 427: slot->ops->vol(slot->arg, slot->vol);
1.3 ratchov 428: }
1.40 ratchov 429: }
430:
431: /*
432: * handle a MIDI sysex received from ibuf
433: */
434: void
435: midi_onsysex(struct aproc *p, struct abuf *ibuf)
436: {
437: struct sysex *x;
438: unsigned fps, len;
439: #ifdef DEBUG
440: unsigned i;
441:
442: if (debug_level >= 3) {
443: abuf_dbg(ibuf);
444: dbg_puts(": got sysex:");
445: for (i = 0; i < ibuf->r.midi.idx; i++) {
446: dbg_puts(" ");
447: dbg_putx(ibuf->r.midi.msg[i]);
448: }
449: dbg_puts("\n");
450: }
451: #endif
1.33 ratchov 452: x = (struct sysex *)ibuf->r.midi.msg;
453: len = ibuf->r.midi.idx;
454: if (x->start != SYSEX_START)
455: return;
456: if (len < SYSEX_SIZE(empty))
457: return;
458: switch (x->type) {
459: case SYSEX_TYPE_RT:
1.41 ! ratchov 460: if (x->id0 == SYSEX_CONTROL && x->id1 == SYSEX_MASTER) {
! 461: if (len == SYSEX_SIZE(master))
! 462: dev_master(p->u.midi.dev, x->u.master.coarse);
! 463: return;
! 464: }
1.33 ratchov 465: if (x->id0 != SYSEX_MMC)
466: return;
467: switch (x->id1) {
468: case SYSEX_MMC_STOP:
469: if (len != SYSEX_SIZE(stop))
470: return;
1.14 ratchov 471: #ifdef DEBUG
1.19 ratchov 472: if (debug_level >= 3) {
1.14 ratchov 473: abuf_dbg(ibuf);
474: dbg_puts(": mmc stop\n");
475: }
476: #endif
1.40 ratchov 477: dev_mmcstop(p->u.midi.dev);
1.13 ratchov 478: break;
1.33 ratchov 479: case SYSEX_MMC_START:
480: if (len != SYSEX_SIZE(start))
481: return;
1.14 ratchov 482: #ifdef DEBUG
1.19 ratchov 483: if (debug_level >= 3) {
1.14 ratchov 484: abuf_dbg(ibuf);
485: dbg_puts(": mmc start\n");
486: }
487: #endif
1.40 ratchov 488: dev_mmcstart(p->u.midi.dev);
1.13 ratchov 489: break;
1.33 ratchov 490: case SYSEX_MMC_LOC:
491: if (len != SYSEX_SIZE(loc) ||
492: x->u.loc.len != SYSEX_MMC_LOC_LEN ||
493: x->u.loc.cmd != SYSEX_MMC_LOC_CMD)
494: return;
495: switch (x->u.loc.hr >> 5) {
496: case MTC_FPS_24:
497: fps = 24;
498: break;
499: case MTC_FPS_25:
500: fps = 25;
501: break;
502: case MTC_FPS_30:
503: fps = 30;
504: break;
505: default:
1.39 ratchov 506: /* XXX: should dev_mmcstop() here */
1.33 ratchov 507: return;
508: }
1.40 ratchov 509: dev_loc(p->u.midi.dev,
1.33 ratchov 510: (x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
511: x->u.loc.min * 60 * MTC_SEC +
512: x->u.loc.sec * MTC_SEC +
513: x->u.loc.fr * (MTC_SEC / fps) +
514: x->u.loc.cent * (MTC_SEC / 100 / fps));
1.13 ratchov 515: break;
516: }
1.35 ratchov 517: break;
518: case SYSEX_TYPE_EDU:
519: if (x->id0 != SYSEX_AUCAT || x->id1 != SYSEX_AUCAT_DUMPREQ)
520: return;
521: if (len != SYSEX_SIZE(dumpreq))
522: return;
523: if (ibuf->duplex)
1.40 ratchov 524: midi_copy_dump(p, ibuf->duplex);
1.33 ratchov 525: break;
1.13 ratchov 526: }
1.3 ratchov 527: }
528:
529: int
1.40 ratchov 530: midi_in(struct aproc *p, struct abuf *ibuf)
1.3 ratchov 531: {
1.40 ratchov 532: unsigned char c, *idata;
533: unsigned i, icount;
1.3 ratchov 534:
535: if (!ABUF_ROK(ibuf))
536: return 0;
1.40 ratchov 537: if (ibuf->tickets == 0) {
538: #ifdef DEBUG
539: if (debug_level >= 4) {
540: abuf_dbg(ibuf);
541: dbg_puts(": out of tickets, blocking\n");
542: }
543: #endif
544: return 0;
545: }
1.3 ratchov 546: idata = abuf_rgetblk(ibuf, &icount, 0);
1.40 ratchov 547: if (icount > ibuf->tickets)
548: icount = ibuf->tickets;
549: ibuf->tickets -= icount;
1.3 ratchov 550: for (i = 0; i < icount; i++) {
551: c = *idata++;
1.8 ratchov 552: if (c >= 0xf8) {
1.40 ratchov 553: if (!p->u.midi.dev && c != MIDI_ACK)
554: midi_send(p, ibuf, &c, 1);
555: } else if (c == SYSEX_END) {
556: if (ibuf->r.midi.st == SYSEX_START) {
1.10 ratchov 557: ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
1.40 ratchov 558: if (!p->u.midi.dev) {
559: midi_send(p, ibuf,
560: ibuf->r.midi.msg, ibuf->r.midi.idx);
561: } else
562: midi_onsysex(p, ibuf);
1.8 ratchov 563: }
1.40 ratchov 564: ibuf->r.midi.st = 0;
565: ibuf->r.midi.idx = 0;
566: } else if (c >= 0xf0) {
1.10 ratchov 567: ibuf->r.midi.msg[0] = c;
568: ibuf->r.midi.len = common_len[c & 7];
569: ibuf->r.midi.st = c;
570: ibuf->r.midi.idx = 1;
1.3 ratchov 571: } else if (c >= 0x80) {
1.10 ratchov 572: ibuf->r.midi.msg[0] = c;
573: ibuf->r.midi.len = voice_len[(c >> 4) & 7];
574: ibuf->r.midi.st = c;
575: ibuf->r.midi.idx = 1;
576: } else if (ibuf->r.midi.st) {
1.40 ratchov 577: if (ibuf->r.midi.idx == 0 &&
578: ibuf->r.midi.st != SYSEX_START) {
579: ibuf->r.midi.msg[ibuf->r.midi.idx++] =
580: ibuf->r.midi.st;
581: }
1.10 ratchov 582: ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
583: if (ibuf->r.midi.idx == ibuf->r.midi.len) {
1.40 ratchov 584: if (!p->u.midi.dev) {
585: midi_send(p, ibuf,
586: ibuf->r.midi.msg, ibuf->r.midi.idx);
587: } else
588: midi_onvoice(p, ibuf);
589: if (ibuf->r.midi.st >= 0xf0)
590: ibuf->r.midi.st = 0;
591: ibuf->r.midi.idx = 0;
592: } else if (ibuf->r.midi.idx == MIDI_MSGMAX) {
593: if (!p->u.midi.dev) {
594: midi_send(p, ibuf,
595: ibuf->r.midi.msg, ibuf->r.midi.idx);
596: }
1.10 ratchov 597: ibuf->r.midi.idx = 0;
1.3 ratchov 598: }
599: }
600: }
1.40 ratchov 601: /*
602: * XXX: if the sysex is received byte by byte, partial messages
603: * won't be sent until the end byte is received. On the other
604: * hand we can't flush it here, since we would loose messages
605: * we parse
606: */
1.3 ratchov 607: abuf_rdiscard(ibuf, icount);
1.40 ratchov 608: midi_flush(p);
1.3 ratchov 609: return 1;
610: }
611:
612: int
1.40 ratchov 613: midi_out(struct aproc *p, struct abuf *obuf)
1.3 ratchov 614: {
615: return 0;
616: }
617:
618: void
1.40 ratchov 619: midi_eof(struct aproc *p, struct abuf *ibuf)
1.3 ratchov 620: {
1.39 ratchov 621: if ((p->flags & APROC_QUIT) && LIST_EMPTY(&p->ins))
1.13 ratchov 622: aproc_del(p);
1.3 ratchov 623: }
624:
625: void
1.40 ratchov 626: midi_hup(struct aproc *p, struct abuf *obuf)
1.3 ratchov 627: {
1.39 ratchov 628: if ((p->flags & APROC_QUIT) && LIST_EMPTY(&p->ins))
1.13 ratchov 629: aproc_del(p);
1.3 ratchov 630: }
631:
632: void
1.40 ratchov 633: midi_newin(struct aproc *p, struct abuf *ibuf)
1.3 ratchov 634: {
1.10 ratchov 635: ibuf->r.midi.used = 0;
636: ibuf->r.midi.len = 0;
637: ibuf->r.midi.idx = 0;
638: ibuf->r.midi.st = 0;
1.40 ratchov 639: ibuf->tickets = MIDITHRU_XFER;
640: }
641:
642: void
643: midi_done(struct aproc *p)
644: {
645: timo_del(&p->u.midi.timo);
1.3 ratchov 646: }
647:
1.40 ratchov 648: struct aproc_ops midi_ops = {
649: "midi",
650: midi_in,
651: midi_out,
652: midi_eof,
653: midi_hup,
654: midi_newin,
1.3 ratchov 655: NULL, /* newout */
656: NULL, /* ipos */
657: NULL, /* opos */
1.40 ratchov 658: midi_done,
1.3 ratchov 659: };
660:
661: struct aproc *
1.40 ratchov 662: midi_new(char *name, struct dev *dev)
1.3 ratchov 663: {
664: struct aproc *p;
665:
1.40 ratchov 666: p = aproc_new(&midi_ops, name);
667: timo_set(&p->u.midi.timo, midi_cb, p);
668: timo_add(&p->u.midi.timo, MIDITHRU_TIMO);
669: p->u.midi.dev = dev;
1.1 ratchov 670: return p;
671: }