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