Annotation of src/usr.bin/sndiod/midi.c, Revision 1.8
1.8 ! ratchov 1: /* $OpenBSD: midi.c,v 1.7 2012/12/20 16:15:55 ratchov Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2008-2012 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: #include <stdio.h>
18: #include <stdlib.h>
19: #include <string.h>
20:
21: #include "abuf.h"
22: #include "defs.h"
23: #include "dev.h"
24: #include "file.h"
25: #include "midi.h"
26: #include "miofile.h"
27: #include "sysex.h"
28: #include "utils.h"
29:
30: /*
31: * input data rate is XFER / TIMO (in bytes per microsecond),
32: * it must be slightly larger than the MIDI standard 3125 bytes/s
33: */
34: #define MIDI_XFER 1
35: #define MIDI_TIMO 100000
36:
37: int port_open(struct port *);
38: void port_imsg(void *, unsigned char *, int);
39: void port_omsg(void *, unsigned char *, int);
40: void port_fill(void *, int);
41: void port_exit(void *);
42:
43: struct midiops port_midiops = {
44: port_imsg,
45: port_omsg,
46: port_fill,
47: port_exit
48: };
49:
50: #define MIDI_NEP 32
51: struct midi midi_ep[MIDI_NEP];
52: struct timo midi_timo;
53: struct port *port_list = NULL;
54: unsigned int midi_portnum = 0;
55:
56: struct midithru {
1.2 ratchov 57: unsigned int txmask, rxmask;
1.1 ratchov 58: #define MIDITHRU_NMAX 32
59: } midithru[MIDITHRU_NMAX];
60:
61: /*
62: * length of voice and common messages (status byte included)
63: */
64: unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
65: unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
66:
67: void
68: midi_log(struct midi *ep)
69: {
70: log_puts("midi");
71: log_putu(ep - midi_ep);
72: }
73:
74: void
75: midi_ontimo(void *arg)
76: {
77: int i;
78: struct midi *ep;
79:
80: for (i = MIDI_NEP, ep = midi_ep; i > 0; i--, ep++) {
81: }
82: timo_add(&midi_timo, MIDI_TIMO);
83: }
84:
85: void
86: midi_init(void)
87: {
88: timo_set(&midi_timo, midi_ontimo, NULL);
89: timo_add(&midi_timo, MIDI_TIMO);
90: }
91:
92: void
93: midi_done(void)
94: {
95: timo_del(&midi_timo);
96: }
97:
98: struct midi *
99: midi_new(struct midiops *ops, void *arg, int mode)
100: {
101: int i;
102: struct midi *ep;
103:
104: for (i = 0, ep = midi_ep;; i++, ep++) {
105: if (i == MIDI_NEP)
106: return NULL;
107: if (ep->ops == NULL)
108: break;
109: }
110: ep->ops = ops;
111: ep->arg = arg;
112: ep->used = 0;
113: ep->len = 0;
114: ep->idx = 0;
115: ep->st = 0;
116: ep->txmask = 0;
1.2 ratchov 117: ep->self = 1 << i;
118: ep->tickets = 0;
1.1 ratchov 119: ep->mode = mode;
1.2 ratchov 120:
1.1 ratchov 121: /*
1.2 ratchov 122: * the output buffer is the client intput
1.1 ratchov 123: */
1.2 ratchov 124: if (ep->mode & MODE_MIDIIN)
1.1 ratchov 125: abuf_init(&ep->obuf, MIDI_BUFSZ);
1.2 ratchov 126: midi_tickets(ep);
1.1 ratchov 127: return ep;
128: }
129:
130: void
131: midi_del(struct midi *ep)
132: {
133: int i;
1.2 ratchov 134: struct midi *peer;
1.1 ratchov 135:
1.2 ratchov 136: ep->txmask = 0;
137: for (i = 0; i < MIDI_NEP; i++) {
138: peer = midi_ep + i;
139: if (peer->txmask & ep->self) {
140: peer->txmask &= ~ep->self;
141: midi_tickets(peer);
142: }
143: }
144: for (i = 0; i < MIDITHRU_NMAX; i++) {
145: midithru[i].txmask &= ~ep->self;
146: midithru[i].rxmask &= ~ep->self;
147: }
1.1 ratchov 148: ep->ops = NULL;
149: if (ep->mode & MODE_MIDIIN) {
150: abuf_done(&ep->obuf);
151: }
152: }
153:
154: /*
1.2 ratchov 155: * connect two midi endpoints
1.1 ratchov 156: */
157: void
1.2 ratchov 158: midi_link(struct midi *ep, struct midi *peer)
1.1 ratchov 159: {
1.2 ratchov 160: if (ep->mode & MODE_MIDIOUT) {
161: ep->txmask |= peer->self;
162: midi_tickets(ep);
163: }
164: if (ep->mode & MODE_MIDIIN) {
165: #ifdef DEBUG
166: if (ep->obuf.used > 0) {
167: midi_log(ep);
168: log_puts(": linked with non-empty buffer\n");
169: panic();
170: }
171: #endif
172: /* ep has empry buffer, so no need to call midi_tickets() */
173: peer->txmask |= ep->self;
1.1 ratchov 174: }
175: }
176:
177: /*
1.2 ratchov 178: * add the midi endpoint in the ``tag'' midi thru box
1.1 ratchov 179: */
180: void
1.2 ratchov 181: midi_tag(struct midi *ep, unsigned int tag)
1.1 ratchov 182: {
1.2 ratchov 183: struct midi *peer;
184: struct midithru *t = midithru + tag;
1.1 ratchov 185: int i;
186:
1.2 ratchov 187: if (ep->mode & MODE_MIDIOUT) {
188: ep->txmask |= t->txmask;
189: midi_tickets(ep);
190: }
191: if (ep->mode & MODE_MIDIIN) {
192: #ifdef DEBUG
193: if (ep->obuf.used > 0) {
194: midi_log(ep);
195: log_puts(": tagged with non-empty buffer\n");
196: panic();
197: }
198: #endif
199: for (i = 0; i < MIDI_NEP; i++) {
200: if (!(t->rxmask & (1 << i)))
201: continue;
202: peer = midi_ep + i;
203: peer->txmask |= ep->self;
204: }
1.1 ratchov 205: }
1.2 ratchov 206: if (ep->mode & MODE_MIDIOUT)
207: t->rxmask |= ep->self;
208: if (ep->mode & MODE_MIDIIN)
209: t->txmask |= ep->self;
1.1 ratchov 210: }
211:
212: /*
1.6 ratchov 213: * broadcast the given message to other endpoints
1.1 ratchov 214: */
215: void
216: midi_send(struct midi *iep, unsigned char *msg, int size)
217: {
218: struct midi *oep;
219: int i;
220:
221: #ifdef DEBUG
222: if (log_level >= 4) {
223: midi_log(iep);
224: log_puts(": sending:");
225: for (i = 0; i < size; i++) {
226: log_puts(" ");
227: log_putx(msg[i]);
228: }
229: log_puts("\n");
230: }
231: #endif
232: for (i = 0; i < MIDI_NEP ; i++) {
233: if ((iep->txmask & (1 << i)) == 0)
234: continue;
235: oep = midi_ep + i;
236: if (msg[0] <= 0x7f) {
237: if (oep->owner != iep)
238: continue;
239: } else if (msg[0] <= 0xf7)
240: oep->owner = iep;
241: #ifdef DEBUG
242: if (log_level >= 4) {
243: midi_log(iep);
244: log_puts(" -> ");
245: midi_log(oep);
246: log_puts("\n");
247: }
248: #endif
249: oep->ops->omsg(oep->arg, msg, size);
250: }
251: }
252:
1.2 ratchov 253: /*
254: * determine if we have gained more input tickets, and if so call the
255: * fill() call-back to notify the i/o layer that it can send more data
256: */
257: void
258: midi_tickets(struct midi *iep)
259: {
260: int i, tickets, avail, maxavail;
261: struct midi *oep;
262:
263: maxavail = MIDI_BUFSZ;
264: for (i = 0; i < MIDI_NEP ; i++) {
265: if ((iep->txmask & (1 << i)) == 0)
266: continue;
267: oep = midi_ep + i;
268: avail = oep->obuf.len - oep->obuf.used;
269: if (maxavail > avail)
270: maxavail = avail;
271: }
272:
273: /*
274: * in the worst case output message is twice the
275: * input message (2-byte messages with running status)
276: */
277: tickets = maxavail / 2 - iep->tickets;
278: if (tickets > 0) {
279: iep->tickets += tickets;
280: iep->ops->fill(iep->arg, tickets);
281: }
282: }
283:
284: /*
285: * recalculate tickets of endpoints sending data to this one
286: */
1.1 ratchov 287: void
288: midi_fill(struct midi *oep)
289: {
1.2 ratchov 290: int i;
1.1 ratchov 291: struct midi *iep;
292:
1.2 ratchov 293: for (i = 0; i < MIDI_NEP; i++) {
1.1 ratchov 294: iep = midi_ep + i;
1.2 ratchov 295: if (iep->txmask & oep->self)
296: midi_tickets(iep);
1.1 ratchov 297: }
298: }
299:
300: /*
1.2 ratchov 301: * parse then give data chunk, and calling imsg() for each message
1.1 ratchov 302: */
303: void
1.2 ratchov 304: midi_in(struct midi *iep, unsigned char *idata, int icount)
1.1 ratchov 305: {
306: int i;
307: unsigned char c;
308:
309: for (i = 0; i < icount; i++) {
310: c = *idata++;
311: if (c >= 0xf8) {
312: if (c != MIDI_ACK)
313: iep->ops->imsg(iep->arg, &c, 1);
314: } else if (c == SYSEX_END) {
315: if (iep->st == SYSEX_START) {
316: iep->msg[iep->idx++] = c;
317: iep->ops->imsg(iep->arg, iep->msg, iep->idx);
318: }
319: iep->st = 0;
320: iep->idx = 0;
321: } else if (c >= 0xf0) {
322: iep->msg[0] = c;
323: iep->len = common_len[c & 7];
324: iep->st = c;
325: iep->idx = 1;
326: } else if (c >= 0x80) {
327: iep->msg[0] = c;
328: iep->len = voice_len[(c >> 4) & 7];
329: iep->st = c;
330: iep->idx = 1;
331: } else if (iep->st) {
332: if (iep->idx == 0 && iep->st != SYSEX_START)
333: iep->msg[iep->idx++] = iep->st;
334: iep->msg[iep->idx++] = c;
335: if (iep->idx == iep->len) {
336: iep->ops->imsg(iep->arg, iep->msg, iep->idx);
337: if (iep->st >= 0xf0)
338: iep->st = 0;
339: iep->idx = 0;
340: } else if (iep->idx == MIDI_MSGMAX) {
341: /* sysex continued */
342: iep->ops->imsg(iep->arg, iep->msg, iep->idx);
343: iep->idx = 0;
344: }
345: }
346: }
1.2 ratchov 347: iep->tickets -= icount;
348: if (iep->tickets < 0)
349: iep->tickets = 0;
1.7 ratchov 350: midi_tickets(iep);
1.1 ratchov 351: }
352:
353: /*
354: * store the given message in the output buffer
355: */
356: void
357: midi_out(struct midi *oep, unsigned char *idata, int icount)
358: {
359: unsigned char *odata;
360: int ocount;
361: #ifdef DEBUG
362: int i;
363: #endif
364:
365: while (icount > 0) {
366: if (oep->obuf.used == oep->obuf.len) {
367: #ifdef DEBUG
368: if (log_level >= 2) {
369: midi_log(oep);
1.2 ratchov 370: log_puts(": too slow, discarding ");
1.1 ratchov 371: log_putu(oep->obuf.used);
372: log_puts(" bytes\n");
373: }
374: #endif
375: abuf_rdiscard(&oep->obuf, oep->obuf.used);
376: oep->owner = NULL;
377: return;
378: }
379: odata = abuf_wgetblk(&oep->obuf, &ocount);
380: if (ocount > icount)
381: ocount = icount;
382: memcpy(odata, idata, ocount);
383: #ifdef DEBUG
384: if (log_level >= 4) {
385: midi_log(oep);
386: log_puts(": out: ");
387: for (i = 0; i < ocount; i++) {
388: log_puts(" ");
389: log_putx(odata[i]);
390: }
391: log_puts("\n");
392: }
393: #endif
394: abuf_wcommit(&oep->obuf, ocount);
395: icount -= ocount;
396: idata += ocount;
397: }
398: }
399:
400: #ifdef DEBUG
401: void
402: port_log(struct port *p)
403: {
404: midi_log(p->midi);
405: }
406: #endif
407:
408: void
409: port_imsg(void *arg, unsigned char *msg, int size)
410: {
411: struct port *p = arg;
412:
413: midi_send(p->midi, msg, size);
414: }
415:
416:
417: void
418: port_omsg(void *arg, unsigned char *msg, int size)
419: {
420: struct port *p = arg;
421:
422: midi_out(p->midi, msg, size);
423: }
424:
425: void
426: port_fill(void *arg, int count)
427: {
428: /* no flow control */
429: }
430:
431: void
432: port_exit(void *arg)
433: {
434: #ifdef DEBUG
435: struct port *p = arg;
436:
437: if (log_level >= 3) {
438: port_log(p);
1.3 ratchov 439: log_puts(": port exit\n");
440: panic();
1.1 ratchov 441: }
442: #endif
443: }
444:
445: /*
446: * create a new midi port
447: */
448: struct port *
1.4 ratchov 449: port_new(char *path, unsigned int mode, int hold)
1.1 ratchov 450: {
451: struct port *c;
452:
453: c = xmalloc(sizeof(struct port));
454: c->path = path;
455: c->state = PORT_CFG;
1.4 ratchov 456: c->hold = hold;
1.1 ratchov 457: c->midi = midi_new(&port_midiops, c, mode);
458: midi_portnum++;
459: c->next = port_list;
460: port_list = c;
461: return c;
462: }
463:
464: /*
465: * destroy the given midi port
466: */
467: void
468: port_del(struct port *c)
469: {
470: struct port **p;
471:
472: if (c->state != PORT_CFG)
473: port_close(c);
474: midi_del(c->midi);
475: for (p = &port_list; *p != c; p = &(*p)->next) {
476: #ifdef DEBUG
477: if (*p == NULL) {
478: log_puts("port to delete not on list\n");
479: panic();
480: }
481: #endif
482: }
483: *p = c->next;
484: xfree(c);
485: }
486:
1.3 ratchov 487: int
488: port_ref(struct port *c)
489: {
490: #ifdef DEBUG
491: if (log_level >= 3) {
492: port_log(c);
493: log_puts(": port requested\n");
494: }
495: #endif
496: if (c->state == PORT_CFG && !port_open(c))
497: return 0;
498: return 1;
499: }
500:
501: void
502: port_unref(struct port *c)
503: {
504: int i, rxmask;
505:
506: #ifdef DEBUG
507: if (log_level >= 3) {
508: port_log(c);
509: log_puts(": port released\n");
510: }
511: #endif
512: for (rxmask = 0, i = 0; i < MIDI_NEP; i++)
513: rxmask |= midi_ep[i].txmask;
1.8 ! ratchov 514: if ((rxmask & ~c->midi->self) == 0 && c->state == PORT_INIT && !c->hold)
1.5 ratchov 515: port_drain(c);
1.3 ratchov 516: }
517:
1.1 ratchov 518: struct port *
519: port_bynum(int num)
520: {
521: struct port *p;
522:
523: for (p = port_list; p != NULL; p = p->next) {
524: if (num-- == 0)
525: return p;
526: }
527: return NULL;
528: }
529:
530: int
531: port_open(struct port *c)
532: {
533: if (!port_mio_open(c)) {
534: if (log_level >= 1) {
535: log_puts(c->path);
536: log_puts(": failed to open midi port\n");
537: }
538: return 0;
539: }
540: c->state = PORT_INIT;
541: return 1;
542: }
543:
544: int
545: port_close(struct port *c)
546: {
1.3 ratchov 547: int i;
548: struct midi *ep;
1.1 ratchov 549: #ifdef DEBUG
550: if (c->state == PORT_CFG) {
551: port_log(c);
552: log_puts(": can't close port (not opened)\n");
1.3 ratchov 553: panic();
1.1 ratchov 554: }
555: #endif
1.3 ratchov 556: c->state = PORT_CFG;
1.1 ratchov 557: port_mio_close(c);
1.3 ratchov 558:
559: for (i = 0; i < MIDI_NEP; i++) {
560: ep = midi_ep + i;
561: if ((ep->txmask & c->midi->self) ||
562: (c->midi->txmask & ep->self))
563: ep->ops->exit(ep->arg);
564: }
1.1 ratchov 565: return 1;
566: }
567:
1.5 ratchov 568: void
569: port_drain(struct port *c)
570: {
571: struct midi *ep = c->midi;
572:
573: if (!(ep->mode & MODE_MIDIOUT) || ep->obuf.used == 0)
574: port_close(c);
575: else {
576: c->state = PORT_DRAIN;
577: #ifdef DEBUG
578: if (log_level >= 3) {
579: port_log(c);
580: log_puts(": draining\n");
581: }
582: #endif
583: }
584: }
585:
1.1 ratchov 586: int
587: port_init(struct port *c)
588: {
1.4 ratchov 589: if (c->hold)
590: return port_open(c);
591: return 1;
1.1 ratchov 592: }
593:
594: void
595: port_done(struct port *c)
596: {
1.5 ratchov 597: if (c->state == PORT_INIT)
598: port_drain(c);
1.1 ratchov 599: }