xref: /openbsd-src/usr.bin/sndiod/midi.c (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1 /*	$OpenBSD: midi.c,v 1.29 2021/11/01 14:43:25 ratchov Exp $	*/
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 int  port_open(struct port *);
31 void port_imsg(void *, unsigned char *, int);
32 void port_omsg(void *, unsigned char *, int);
33 void port_fill(void *, int);
34 void port_exit(void *);
35 void port_exitall(struct port *);
36 
37 struct midiops port_midiops = {
38 	port_imsg,
39 	port_omsg,
40 	port_fill,
41 	port_exit
42 };
43 
44 #define MIDI_NEP 32
45 struct midi midi_ep[MIDI_NEP];
46 struct port *port_list = NULL;
47 unsigned int midi_portnum = 0;
48 
49 struct midithru {
50 	unsigned int txmask, rxmask;
51 #define MIDITHRU_NMAX 32
52 } midithru[MIDITHRU_NMAX];
53 
54 /*
55  * length of voice and common messages (status byte included)
56  */
57 const unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
58 const unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
59 
60 void
61 midi_log(struct midi *ep)
62 {
63 	log_puts("midi");
64 	log_putu(ep - midi_ep);
65 }
66 
67 void
68 midi_init(void)
69 {
70 }
71 
72 void
73 midi_done(void)
74 {
75 }
76 
77 struct midi *
78 midi_new(struct midiops *ops, void *arg, int mode)
79 {
80 	int i;
81 	struct midi *ep;
82 
83 	for (i = 0, ep = midi_ep;; i++, ep++) {
84 		if (i == MIDI_NEP)
85 			return NULL;
86 		if (ep->ops == NULL)
87 			break;
88 	}
89 	ep->ops = ops;
90 	ep->arg = arg;
91 	ep->used = 0;
92 	ep->len = 0;
93 	ep->idx = 0;
94 	ep->st = 0;
95 	ep->last_st = 0;
96 	ep->txmask = 0;
97 	ep->self = 1 << i;
98 	ep->tickets = 0;
99 	ep->mode = mode;
100 
101 	/*
102 	 * the output buffer is the client input
103 	 */
104 	if (ep->mode & MODE_MIDIIN)
105 		abuf_init(&ep->obuf, MIDI_BUFSZ);
106 	midi_tickets(ep);
107 	return ep;
108 }
109 
110 void
111 midi_del(struct midi *ep)
112 {
113 	int i;
114 	struct midi *peer;
115 
116 	ep->txmask = 0;
117 	for (i = 0; i < MIDI_NEP; i++) {
118 		peer = midi_ep + i;
119 		if (peer->txmask & ep->self) {
120 			peer->txmask &= ~ep->self;
121 			midi_tickets(peer);
122 		}
123 	}
124 	for (i = 0; i < MIDITHRU_NMAX; i++) {
125 		midithru[i].txmask &= ~ep->self;
126 		midithru[i].rxmask &= ~ep->self;
127 	}
128 	ep->ops = NULL;
129 	if (ep->mode & MODE_MIDIIN) {
130 		abuf_done(&ep->obuf);
131 	}
132 }
133 
134 /*
135  * connect two midi endpoints
136  */
137 void
138 midi_link(struct midi *ep, struct midi *peer)
139 {
140 	if (ep->mode & MODE_MIDIOUT) {
141 		ep->txmask |= peer->self;
142 		midi_tickets(ep);
143 	}
144 	if (ep->mode & MODE_MIDIIN) {
145 #ifdef DEBUG
146 		if (ep->obuf.used > 0) {
147 			midi_log(ep);
148 			log_puts(": linked with non-empty buffer\n");
149 			panic();
150 		}
151 #endif
152 		/* ep has empty buffer, so no need to call midi_tickets() */
153 		peer->txmask |= ep->self;
154 	}
155 }
156 
157 /*
158  * add the midi endpoint in the ``tag'' midi thru box
159  */
160 void
161 midi_tag(struct midi *ep, unsigned int tag)
162 {
163 	struct midi *peer;
164 	struct midithru *t = midithru + tag;
165 	int i;
166 
167 	if (ep->mode & MODE_MIDIOUT) {
168 		ep->txmask |= t->txmask;
169 		midi_tickets(ep);
170 	}
171 	if (ep->mode & MODE_MIDIIN) {
172 #ifdef DEBUG
173 		if (ep->obuf.used > 0) {
174 			midi_log(ep);
175 			log_puts(": tagged with non-empty buffer\n");
176 			panic();
177 		}
178 #endif
179 		for (i = 0; i < MIDI_NEP; i++) {
180 			if (!(t->rxmask & (1 << i)))
181 				continue;
182 			peer = midi_ep + i;
183 			peer->txmask |= ep->self;
184 		}
185 	}
186 	if (ep->mode & MODE_MIDIOUT)
187 		t->rxmask |= ep->self;
188 	if (ep->mode & MODE_MIDIIN)
189 		t->txmask |= ep->self;
190 }
191 
192 /*
193  * return the list of tags
194  */
195 unsigned int
196 midi_tags(struct midi *ep)
197 {
198 	int i;
199 	struct midithru *t;
200 	unsigned int tags;
201 
202 	tags = 0;
203 	for (i = 0; i < MIDITHRU_NMAX; i++) {
204 		t = midithru + i;
205 		if ((t->txmask | t->rxmask) & ep->self)
206 			tags |= 1 << i;
207 	}
208 	return tags;
209 }
210 
211 /*
212  * broadcast the given message to other endpoints
213  */
214 void
215 midi_send(struct midi *iep, unsigned char *msg, int size)
216 {
217 	struct midi *oep;
218 	int i;
219 
220 #ifdef DEBUG
221 	if (log_level >= 4) {
222 		midi_log(iep);
223 		log_puts(": sending:");
224 		for (i = 0; i < size; i++) {
225 			log_puts(" ");
226 			log_putx(msg[i]);
227 		}
228 		log_puts("\n");
229 	}
230 #endif
231 	for (i = 0; i < MIDI_NEP ; i++) {
232 		if ((iep->txmask & (1 << i)) == 0)
233 			continue;
234 		oep = midi_ep + i;
235 		if (msg[0] <= 0x7f) {
236 			if (oep->owner != iep)
237 				continue;
238 		} else if (msg[0] <= 0xf7)
239 			oep->owner = iep;
240 #ifdef DEBUG
241 		if (log_level >= 4) {
242 			midi_log(iep);
243 			log_puts(" -> ");
244 			midi_log(oep);
245 			log_puts("\n");
246 		}
247 #endif
248 		oep->ops->omsg(oep->arg, msg, size);
249 	}
250 }
251 
252 /*
253  * determine if we have gained more input tickets, and if so call the
254  * fill() call-back to notify the i/o layer that it can send more data
255  */
256 void
257 midi_tickets(struct midi *iep)
258 {
259 	int i, tickets, avail, maxavail;
260 	struct midi *oep;
261 
262 	/*
263 	 * don't request iep->ops->fill() too often as it generates
264 	 * useless network traffic: wait until we reach half of the
265 	 * max tickets count. As in the worst case (see comment below)
266 	 * one ticket may consume two bytes, the max ticket count is
267 	 * BUFSZ / 2 and halt of it is simply BUFSZ / 4.
268 	 */
269 	if (iep->tickets >= MIDI_BUFSZ / 4)
270 		return;
271 
272 	maxavail = MIDI_BUFSZ;
273 	for (i = 0; i < MIDI_NEP ; i++) {
274 		if ((iep->txmask & (1 << i)) == 0)
275 			continue;
276 		oep = midi_ep + i;
277 		avail = oep->obuf.len - oep->obuf.used;
278 		if (maxavail > avail)
279 			maxavail = avail;
280 	}
281 
282 	/*
283 	 * in the worst case output message is twice the
284 	 * input message (2-byte messages with running status)
285 	 */
286 	tickets = maxavail / 2 - iep->tickets;
287 	if (tickets > 0) {
288 		iep->tickets += tickets;
289 		iep->ops->fill(iep->arg, tickets);
290 	}
291 }
292 
293 /*
294  * recalculate tickets of endpoints sending data to this one
295  */
296 void
297 midi_fill(struct midi *oep)
298 {
299 	int i;
300 	struct midi *iep;
301 
302 	for (i = 0; i < MIDI_NEP; i++) {
303 		iep = midi_ep + i;
304 		if (iep->txmask & oep->self)
305 			midi_tickets(iep);
306 	}
307 }
308 
309 /*
310  * parse then give data chunk, and calling imsg() for each message
311  */
312 void
313 midi_in(struct midi *iep, unsigned char *idata, int icount)
314 {
315 	int i;
316 	unsigned char c;
317 
318 	for (i = 0; i < icount; i++) {
319 		c = *idata++;
320 		if (c >= 0xf8) {
321 			if (c != MIDI_ACK)
322 				iep->ops->imsg(iep->arg, &c, 1);
323 		} else if (c == SYSEX_END) {
324 			if (iep->st == SYSEX_START) {
325 				iep->msg[iep->idx++] = c;
326 				iep->ops->imsg(iep->arg, iep->msg, iep->idx);
327 			}
328 
329 			/*
330 			 * There are bogus MIDI sources that keep
331 			 * state across sysex; Linux virmidi ports fed
332 			 * by the sequencer is an example. We
333 			 * workaround this by saving the current
334 			 * status and restoring it at the end of the
335 			 * sysex.
336 			 */
337 			iep->st = iep->last_st;
338 			if (iep->st)
339 				iep->len = voice_len[(iep->st >> 4) & 7];
340 			iep->idx = 0;
341 		} else if (c >= 0xf0) {
342 			iep->msg[0] = c;
343 			iep->len = common_len[c & 7];
344 			iep->st = c;
345 			iep->idx = 1;
346 		} else if (c >= 0x80) {
347 			iep->msg[0] = c;
348 			iep->len = voice_len[(c >> 4) & 7];
349 			iep->last_st = iep->st = c;
350 			iep->idx = 1;
351 		} else if (iep->st) {
352 			if (iep->idx == 0 && iep->st != SYSEX_START)
353 				iep->msg[iep->idx++] = iep->st;
354 			iep->msg[iep->idx++] = c;
355 			if (iep->idx == iep->len) {
356 				iep->ops->imsg(iep->arg, iep->msg, iep->idx);
357 				if (iep->st >= 0xf0)
358 					iep->st = 0;
359 				iep->idx = 0;
360 			} else if (iep->idx == MIDI_MSGMAX) {
361 				/* sysex continued */
362 				iep->ops->imsg(iep->arg, iep->msg, iep->idx);
363 				iep->idx = 0;
364 			}
365 		}
366 	}
367 	iep->tickets -= icount;
368 	if (iep->tickets < 0)
369 		iep->tickets = 0;
370 	midi_tickets(iep);
371 }
372 
373 /*
374  * store the given message in the output buffer
375  */
376 void
377 midi_out(struct midi *oep, unsigned char *idata, int icount)
378 {
379 	unsigned char *odata;
380 	int ocount;
381 #ifdef DEBUG
382 	int i;
383 #endif
384 
385 	while (icount > 0) {
386 		if (oep->obuf.used == oep->obuf.len) {
387 #ifdef DEBUG
388 			if (log_level >= 2) {
389 				midi_log(oep);
390 				log_puts(": too slow, discarding ");
391 				log_putu(oep->obuf.used);
392 				log_puts(" bytes\n");
393 			}
394 #endif
395 			abuf_rdiscard(&oep->obuf, oep->obuf.used);
396 			oep->owner = NULL;
397 			return;
398 		}
399 		odata = abuf_wgetblk(&oep->obuf, &ocount);
400 		if (ocount > icount)
401 			ocount = icount;
402 		memcpy(odata, idata, ocount);
403 #ifdef DEBUG
404 		if (log_level >= 4) {
405 			midi_log(oep);
406 			log_puts(": out: ");
407 			for (i = 0; i < ocount; i++) {
408 				log_puts(" ");
409 				log_putx(odata[i]);
410 			}
411 			log_puts("\n");
412 		}
413 #endif
414 		abuf_wcommit(&oep->obuf, ocount);
415 		icount -= ocount;
416 		idata += ocount;
417 	}
418 }
419 
420 /*
421  * disconnect clients attached to this end-point
422  */
423 void
424 midi_abort(struct midi *p)
425 {
426 	int i;
427 	struct midi *ep;
428 
429 	for (i = 0; i < MIDI_NEP; i++) {
430 		ep = midi_ep + i;
431 		if ((ep->txmask & p->self) || (p->txmask & ep->self))
432 			ep->ops->exit(ep->arg);
433 	}
434 }
435 
436 /*
437  * connect to "nep" all endpoints currently connected to "oep"
438  */
439 void
440 midi_migrate(struct midi *oep, struct midi *nep)
441 {
442 	struct midithru *t;
443 	struct midi *ep;
444 	int i;
445 
446 	for (i = 0; i < MIDITHRU_NMAX; i++) {
447 		t = midithru + i;
448 		if (t->txmask & oep->self) {
449 			t->txmask &= ~oep->self;
450 			t->txmask |= nep->self;
451 		}
452 		if (t->rxmask & oep->self) {
453 			t->rxmask &= ~oep->self;
454 			t->rxmask |= nep->self;
455 		}
456 	}
457 
458 	for (i = 0; i < MIDI_NEP; i++) {
459 		ep = midi_ep + i;
460 		if (ep->txmask & oep->self) {
461 			ep->txmask &= ~oep->self;
462 			ep->txmask |= nep->self;
463 		}
464 	}
465 
466 	for (i = 0; i < MIDI_NEP; i++) {
467 		ep = midi_ep + i;
468 		if (oep->txmask & ep->self) {
469 			oep->txmask &= ~ep->self;
470 			nep->txmask |= ep->self;
471 		}
472 	}
473 }
474 
475 void
476 port_log(struct port *p)
477 {
478 	midi_log(p->midi);
479 }
480 
481 void
482 port_imsg(void *arg, unsigned char *msg, int size)
483 {
484 	struct port *p = arg;
485 
486 	midi_send(p->midi, msg, size);
487 }
488 
489 
490 void
491 port_omsg(void *arg, unsigned char *msg, int size)
492 {
493 	struct port *p = arg;
494 
495 	midi_out(p->midi, msg, size);
496 }
497 
498 void
499 port_fill(void *arg, int count)
500 {
501 	/* no flow control */
502 }
503 
504 void
505 port_exit(void *arg)
506 {
507 #ifdef DEBUG
508 	struct port *p = arg;
509 
510 	if (log_level >= 3) {
511 		port_log(p);
512 		log_puts(": port exit\n");
513 		panic();
514 	}
515 #endif
516 }
517 
518 /*
519  * create a new midi port
520  */
521 struct port *
522 port_new(char *path, unsigned int mode, int hold)
523 {
524 	struct port *c;
525 
526 	c = xmalloc(sizeof(struct port));
527 	c->path = path;
528 	c->state = PORT_CFG;
529 	c->hold = hold;
530 	c->midi = midi_new(&port_midiops, c, mode);
531 	c->num = midi_portnum++;
532 	c->alt_next = c;
533 	c->next = port_list;
534 	port_list = c;
535 	return c;
536 }
537 
538 /*
539  * destroy the given midi port
540  */
541 void
542 port_del(struct port *c)
543 {
544 	struct port **p;
545 
546 	if (c->state != PORT_CFG)
547 		port_close(c);
548 	midi_del(c->midi);
549 	for (p = &port_list; *p != c; p = &(*p)->next) {
550 #ifdef DEBUG
551 		if (*p == NULL) {
552 			log_puts("port to delete not on list\n");
553 			panic();
554 		}
555 #endif
556 	}
557 	*p = c->next;
558 	xfree(c);
559 }
560 
561 int
562 port_ref(struct port *c)
563 {
564 #ifdef DEBUG
565 	if (log_level >= 3) {
566 		port_log(c);
567 		log_puts(": port requested\n");
568 	}
569 #endif
570 	if (c->state == PORT_CFG && !port_open(c))
571 		return 0;
572 	return 1;
573 }
574 
575 void
576 port_unref(struct port *c)
577 {
578 	int i, rxmask;
579 
580 #ifdef DEBUG
581 	if (log_level >= 3) {
582 		port_log(c);
583 		log_puts(": port released\n");
584 	}
585 #endif
586 	for (rxmask = 0, i = 0; i < MIDI_NEP; i++)
587 		rxmask |= midi_ep[i].txmask;
588 	if ((rxmask & c->midi->self) == 0 && c->midi->txmask == 0 &&
589 	    c->state == PORT_INIT && !c->hold)
590 		port_drain(c);
591 }
592 
593 struct port *
594 port_alt_ref(int num)
595 {
596 	struct port *a, *p;
597 
598 	a = port_bynum(num);
599 	if (a == NULL)
600 		return NULL;
601 
602 	/* circulate to first alt port */
603 	while (a->alt_next->num > a->num)
604 		a = a->alt_next;
605 
606 	p = a;
607 	while (1) {
608 		if (port_ref(p))
609 			break;
610 		p = p->alt_next;
611 		if (p == a)
612 			return NULL;
613 	}
614 
615 	return p;
616 }
617 
618 struct port *
619 port_migrate(struct port *op)
620 {
621 	struct port *np;
622 
623 	/* not opened */
624 	if (op->state == PORT_CFG)
625 		return op;
626 
627 	np = op;
628 	while (1) {
629 		/* try next one, circulating through the list */
630 		np = np->alt_next;
631 		if (np == op) {
632 			if (log_level >= 2) {
633 				port_log(op);
634 				log_puts(": no fall-back port found\n");
635 			}
636 			return op;
637 		}
638 
639 		if (port_ref(np))
640 			break;
641 	}
642 
643 	if (log_level >= 2) {
644 		port_log(op);
645 		log_puts(": switching to ");
646 		port_log(np);
647 		log_puts("\n");
648 	}
649 
650 	midi_migrate(op->midi, np->midi);
651 	return np;
652 }
653 
654 struct port *
655 port_bynum(int num)
656 {
657 	struct port *p;
658 
659 	for (p = port_list; p != NULL; p = p->next) {
660 		if (p->num == num)
661 			return p;
662 	}
663 	return NULL;
664 }
665 
666 int
667 port_open(struct port *c)
668 {
669 	if (!port_mio_open(c)) {
670 		if (log_level >= 1) {
671 			port_log(c);
672 			log_puts(": failed to open midi port\n");
673 		}
674 		return 0;
675 	}
676 	c->state = PORT_INIT;
677 	return 1;
678 }
679 
680 int
681 port_close(struct port *c)
682 {
683 #ifdef DEBUG
684 	if (c->state == PORT_CFG) {
685 		port_log(c);
686 		log_puts(": can't close port (not opened)\n");
687 		panic();
688 	}
689 #endif
690 	port_log(c);
691 	log_puts(": closed\n");
692 	c->state = PORT_CFG;
693 	port_mio_close(c);
694 	return 1;
695 }
696 
697 void
698 port_drain(struct port *c)
699 {
700 	struct midi *ep = c->midi;
701 
702 	if (!(ep->mode & MODE_MIDIOUT) || ep->obuf.used == 0)
703 		port_close(c);
704 	else {
705 		c->state = PORT_DRAIN;
706 #ifdef DEBUG
707 		if (log_level >= 3) {
708 			port_log(c);
709 			log_puts(": draining\n");
710 		}
711 #endif
712 	}
713 }
714 
715 int
716 port_init(struct port *c)
717 {
718 	if (c->hold)
719 		return port_open(c);
720 	return 1;
721 }
722 
723 void
724 port_done(struct port *c)
725 {
726 	if (c->state == PORT_INIT)
727 		port_drain(c);
728 }
729