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