Annotation of src/usr.bin/aucat/midi.c, Revision 1.14
1.14 ! ratchov 1: /* $OpenBSD: midi.c,v 1.13 2009/11/03 21:31:37 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"
1.14 ! ratchov 35: #ifdef DEBUG
! 36: #include "dbg.h"
! 37: #endif
1.1 ratchov 38:
39: /*
40: * input data rate is XFER / TIMO (in bytes per microsecond),
41: * it must be slightly larger than the MIDI standard 3125 bytes/s
42: */
43: #define MIDITHRU_XFER 340
44: #define MIDITHRU_TIMO 100000
45:
1.3 ratchov 46: /*
47: * masks to extract command and channel of status byte
48: */
49: #define MIDI_CMDMASK 0xf0
50: #define MIDI_CHANMASK 0x0f
51:
52: /*
53: * MIDI status bytes of voice messages
54: */
55: #define MIDI_NOFF 0x80 /* note off */
56: #define MIDI_NON 0x90 /* note on */
57: #define MIDI_KAT 0xa0 /* key after touch */
58: #define MIDI_CTL 0xb0 /* controller */
59: #define MIDI_PC 0xc0 /* program change */
60: #define MIDI_CAT 0xd0 /* channel after touch */
61: #define MIDI_BEND 0xe0 /* pitch bend */
62:
63: /*
64: * MIDI controller numbers
65: */
66: #define MIDI_CTLVOL 7 /* volume */
67: #define MIDI_CTLPAN 11 /* pan */
68:
69: /*
70: * length of voice and common messages (status byte included)
71: */
1.1 ratchov 72: unsigned voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
73: unsigned common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
74:
1.7 ratchov 75: /*
1.10 ratchov 76: * send the message stored in of ibuf->r.midi.msg to obuf
1.7 ratchov 77: */
1.1 ratchov 78: void
79: thru_flush(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
80: {
81: unsigned ocount, itodo;
82: unsigned char *odata, *idata;
83:
1.10 ratchov 84: itodo = ibuf->r.midi.used;
85: idata = ibuf->r.midi.msg;
1.14 ! ratchov 86: #ifdef DEBUG
! 87: if (debug_level >= 4) {
! 88: aproc_dbg(p);
! 89: dbg_puts(": flushing ");
! 90: dbg_putu(itodo);
! 91: dbg_puts(" byte message\n");
! 92: }
! 93: #endif
1.1 ratchov 94: while (itodo > 0) {
95: if (!ABUF_WOK(obuf)) {
1.14 ! ratchov 96: #ifdef DEBUG
! 97: if (debug_level >= 4) {
! 98: aproc_dbg(p);
! 99: dbg_puts(": overrun, discarding ");
! 100: dbg_putu(obuf->used);
! 101: dbg_puts(" bytes\n");
! 102: }
! 103: #endif
1.1 ratchov 104: abuf_rdiscard(obuf, obuf->used);
105: if (p->u.thru.owner == ibuf)
106: p->u.thru.owner = NULL;
107: return;
108: }
109: odata = abuf_wgetblk(obuf, &ocount, 0);
110: if (ocount > itodo)
111: ocount = itodo;
112: memcpy(odata, idata, ocount);
113: abuf_wcommit(obuf, ocount);
114: itodo -= ocount;
115: idata += ocount;
116: }
1.10 ratchov 117: ibuf->r.midi.used = 0;
1.1 ratchov 118: p->u.thru.owner = ibuf;
119: }
120:
1.7 ratchov 121: /*
122: * send the real-time message (one byte) to obuf, similar to thrui_flush()
123: */
1.1 ratchov 124: void
125: thru_rt(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned c)
126: {
127: unsigned ocount;
128: unsigned char *odata;
129:
1.14 ! ratchov 130: #ifdef DEBUG
! 131: if (debug_level >= 4) {
! 132: aproc_dbg(p);
! 133: dbg_puts(": ");
! 134: dbg_putu(c);
! 135: dbg_puts(": flushing realtime message\n");
! 136: }
! 137: #endif
1.1 ratchov 138: if (!ABUF_WOK(obuf)) {
1.14 ! ratchov 139: #ifdef DEBUG
! 140: if (debug_level >= 4) {
! 141: aproc_dbg(p);
! 142: dbg_puts(": overrun, discarding ");
! 143: dbg_putu(obuf->used);
! 144: dbg_puts(" bytes\n");
! 145: }
! 146: #endif
1.1 ratchov 147: abuf_rdiscard(obuf, obuf->used);
148: if (p->u.thru.owner == ibuf)
149: p->u.thru.owner = NULL;
150: }
151: odata = abuf_wgetblk(obuf, &ocount, 0);
152: odata[0] = c;
153: abuf_wcommit(obuf, 1);
154: }
155:
1.7 ratchov 156: /*
157: * parse ibuf contents and store each message into obuf,
158: * use at most ``todo'' bytes (for throttling)
159: */
1.1 ratchov 160: void
161: thru_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned todo)
162: {
163: unsigned char *idata;
164: unsigned c, icount, ioffs;
165:
166: idata = NULL;
167: icount = ioffs = 0;
168: for (;;) {
169: if (icount == 0) {
170: if (todo == 0)
171: break;
172: idata = abuf_rgetblk(ibuf, &icount, ioffs);
173: if (icount > todo)
174: icount = todo;
175: if (icount == 0)
176: break;
177: todo -= icount;
178: ioffs += icount;
179: }
180: c = *idata++;
181: icount--;
182: if (c < 0x80) {
1.10 ratchov 183: if (ibuf->r.midi.idx == 0 && ibuf->r.midi.st) {
184: ibuf->r.midi.msg[ibuf->r.midi.used++] = ibuf->r.midi.st;
185: ibuf->r.midi.idx++;
1.1 ratchov 186: }
1.10 ratchov 187: ibuf->r.midi.msg[ibuf->r.midi.used++] = c;
188: ibuf->r.midi.idx++;
189: if (ibuf->r.midi.idx == ibuf->r.midi.len) {
1.1 ratchov 190: thru_flush(p, ibuf, obuf);
1.10 ratchov 191: if (ibuf->r.midi.st >= 0xf0)
192: ibuf->r.midi.st = 0;
193: ibuf->r.midi.idx = 0;
1.1 ratchov 194: }
1.10 ratchov 195: if (ibuf->r.midi.used == MIDI_MSGMAX) {
196: if (ibuf->r.midi.used == ibuf->r.midi.idx ||
1.1 ratchov 197: p->u.thru.owner == ibuf)
198: thru_flush(p, ibuf, obuf);
199: else
1.10 ratchov 200: ibuf->r.midi.used = 0;
1.1 ratchov 201: }
202: } else if (c < 0xf8) {
1.10 ratchov 203: if (ibuf->r.midi.used == ibuf->r.midi.idx ||
1.1 ratchov 204: p->u.thru.owner == ibuf) {
205: thru_flush(p, ibuf, obuf);
206: } else
1.10 ratchov 207: ibuf->r.midi.used = 0;
208: ibuf->r.midi.msg[0] = c;
209: ibuf->r.midi.used = 1;
210: ibuf->r.midi.len = (c >= 0xf0) ?
1.1 ratchov 211: common_len[c & 7] :
212: voice_len[(c >> 4) & 7];
1.10 ratchov 213: if (ibuf->r.midi.len == 1) {
1.1 ratchov 214: thru_flush(p, ibuf, obuf);
1.10 ratchov 215: ibuf->r.midi.idx = 0;
216: ibuf->r.midi.st = 0;
217: ibuf->r.midi.len = 0;
1.1 ratchov 218: } else {
1.10 ratchov 219: ibuf->r.midi.st = c;
220: ibuf->r.midi.idx = 1;
1.1 ratchov 221: }
222: } else {
223: thru_rt(p, ibuf, obuf, c);
224: }
225: }
226: }
227:
228: int
229: thru_in(struct aproc *p, struct abuf *ibuf)
230: {
231: struct abuf *i, *inext;
232: unsigned todo;
233:
234: if (!ABUF_ROK(ibuf))
235: return 0;
1.10 ratchov 236: if (ibuf->tickets == 0) {
1.14 ! ratchov 237: #ifdef DEBUG
! 238: if (debug_level >= 4) {
! 239: abuf_dbg(ibuf);
! 240: dbg_puts(": out of tickets, blocking\n");
! 241: }
! 242: #endif
1.1 ratchov 243: return 0;
244: }
245: todo = ibuf->used;
1.10 ratchov 246: if (todo > ibuf->tickets)
247: todo = ibuf->tickets;
248: ibuf->tickets -= todo;
1.1 ratchov 249: for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
250: inext = LIST_NEXT(i, oent);
251: if (ibuf->duplex == i)
252: continue;
253: thru_bcopy(p, ibuf, i, todo);
254: (void)abuf_flush(i);
255: }
256: abuf_rdiscard(ibuf, todo);
257: return 1;
258: }
259:
260: int
261: thru_out(struct aproc *p, struct abuf *obuf)
262: {
263: return 0;
264: }
265:
266: void
267: thru_eof(struct aproc *p, struct abuf *ibuf)
268: {
1.13 ratchov 269: if (!(p->flags & APROC_QUIT))
1.11 ratchov 270: return;
271: if (LIST_EMPTY(&p->obuflist) || LIST_EMPTY(&p->ibuflist))
272: aproc_del(p);
1.1 ratchov 273: }
274:
275: void
276: thru_hup(struct aproc *p, struct abuf *obuf)
277: {
1.13 ratchov 278: if (!(p->flags & APROC_QUIT))
1.11 ratchov 279: return;
280: if (LIST_EMPTY(&p->obuflist) || LIST_EMPTY(&p->ibuflist))
281: aproc_del(p);
1.1 ratchov 282: }
283:
284: void
285: thru_newin(struct aproc *p, struct abuf *ibuf)
286: {
1.10 ratchov 287: ibuf->r.midi.used = 0;
288: ibuf->r.midi.len = 0;
289: ibuf->r.midi.idx = 0;
290: ibuf->r.midi.st = 0;
291: ibuf->tickets = MIDITHRU_XFER;
1.1 ratchov 292: }
293:
294: void
295: thru_done(struct aproc *p)
296: {
297: timo_del(&p->u.thru.timo);
298: }
299:
300: struct aproc_ops thru_ops = {
301: "thru",
302: thru_in,
303: thru_out,
304: thru_eof,
305: thru_hup,
306: thru_newin,
307: NULL, /* newout */
308: NULL, /* ipos */
309: NULL, /* opos */
310: thru_done
311: };
312:
1.7 ratchov 313: /*
314: * call-back invoked periodically to implement throttling at each invocation
315: * gain more ``tickets'' for processing. If one of the buffer was blocked by
316: * the throttelling mechanism, then run it
317: */
1.1 ratchov 318: void
319: thru_cb(void *addr)
320: {
321: struct aproc *p = (struct aproc *)addr;
322: struct abuf *i, *inext;
323: unsigned tickets;
324:
325: timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
326:
327: for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
328: inext = LIST_NEXT(i, ient);
1.10 ratchov 329: tickets = i->tickets;
330: i->tickets = MIDITHRU_XFER;
1.1 ratchov 331: if (tickets == 0)
332: abuf_run(i);
333: }
334: }
335:
336: struct aproc *
337: thru_new(char *name)
338: {
339: struct aproc *p;
340:
341: p = aproc_new(&thru_ops, name);
342: p->u.thru.owner = NULL;
343: timo_set(&p->u.thru.timo, thru_cb, p);
344: timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
1.3 ratchov 345: return p;
346: }
347:
1.14 ! ratchov 348: #ifdef DEBUG
! 349: void
! 350: ctl_slotdbg(struct aproc *p, int slot)
! 351: {
! 352: struct ctl_slot *s;
! 353:
! 354: aproc_dbg(p);
! 355: if (slot < 0) {
! 356: dbg_puts("/none");
! 357: } else {
! 358: s = p->u.ctl.slot + slot;
! 359: dbg_puts(s->name);
! 360: dbg_putu(s->unit);
! 361: dbg_puts("=");
! 362: dbg_putu(s->vol);
! 363: dbg_puts("/");
! 364: switch (s->tstate) {
! 365: case CTL_OFF:
! 366: dbg_puts("off");
! 367: break;
! 368: case CTL_RUN:
! 369: dbg_puts("run");
! 370: break;
! 371: case CTL_START:
! 372: dbg_puts("sta");
! 373: break;
! 374: case CTL_STOP:
! 375: dbg_puts("stp");
! 376: break;
! 377: default:
! 378: dbg_puts("unk");
! 379: break;
! 380: }
! 381: }
! 382: }
! 383: #endif
1.12 ratchov 384:
1.7 ratchov 385: /*
386: * broadcast a message to all output buffers on the behalf of ibuf.
387: * ie. don't sent back the message to the sender
388: */
1.3 ratchov 389: void
390: ctl_sendmsg(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len)
391: {
392: unsigned ocount, itodo;
393: unsigned char *odata, *idata;
394: struct abuf *i, *inext;
395:
396: for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
397: inext = LIST_NEXT(i, oent);
398: if (i->duplex == ibuf)
399: continue;
400: itodo = len;
401: idata = msg;
402: while (itodo > 0) {
403: if (!ABUF_WOK(i)) {
1.14 ! ratchov 404: #ifdef DEBUG
! 405: if (debug_level >= 4) {
! 406: abuf_dbg(i);
! 407: dbg_puts(": overrun, discarding ");
! 408: dbg_putu(i->used);
! 409: dbg_puts(" bytes\n");
! 410: }
! 411: #endif
1.3 ratchov 412: abuf_rdiscard(i, i->used);
413: }
414: odata = abuf_wgetblk(i, &ocount, 0);
415: if (ocount > itodo)
416: ocount = itodo;
1.14 ! ratchov 417: #ifdef DEBUG
! 418: if (debug_level >= 4) {
! 419: abuf_dbg(i);
! 420: dbg_puts(": stored ");
! 421: dbg_putu(ocount);
! 422: dbg_puts(" bytes\n");
! 423: }
! 424: #endif
1.3 ratchov 425: memcpy(odata, idata, ocount);
426: abuf_wcommit(i, ocount);
427: itodo -= ocount;
428: idata += ocount;
429: }
430: (void)abuf_flush(i);
431: }
432: }
433:
1.7 ratchov 434: /*
1.13 ratchov 435: * send a quarter frame MTC message
436: */
437: void
438: ctl_qfr(struct aproc *p)
439: {
440: unsigned char buf[2];
441: unsigned data;
442:
443: switch (p->u.ctl.qfr) {
444: case 0:
445: data = p->u.ctl.fr & 0xf;
446: break;
447: case 1:
448: data = p->u.ctl.fr >> 4;
449: break;
450: case 2:
451: data = p->u.ctl.sec & 0xf;
452: break;
453: case 3:
454: data = p->u.ctl.sec >> 4;
455: break;
456: case 4:
457: data = p->u.ctl.min & 0xf;
458: break;
459: case 5:
460: data = p->u.ctl.min >> 4;
461: break;
462: case 6:
463: data = p->u.ctl.hr & 0xf;
464: break;
465: case 7:
466: data = (p->u.ctl.hr >> 4) | (p->u.ctl.fps_id << 1);
467: /*
468: * tick messages are sent 2 frames ahead
469: */
470: p->u.ctl.fr += 2;
471: if (p->u.ctl.fr < p->u.ctl.fps)
472: break;
473: p->u.ctl.fr -= p->u.ctl.fps;
474: p->u.ctl.sec++;
475: if (p->u.ctl.sec < 60)
476: break;;
477: p->u.ctl.sec = 0;
478: p->u.ctl.min++;
479: if (p->u.ctl.min < 60)
480: break;
481: p->u.ctl.min = 0;
482: p->u.ctl.hr++;
483: if (p->u.ctl.hr < 24)
484: break;
485: p->u.ctl.hr = 0;
486: break;
487: default:
488: /* NOTREACHED */
489: data = 0;
490: }
491: buf[0] = 0xf1;
492: buf[1] = (p->u.ctl.qfr << 4) | data;
493: p->u.ctl.qfr++;
494: p->u.ctl.qfr &= 7;
495: ctl_sendmsg(p, NULL, buf, 2);
496: }
497:
498: /*
499: * send a full frame MTC message
500: */
501: void
502: ctl_full(struct aproc *p)
503: {
504: unsigned char buf[10];
505: unsigned origin = p->u.ctl.origin;
506: unsigned fps = p->u.ctl.fps;
507:
508: p->u.ctl.hr = (origin / (3600 * MTC_SEC)) % 24;
509: p->u.ctl.min = (origin / (60 * MTC_SEC)) % 60;
510: p->u.ctl.sec = (origin / MTC_SEC) % 60;
511: p->u.ctl.fr = (origin / (MTC_SEC / fps)) % fps;
512:
513: buf[0] = 0xf0;
514: buf[1] = 0x7f;
515: buf[2] = 0x7f;
516: buf[3] = 0x01;
517: buf[4] = 0x01;
518: buf[5] = p->u.ctl.hr | (p->u.ctl.fps_id << 5);
519: buf[6] = p->u.ctl.min;
520: buf[7] = p->u.ctl.sec;
521: buf[8] = p->u.ctl.fr;
522: buf[9] = 0xf7;
523: p->u.ctl.qfr = 0;
524: ctl_sendmsg(p, NULL, buf, 10);
525: }
526:
527: /*
1.12 ratchov 528: * find the best matching free slot index (ie midi channel).
529: * return -1, if there are no free slots anymore
1.7 ratchov 530: */
1.3 ratchov 531: int
1.12 ratchov 532: ctl_getidx(struct aproc *p, char *who)
1.3 ratchov 533: {
534: char *s;
535: struct ctl_slot *slot;
1.4 ratchov 536: char name[CTL_NAMEMAX];
537: unsigned i, unit, umap = 0;
1.6 ratchov 538: unsigned ser, bestser, bestidx;
1.3 ratchov 539:
1.4 ratchov 540: /*
541: * create a ``valid'' control name (lowcase, remove [^a-z], trucate)
542: */
1.5 ratchov 543: for (i = 0, s = who; ; s++) {
1.4 ratchov 544: if (i == CTL_NAMEMAX - 1 || *s == '\0') {
545: name[i] = '\0';
546: break;
547: } else if (*s >= 'A' && *s <= 'Z') {
548: name[i++] = *s + 'a' - 'A';
549: } else if (*s >= 'a' && *s <= 'z')
550: name[i++] = *s;
551: }
552: if (i == 0)
553: strlcpy(name, "noname", CTL_NAMEMAX);
554:
555: /*
556: * find the instance number of the control name
557: */
558: for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.12 ratchov 559: if (slot->ops == NULL)
1.4 ratchov 560: continue;
561: if (strcmp(slot->name, name) == 0)
562: umap |= (1 << i);
563: }
1.12 ratchov 564: for (unit = 0; ; unit++) {
1.4 ratchov 565: if (unit == CTL_NSLOT)
1.3 ratchov 566: return -1;
1.12 ratchov 567: if ((umap & (1 << unit)) == 0)
1.3 ratchov 568: break;
569: }
1.14 ! ratchov 570: #ifdef DEBUG
! 571: if (debug_level >= 3) {
! 572: aproc_dbg(p);
! 573: dbg_puts(": new control name is ");
! 574: dbg_puts(name);
! 575: dbg_putu(unit);
! 576: dbg_puts("\n");
! 577: }
! 578: #endif
1.4 ratchov 579: /*
580: * find a free controller slot with the same name/unit
581: */
582: for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.12 ratchov 583: if (slot->ops == NULL &&
1.4 ratchov 584: strcmp(slot->name, name) == 0 &&
585: slot->unit == unit) {
1.14 ! ratchov 586: #ifdef DEBUG
! 587: if (debug_level >= 3) {
! 588: aproc_dbg(p);
! 589: dbg_puts(": found slot ");
! 590: dbg_putu(i);
! 591: dbg_puts("\n");
! 592: }
! 593: #endif
1.4 ratchov 594: return i;
595: }
596: }
597:
598: /*
1.6 ratchov 599: * couldn't find a matching slot, pick oldest free slot
1.12 ratchov 600: * and set its name/unit
1.4 ratchov 601: */
1.6 ratchov 602: bestser = 0;
603: bestidx = CTL_NSLOT;
604: for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.12 ratchov 605: if (slot->ops != NULL)
1.6 ratchov 606: continue;
607: ser = p->u.ctl.serial - slot->serial;
608: if (ser > bestser) {
609: bestser = ser;
610: bestidx = i;
611: }
1.3 ratchov 612: }
1.6 ratchov 613: if (bestidx == CTL_NSLOT)
614: return -1;
615: slot = p->u.ctl.slot + bestidx;
1.4 ratchov 616: strlcpy(slot->name, name, CTL_NAMEMAX);
1.6 ratchov 617: slot->serial = p->u.ctl.serial++;
1.4 ratchov 618: slot->unit = unit;
1.7 ratchov 619: slot->vol = MIDI_MAXCTL;
1.14 ! ratchov 620: #ifdef DEBUG
! 621: if (debug_level >= 3) {
! 622: aproc_dbg(p);
! 623: dbg_puts(": overwritten slot ");
! 624: dbg_putu(bestidx);
! 625: dbg_puts("\n");
! 626: }
! 627: #endif
1.6 ratchov 628: return bestidx;
1.3 ratchov 629: }
630:
1.7 ratchov 631: /*
1.13 ratchov 632: * check that all clients controlled by MMC are ready to start,
633: * if so, start them all but the caller
634: */
635: int
636: ctl_trystart(struct aproc *p, int caller)
637: {
638: unsigned i;
639: struct ctl_slot *s;
640:
641: if (p->u.ctl.tstate != CTL_START) {
1.14 ! ratchov 642: #ifdef DEBUG
! 643: aproc_dbg(p);
! 644: dbg_puts(": not in starting state\n");
! 645: #endif
1.13 ratchov 646: return 0;
647: }
648: for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
649: if (!s->ops || i == caller)
650: continue;
651: if (s->tstate != CTL_OFF && s->tstate != CTL_START) {
1.14 ! ratchov 652: #ifdef DEBUG
! 653: ctl_slotdbg(p, i);
! 654: dbg_puts(": not ready to start, start delayed\n");
! 655: #endif
1.13 ratchov 656: return 0;
657: }
658: }
659: for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
660: if (!s->ops || i == caller)
661: continue;
662: if (s->tstate == CTL_START) {
1.14 ! ratchov 663: #ifdef DEBUG
! 664: ctl_slotdbg(p, i);
! 665: dbg_puts(": started\n");
! 666: #endif
1.13 ratchov 667: s->tstate = CTL_RUN;
668: s->ops->start(s->arg);
669: }
670: }
671: if (caller >= 0)
672: p->u.ctl.slot[caller].tstate = CTL_RUN;
673: p->u.ctl.tstate = CTL_RUN;
674: p->u.ctl.delta = MTC_SEC * dev_getpos();
675: if (dev_rate % (30 * 4 * dev_round)) {
676: p->u.ctl.fps_id = MTC_FPS_30;
677: p->u.ctl.fps = 30;
678: } else if (dev_rate % (25 * 4 * dev_round)) {
679: p->u.ctl.fps_id = MTC_FPS_25;
680: p->u.ctl.fps = 25;
681: } else {
682: p->u.ctl.fps_id = MTC_FPS_24;
683: p->u.ctl.fps = 24;
684: }
1.14 ! ratchov 685: #ifdef DEBUG
! 686: ctl_slotdbg(p, caller);
! 687: dbg_puts(": started server at ");
! 688: dbg_puti(p->u.ctl.delta);
! 689: dbg_puts(", ");
! 690: dbg_puti(p->u.ctl.fps);
! 691: dbg_puts(" mtc fps\n");
! 692: #endif
1.13 ratchov 693: ctl_full(p);
694: return 1;
695: }
696:
697: /*
1.12 ratchov 698: * allocate a new slot and register the given call-backs
699: */
700: int
1.13 ratchov 701: ctl_slotnew(struct aproc *p, char *who, struct ctl_ops *ops, void *arg, int tr)
1.12 ratchov 702: {
703: int idx;
704: struct ctl_slot *s;
705:
1.13 ratchov 706: if (p == NULL)
707: return -1;
1.12 ratchov 708: idx = ctl_getidx(p, who);
709: if (idx < 0)
710: return -1;
711:
712: s = p->u.ctl.slot + idx;
713: s->ops = ops;
714: s->arg = arg;
1.13 ratchov 715: s->tstate = tr ? CTL_STOP : CTL_OFF;
1.12 ratchov 716: s->ops->vol(s->arg, s->vol);
717: ctl_slotvol(p, idx, s->vol);
718: return idx;
719: }
720:
721: /*
1.7 ratchov 722: * release the given slot
723: */
1.3 ratchov 724: void
725: ctl_slotdel(struct aproc *p, int index)
726: {
1.13 ratchov 727: unsigned i;
728: struct ctl_slot *s;
729:
730: if (p == NULL)
731: return;
1.12 ratchov 732: p->u.ctl.slot[index].ops = NULL;
1.13 ratchov 733: if (!(p->flags & APROC_QUIT))
734: return;
735: for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
736: if (s->ops)
737: return;
738: }
739: if (!LIST_EMPTY(&p->obuflist) || !LIST_EMPTY(&p->ibuflist))
740: aproc_del(p);
741: }
742:
743: /*
744: * called at every clock tick by the mixer, delta is positive, unless
745: * there's an overrun/underrun
746: */
747: void
748: ctl_ontick(struct aproc *p, int delta)
749: {
750: int qfrlen;
751:
752: /*
753: * don't send ticks before the start signal
754: */
755: if (p->u.ctl.tstate != CTL_RUN)
756: return;
757:
758: p->u.ctl.delta += delta * MTC_SEC;
759:
760: /*
761: * don't send ticks during the count-down
762: */
763: if (p->u.ctl.delta < 0)
764: return;
765:
766: qfrlen = dev_rate * (MTC_SEC / (4 * p->u.ctl.fps));
767: while (p->u.ctl.delta >= qfrlen) {
768: ctl_qfr(p);
769: p->u.ctl.delta -= qfrlen;
770: }
1.3 ratchov 771: }
772:
1.7 ratchov 773: /*
774: * notifty the mixer that volume changed, called by whom allocad the slot using
775: * ctl_slotnew(). Note: it doesn't make sens to call this from within the
776: * call-back.
777: */
1.3 ratchov 778: void
779: ctl_slotvol(struct aproc *p, int slot, unsigned vol)
780: {
781: unsigned char msg[3];
782:
1.13 ratchov 783: if (p == NULL)
784: return;
1.14 ! ratchov 785: #ifdef DEBUG
! 786: if (debug_level >= 3) {
! 787: ctl_slotdbg(p, slot);
! 788: dbg_puts(": changing volume to ");
! 789: dbg_putu(vol);
! 790: dbg_puts("\n");
! 791: }
! 792: #endif
1.7 ratchov 793: p->u.ctl.slot[slot].vol = vol;
1.3 ratchov 794: msg[0] = MIDI_CTL | slot;
795: msg[1] = MIDI_CTLVOL;
796: msg[2] = vol;
797: ctl_sendmsg(p, NULL, msg, 3);
798: }
799:
1.7 ratchov 800: /*
1.13 ratchov 801: * notify the MMC layer that the stream is attempting
802: * to start. If other streams are not ready, 0 is returned meaning
803: * that the stream should wait. If other streams are ready, they
804: * are started, and the caller should start immediately.
805: */
806: int
807: ctl_slotstart(struct aproc *p, int slot)
808: {
809: struct ctl_slot *s = p->u.ctl.slot + slot;
810:
811: if (p == NULL)
812: return 1;
813: if (s->tstate == CTL_OFF || p->u.ctl.tstate == CTL_OFF)
814: return 1;
815:
816: /*
817: * if the server already started (the client missed the
818: * start rendez-vous) or the server is stopped, then
819: * tag the client as ``wanting to start''
820: */
821: s->tstate = CTL_START;
822: return ctl_trystart(p, slot);
823: }
824:
825: /*
826: * notify the MMC layer that the stream no longer is trying to
827: * start (or that it just stopped), meaning that its ``start'' call-back
828: * shouldn't be called anymore
829: */
830: void
831: ctl_slotstop(struct aproc *p, int slot)
832: {
833: struct ctl_slot *s = p->u.ctl.slot + slot;
834:
835: if (p == NULL)
836: return;
837: /*
838: * tag the stream as not trying to start,
839: * unless MMC is turned off
840: */
841: if (s->tstate != CTL_OFF)
842: s->tstate = CTL_STOP;
843: }
844:
845: /*
1.7 ratchov 846: * handle a MIDI event received from ibuf
847: */
1.3 ratchov 848: void
849: ctl_ev(struct aproc *p, struct abuf *ibuf)
850: {
851: unsigned chan;
1.5 ratchov 852: struct ctl_slot *slot;
1.13 ratchov 853: unsigned fps;
1.14 ! ratchov 854: #ifdef DEBUG
! 855: unsigned i;
! 856:
! 857: if (debug_level >= 3) {
! 858: abuf_dbg(ibuf);
! 859: dbg_puts(": got event:");
! 860: for (i = 0; i < ibuf->r.midi.idx; i++) {
! 861: dbg_puts(" ");
! 862: dbg_putx(ibuf->r.midi.msg[i]);
! 863: }
! 864: dbg_puts("\n");
! 865: }
! 866: #endif
1.10 ratchov 867: if ((ibuf->r.midi.msg[0] & MIDI_CMDMASK) == MIDI_CTL &&
868: ibuf->r.midi.msg[1] == MIDI_CTLVOL) {
869: chan = ibuf->r.midi.msg[0] & MIDI_CHANMASK;
1.3 ratchov 870: if (chan >= CTL_NSLOT)
871: return;
1.5 ratchov 872: slot = p->u.ctl.slot + chan;
1.12 ratchov 873: if (slot->ops == NULL)
1.3 ratchov 874: return;
1.10 ratchov 875: slot->vol = ibuf->r.midi.msg[2];
1.12 ratchov 876: slot->ops->vol(slot->arg, slot->vol);
1.10 ratchov 877: ctl_sendmsg(p, ibuf, ibuf->r.midi.msg, ibuf->r.midi.len);
1.3 ratchov 878: }
1.13 ratchov 879: if (ibuf->r.midi.idx == 6 &&
880: ibuf->r.midi.msg[0] == 0xf0 &&
881: ibuf->r.midi.msg[1] == 0x7f && /* type is realtime */
882: ibuf->r.midi.msg[3] == 0x06 && /* subtype is mmc */
883: ibuf->r.midi.msg[5] == 0xf7) { /* subtype is mmc */
884: switch (ibuf->r.midi.msg[4]) {
885: case 0x01: /* mmc stop */
1.14 ! ratchov 886: #ifdef DEBUG
! 887: if (debug_level >= 1) {
! 888: abuf_dbg(ibuf);
! 889: dbg_puts(": mmc stop\n");
! 890: }
! 891: #endif
1.13 ratchov 892: if (p->u.ctl.tstate == CTL_RUN ||
893: p->u.ctl.tstate == CTL_START)
894: p->u.ctl.tstate = CTL_STOP;
1.14 ! ratchov 895: #ifdef DEBUG
! 896: else {
! 897: if (debug_level >= 1) {
! 898: aproc_dbg(p);
! 899: dbg_puts(": ignored mmc stop\n");
! 900: }
! 901: }
! 902: #endif
1.13 ratchov 903: break;
904: case 0x02: /* mmc start */
1.14 ! ratchov 905: #ifdef DEBUG
! 906: if (debug_level >= 1) {
! 907: abuf_dbg(ibuf);
! 908: dbg_puts(": mmc start\n");
! 909: }
! 910: #endif
1.13 ratchov 911: if (p->u.ctl.tstate == CTL_STOP) {
912: p->u.ctl.tstate = CTL_START;
913: (void)ctl_trystart(p, -1);
1.14 ! ratchov 914: #ifdef DEBUG
! 915: } else {
! 916: if (debug_level >= 1) {
! 917: abuf_dbg(ibuf);
! 918: dbg_puts(": ignoring mmc start\n");
! 919: }
! 920: #endif
1.13 ratchov 921: }
922: break;
923: }
924: }
925: if (ibuf->r.midi.idx == 13 &&
926: ibuf->r.midi.msg[0] == 0xf0 &&
927: ibuf->r.midi.msg[1] == 0x7f &&
928: ibuf->r.midi.msg[3] == 0x06 &&
929: ibuf->r.midi.msg[4] == 0x44 &&
930: ibuf->r.midi.msg[5] == 0x06 &&
931: ibuf->r.midi.msg[6] == 0x01 &&
932: ibuf->r.midi.msg[12] == 0xf7) {
933: switch (ibuf->r.midi.msg[7] >> 5) {
934: case MTC_FPS_24:
935: fps = 24;
936: break;
937: case MTC_FPS_25:
938: fps = 25;
939: break;
940: case MTC_FPS_30:
941: fps = 30;
942: break;
943: default:
944: p->u.ctl.origin = 0;
945: return;
946: }
947: p->u.ctl.origin =
948: (ibuf->r.midi.msg[7] & 0x1f) * 3600 * MTC_SEC +
949: ibuf->r.midi.msg[8] * 60 * MTC_SEC +
950: ibuf->r.midi.msg[9] * MTC_SEC +
951: ibuf->r.midi.msg[10] * (MTC_SEC / fps) +
952: ibuf->r.midi.msg[11] * (MTC_SEC / 100 / fps);
1.14 ! ratchov 953: #ifdef DEBUG
! 954: if (debug_level >= 1) {
! 955: aproc_dbg(p);
! 956: dbg_puts(": relocated to ");
! 957: dbg_putu(p->u.ctl.origin);
! 958: dbg_puts("\n");
! 959: }
! 960: #endif
1.13 ratchov 961: }
1.3 ratchov 962: }
963:
964: int
965: ctl_in(struct aproc *p, struct abuf *ibuf)
966: {
967: unsigned char *idata;
968: unsigned c, i, icount;
969:
970: if (!ABUF_ROK(ibuf))
971: return 0;
972: idata = abuf_rgetblk(ibuf, &icount, 0);
973: for (i = 0; i < icount; i++) {
974: c = *idata++;
1.8 ratchov 975: if (c >= 0xf8) {
976: /* clock events not used yet */
977: } else if (c >= 0xf0) {
1.10 ratchov 978: if (ibuf->r.midi.st == 0xf0 && c == 0xf7 &&
979: ibuf->r.midi.idx < MIDI_MSGMAX) {
980: ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
1.8 ratchov 981: ctl_ev(p, ibuf);
982: continue;
983: }
1.10 ratchov 984: ibuf->r.midi.msg[0] = c;
985: ibuf->r.midi.len = common_len[c & 7];
986: ibuf->r.midi.st = c;
987: ibuf->r.midi.idx = 1;
1.3 ratchov 988: } else if (c >= 0x80) {
1.10 ratchov 989: ibuf->r.midi.msg[0] = c;
990: ibuf->r.midi.len = voice_len[(c >> 4) & 7];
991: ibuf->r.midi.st = c;
992: ibuf->r.midi.idx = 1;
993: } else if (ibuf->r.midi.st) {
994: if (ibuf->r.midi.idx == MIDI_MSGMAX)
1.8 ratchov 995: continue;
1.10 ratchov 996: if (ibuf->r.midi.idx == 0)
997: ibuf->r.midi.msg[ibuf->r.midi.idx++] = ibuf->r.midi.st;
998: ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
999: if (ibuf->r.midi.idx == ibuf->r.midi.len) {
1.3 ratchov 1000: ctl_ev(p, ibuf);
1.10 ratchov 1001: ibuf->r.midi.idx = 0;
1.3 ratchov 1002: }
1003: }
1004: }
1005: abuf_rdiscard(ibuf, icount);
1006: return 1;
1007: }
1008:
1009: int
1010: ctl_out(struct aproc *p, struct abuf *obuf)
1011: {
1012: return 0;
1013: }
1014:
1015: void
1016: ctl_eof(struct aproc *p, struct abuf *ibuf)
1017: {
1.13 ratchov 1018: unsigned i;
1019: struct ctl_slot *s;
1020:
1021: if (!(p->flags & APROC_QUIT))
1022: return;
1023: for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
1024: if (s->ops)
1025: return;
1026: }
1027: if (!LIST_EMPTY(&p->obuflist) || !LIST_EMPTY(&p->ibuflist))
1028: aproc_del(p);
1.3 ratchov 1029: }
1030:
1031: void
1032: ctl_hup(struct aproc *p, struct abuf *obuf)
1033: {
1.13 ratchov 1034: unsigned i;
1035: struct ctl_slot *s;
1036:
1037: if (!(p->flags & APROC_QUIT))
1038: return;
1039: for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
1040: if (s->ops)
1041: return;
1042: }
1043: if (!LIST_EMPTY(&p->obuflist) || !LIST_EMPTY(&p->ibuflist))
1044: aproc_del(p);
1.3 ratchov 1045: }
1046:
1047: void
1048: ctl_newin(struct aproc *p, struct abuf *ibuf)
1049: {
1.10 ratchov 1050: ibuf->r.midi.used = 0;
1051: ibuf->r.midi.len = 0;
1052: ibuf->r.midi.idx = 0;
1053: ibuf->r.midi.st = 0;
1.3 ratchov 1054: }
1055:
1056: void
1057: ctl_done(struct aproc *p)
1058: {
1.14 ! ratchov 1059: #ifdef DEBUG
! 1060: unsigned i;
! 1061: struct ctl_slot *s;
! 1062:
! 1063: for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
! 1064: /*
! 1065: * XXX: shouldn't we abord() here ?
! 1066: */
! 1067: if (s->ops != NULL) {
! 1068: ctl_slotdbg(p, i);
! 1069: dbg_puts(": still in use\n");
! 1070: }
! 1071: }
! 1072: #endif
1.3 ratchov 1073: }
1074:
1075: struct aproc_ops ctl_ops = {
1076: "ctl",
1077: ctl_in,
1078: ctl_out,
1079: ctl_eof,
1080: ctl_hup,
1081: ctl_newin,
1082: NULL, /* newout */
1083: NULL, /* ipos */
1084: NULL, /* opos */
1085: ctl_done
1086: };
1087:
1088: struct aproc *
1089: ctl_new(char *name)
1090: {
1091: struct aproc *p;
1.5 ratchov 1092: struct ctl_slot *s;
1.3 ratchov 1093: unsigned i;
1094:
1095: p = aproc_new(&ctl_ops, name);
1.6 ratchov 1096: p->u.ctl.serial = 0;
1.13 ratchov 1097: p->u.ctl.tstate = CTL_STOP;
1.5 ratchov 1098: for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
1.3 ratchov 1099: p->u.ctl.slot[i].unit = i;
1.12 ratchov 1100: p->u.ctl.slot[i].ops = NULL;
1.7 ratchov 1101: p->u.ctl.slot[i].vol = MIDI_MAXCTL;
1.13 ratchov 1102: p->u.ctl.slot[i].tstate = CTL_OFF;
1.6 ratchov 1103: p->u.ctl.slot[i].serial = p->u.ctl.serial++;
1.3 ratchov 1104: strlcpy(p->u.ctl.slot[i].name, "unknown", CTL_NAMEMAX);
1105: }
1.1 ratchov 1106: return p;
1107: }