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