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