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