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