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