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