xref: /openbsd/usr.bin/sndiod/midi.c (revision 7b639200)
1 /*	$OpenBSD: midi.c,v 1.32 2024/12/20 07:35:56 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 
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 size_t
midiev_fmt(char * buf,size_t size,unsigned char * ev,size_t len)60 midiev_fmt(char *buf, size_t size, unsigned char *ev, size_t len)
61 {
62 	const char *sep = "";
63 	char *end = buf + size;
64 	char *p = buf;
65 	int i;
66 
67 	for (i = 0; i < len; i++) {
68 		if (i == 1)
69 			sep = " ";
70 		p += snprintf(p, p < end ? end - p : 0, "%s%02x", sep, ev[i]);
71 	}
72 
73 	return p - buf;
74 }
75 
76 void
midi_init(void)77 midi_init(void)
78 {
79 }
80 
81 void
midi_done(void)82 midi_done(void)
83 {
84 }
85 
86 struct midi *
midi_new(struct midiops * ops,void * arg,int mode)87 midi_new(struct midiops *ops, void *arg, int mode)
88 {
89 	int i;
90 	struct midi *ep;
91 
92 	for (i = 0, ep = midi_ep;; i++, ep++) {
93 		if (i == MIDI_NEP)
94 			return NULL;
95 		if (ep->ops == NULL)
96 			break;
97 	}
98 	ep->ops = ops;
99 	ep->arg = arg;
100 	ep->used = 0;
101 	ep->len = 0;
102 	ep->idx = 0;
103 	ep->st = 0;
104 	ep->last_st = 0;
105 	ep->txmask = 0;
106 	ep->num = i;
107 	ep->self = 1 << i;
108 	ep->tickets = 0;
109 	ep->mode = mode;
110 
111 	/*
112 	 * the output buffer is the client input
113 	 */
114 	if (ep->mode & MODE_MIDIIN)
115 		abuf_init(&ep->obuf, MIDI_BUFSZ);
116 	midi_tickets(ep);
117 	return ep;
118 }
119 
120 void
midi_del(struct midi * ep)121 midi_del(struct midi *ep)
122 {
123 	int i;
124 	struct midi *peer;
125 
126 	ep->txmask = 0;
127 	for (i = 0; i < MIDI_NEP; i++) {
128 		peer = midi_ep + i;
129 		if (peer->txmask & ep->self) {
130 			peer->txmask &= ~ep->self;
131 			midi_tickets(peer);
132 		}
133 	}
134 	for (i = 0; i < MIDITHRU_NMAX; i++) {
135 		midithru[i].txmask &= ~ep->self;
136 		midithru[i].rxmask &= ~ep->self;
137 	}
138 	ep->ops = NULL;
139 	if (ep->mode & MODE_MIDIIN) {
140 		abuf_done(&ep->obuf);
141 	}
142 }
143 
144 /*
145  * connect two midi endpoints
146  */
147 void
midi_link(struct midi * ep,struct midi * peer)148 midi_link(struct midi *ep, struct midi *peer)
149 {
150 	if (ep->mode & MODE_MIDIOUT) {
151 		ep->txmask |= peer->self;
152 		midi_tickets(ep);
153 	}
154 	if (ep->mode & MODE_MIDIIN) {
155 #ifdef DEBUG
156 		if (ep->obuf.used > 0) {
157 			logx(0, "midi%u: linked with non-empty buffer", ep->num);
158 			panic();
159 		}
160 #endif
161 		/* ep has empty buffer, so no need to call midi_tickets() */
162 		peer->txmask |= ep->self;
163 	}
164 }
165 
166 /*
167  * return the list of endpoints the given one receives from
168  */
169 unsigned int
midi_rxmask(struct midi * ep)170 midi_rxmask(struct midi *ep)
171 {
172 	int i, rxmask;
173 
174 	for (rxmask = 0, i = 0; i < MIDI_NEP; i++) {
175 		if ((midi_ep[i].txmask & ep->self) == 0)
176 			continue;
177 		rxmask |= midi_ep[i].self;
178 	}
179 
180 	return rxmask;
181 }
182 
183 /*
184  * add the midi endpoint in the ``tag'' midi thru box
185  */
186 void
midi_tag(struct midi * ep,unsigned int tag)187 midi_tag(struct midi *ep, unsigned int tag)
188 {
189 	struct midi *peer;
190 	struct midithru *t = midithru + tag;
191 	int i;
192 
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 			logx(0, "midi%u: tagged with non-empty buffer", ep->num);
201 			panic();
202 		}
203 #endif
204 		for (i = 0; i < MIDI_NEP; i++) {
205 			if (!(t->rxmask & (1 << i)))
206 				continue;
207 			peer = midi_ep + i;
208 			peer->txmask |= ep->self;
209 		}
210 	}
211 	if (ep->mode & MODE_MIDIOUT)
212 		t->rxmask |= ep->self;
213 	if (ep->mode & MODE_MIDIIN)
214 		t->txmask |= ep->self;
215 }
216 
217 /*
218  * return the list of tags
219  */
220 unsigned int
midi_tags(struct midi * ep)221 midi_tags(struct midi *ep)
222 {
223 	int i;
224 	struct midithru *t;
225 	unsigned int tags;
226 
227 	tags = 0;
228 	for (i = 0; i < MIDITHRU_NMAX; i++) {
229 		t = midithru + i;
230 		if ((t->txmask | t->rxmask) & ep->self)
231 			tags |= 1 << i;
232 	}
233 	return tags;
234 }
235 
236 /*
237  * broadcast the given message to other endpoints
238  */
239 void
midi_send(struct midi * iep,unsigned char * msg,int size)240 midi_send(struct midi *iep, unsigned char *msg, int size)
241 {
242 #ifdef DEBUG
243 	char str[128];
244 #endif
245 	struct midi *oep;
246 	int i;
247 
248 #ifdef DEBUG
249 	logx(4, "midi%u: sending: %s", iep->num,
250 	    (midiev_fmt(str, sizeof(str), msg, size), str));
251 #endif
252 	for (i = 0; i < MIDI_NEP ; i++) {
253 		if ((iep->txmask & (1 << i)) == 0)
254 			continue;
255 		oep = midi_ep + i;
256 		if (msg[0] <= 0x7f) {
257 			if (oep->owner != iep)
258 				continue;
259 		} else if (msg[0] <= 0xf7)
260 			oep->owner = iep;
261 #ifdef DEBUG
262 		logx(4, "midi%u -> midi%u", iep->num, oep->num);
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 #ifdef DEBUG
396 	char str[128];
397 #endif
398 	unsigned char *odata;
399 	int ocount;
400 
401 	while (icount > 0) {
402 		if (oep->obuf.used == oep->obuf.len) {
403 #ifdef DEBUG
404 			logx(2, "midi%u: too slow, discarding %d bytes",
405 			    oep->num, oep->obuf.used);
406 #endif
407 			abuf_rdiscard(&oep->obuf, oep->obuf.used);
408 			oep->owner = NULL;
409 			return;
410 		}
411 		odata = abuf_wgetblk(&oep->obuf, &ocount);
412 		if (ocount > icount)
413 			ocount = icount;
414 		memcpy(odata, idata, ocount);
415 #ifdef DEBUG
416 		logx(4, "midi%u: out: %s", oep->num,
417 		    (midiev_fmt(str, sizeof(str), odata, ocount), str));
418 #endif
419 		abuf_wcommit(&oep->obuf, ocount);
420 		icount -= ocount;
421 		idata += ocount;
422 	}
423 }
424 
425 /*
426  * disconnect clients attached to this end-point
427  */
428 void
midi_abort(struct midi * p)429 midi_abort(struct midi *p)
430 {
431 	int i;
432 	struct midi *ep;
433 
434 	for (i = 0; i < MIDI_NEP; i++) {
435 		ep = midi_ep + i;
436 		if ((ep->txmask & p->self) || (p->txmask & ep->self))
437 			ep->ops->exit(ep->arg);
438 	}
439 }
440 
441 /*
442  * connect to "nep" all endpoints currently connected to "oep"
443  */
444 void
midi_migrate(struct midi * oep,struct midi * nep)445 midi_migrate(struct midi *oep, struct midi *nep)
446 {
447 	struct midithru *t;
448 	struct midi *ep;
449 	int i;
450 
451 	for (i = 0; i < MIDITHRU_NMAX; i++) {
452 		t = midithru + i;
453 		if (t->txmask & oep->self) {
454 			t->txmask &= ~oep->self;
455 			t->txmask |= nep->self;
456 		}
457 		if (t->rxmask & oep->self) {
458 			t->rxmask &= ~oep->self;
459 			t->rxmask |= nep->self;
460 		}
461 	}
462 
463 	for (i = 0; i < MIDI_NEP; i++) {
464 		ep = midi_ep + i;
465 		if (ep->txmask & oep->self) {
466 			ep->txmask &= ~oep->self;
467 			ep->txmask |= nep->self;
468 		}
469 	}
470 
471 	for (i = 0; i < MIDI_NEP; i++) {
472 		ep = midi_ep + i;
473 		if (oep->txmask & ep->self) {
474 			oep->txmask &= ~ep->self;
475 			nep->txmask |= ep->self;
476 		}
477 	}
478 }
479 
480 void
port_imsg(void * arg,unsigned char * msg,int size)481 port_imsg(void *arg, unsigned char *msg, int size)
482 {
483 	struct port *p = arg;
484 
485 	midi_send(p->midi, msg, size);
486 }
487 
488 
489 void
port_omsg(void * arg,unsigned char * msg,int size)490 port_omsg(void *arg, unsigned char *msg, int size)
491 {
492 	struct port *p = arg;
493 
494 	midi_out(p->midi, msg, size);
495 }
496 
497 void
port_fill(void * arg,int count)498 port_fill(void *arg, int count)
499 {
500 	/* no flow control */
501 }
502 
503 void
port_exit(void * arg)504 port_exit(void *arg)
505 {
506 #ifdef DEBUG
507 	struct port *p = arg;
508 
509 	logx(0, "midi%u: port exit", p->midi->num);
510 	panic();
511 #endif
512 }
513 
514 /*
515  * create a new midi port
516  */
517 struct port *
port_new(char * path,unsigned int mode,int hold)518 port_new(char *path, unsigned int mode, int hold)
519 {
520 	struct port *c;
521 
522 	c = xmalloc(sizeof(struct port));
523 	c->path = path;
524 	c->state = PORT_CFG;
525 	c->hold = hold;
526 	c->midi = midi_new(&port_midiops, c, mode);
527 	c->num = midi_portnum++;
528 	c->alt_next = c;
529 	c->next = port_list;
530 	port_list = c;
531 	return c;
532 }
533 
534 /*
535  * destroy the given midi port
536  */
537 void
port_del(struct port * c)538 port_del(struct port *c)
539 {
540 	struct port **p;
541 
542 	if (c->state != PORT_CFG)
543 		port_close(c);
544 	midi_del(c->midi);
545 	for (p = &port_list; *p != c; p = &(*p)->next) {
546 #ifdef DEBUG
547 		if (*p == NULL) {
548 			logx(0, "port to delete not on list");
549 			panic();
550 		}
551 #endif
552 	}
553 	*p = c->next;
554 	xfree(c);
555 }
556 
557 int
port_ref(struct port * c)558 port_ref(struct port *c)
559 {
560 #ifdef DEBUG
561 	logx(3, "midi%u: port requested", c->midi->num);
562 #endif
563 	if (c->state == PORT_CFG && !port_open(c))
564 		return 0;
565 	return 1;
566 }
567 
568 void
port_unref(struct port * c)569 port_unref(struct port *c)
570 {
571 	int i, rxmask;
572 
573 #ifdef DEBUG
574 	logx(3, "midi%u: port released", c->midi->num);
575 #endif
576 	for (rxmask = 0, i = 0; i < MIDI_NEP; i++)
577 		rxmask |= midi_ep[i].txmask;
578 	if ((rxmask & c->midi->self) == 0 && c->midi->txmask == 0 &&
579 	    c->state == PORT_INIT && !c->hold)
580 		port_drain(c);
581 }
582 
583 struct port *
port_alt_ref(int num)584 port_alt_ref(int num)
585 {
586 	struct port *a, *p;
587 
588 	a = port_bynum(num);
589 	if (a == NULL)
590 		return NULL;
591 
592 	/* circulate to first alt port */
593 	while (a->alt_next->num > a->num)
594 		a = a->alt_next;
595 
596 	p = a;
597 	while (1) {
598 		if (port_ref(p))
599 			break;
600 		p = p->alt_next;
601 		if (p == a)
602 			return NULL;
603 	}
604 
605 	return p;
606 }
607 
608 struct port *
port_migrate(struct port * op)609 port_migrate(struct port *op)
610 {
611 	struct port *np;
612 
613 	/* not opened */
614 	if (op->state == PORT_CFG)
615 		return op;
616 
617 	np = op;
618 	while (1) {
619 		/* try next one, circulating through the list */
620 		np = np->alt_next;
621 		if (np == op) {
622 			logx(2, "midi%u: no fall-back port found", op->midi->num);
623 			return op;
624 		}
625 
626 		if (port_ref(np))
627 			break;
628 	}
629 
630 	logx(2, "midi%u: switching to midi%u", op->midi->num, np->midi->num);
631 
632 	midi_migrate(op->midi, np->midi);
633 	return np;
634 }
635 
636 struct port *
port_bynum(int num)637 port_bynum(int num)
638 {
639 	struct port *p;
640 
641 	for (p = port_list; p != NULL; p = p->next) {
642 		if (p->num == num)
643 			return p;
644 	}
645 	return NULL;
646 }
647 
648 int
port_open(struct port * c)649 port_open(struct port *c)
650 {
651 	if (!port_mio_open(c)) {
652 		logx(1, "midi%u: failed to open midi port", c->midi->num);
653 		return 0;
654 	}
655 	c->state = PORT_INIT;
656 	return 1;
657 }
658 
659 int
port_close(struct port * c)660 port_close(struct port *c)
661 {
662 #ifdef DEBUG
663 	if (c->state == PORT_CFG) {
664 		logx(0, "midi%u: can't close port (not opened)", c->midi->num);
665 		panic();
666 	}
667 #endif
668 	logx(2, "midi%u: closed", c->midi->num);
669 	c->state = PORT_CFG;
670 	port_mio_close(c);
671 	return 1;
672 }
673 
674 void
port_drain(struct port * c)675 port_drain(struct port *c)
676 {
677 	struct midi *ep = c->midi;
678 
679 	if (!(ep->mode & MODE_MIDIOUT) || ep->obuf.used == 0)
680 		port_close(c);
681 	else {
682 		c->state = PORT_DRAIN;
683 #ifdef DEBUG
684 		logx(3, "midi%u: draining", c->midi->num);
685 #endif
686 	}
687 }
688 
689 int
port_init(struct port * c)690 port_init(struct port *c)
691 {
692 	if (c->hold)
693 		return port_open(c);
694 	return 1;
695 }
696 
697 void
port_done(struct port * c)698 port_done(struct port *c)
699 {
700 	if (c->state == PORT_INIT)
701 		port_drain(c);
702 }
703