xref: /openbsd-src/usr.bin/sndiod/midi.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: midi.c,v 1.23 2020/01/23 05:27:17 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 unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
58 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  * broadcast the given message to other endpoints
194  */
195 void
196 midi_send(struct midi *iep, unsigned char *msg, int size)
197 {
198 	struct midi *oep;
199 	int i;
200 
201 #ifdef DEBUG
202 	if (log_level >= 4) {
203 		midi_log(iep);
204 		log_puts(": sending:");
205 		for (i = 0; i < size; i++) {
206 			log_puts(" ");
207 			log_putx(msg[i]);
208 		}
209 		log_puts("\n");
210 	}
211 #endif
212 	for (i = 0; i < MIDI_NEP ; i++) {
213 		if ((iep->txmask & (1 << i)) == 0)
214 			continue;
215 		oep = midi_ep + i;
216 		if (msg[0] <= 0x7f) {
217 			if (oep->owner != iep)
218 				continue;
219 		} else if (msg[0] <= 0xf7)
220 			oep->owner = iep;
221 #ifdef DEBUG
222 		if (log_level >= 4) {
223 			midi_log(iep);
224 			log_puts(" -> ");
225 			midi_log(oep);
226 			log_puts("\n");
227 		}
228 #endif
229 		oep->ops->omsg(oep->arg, msg, size);
230 	}
231 }
232 
233 /*
234  * determine if we have gained more input tickets, and if so call the
235  * fill() call-back to notify the i/o layer that it can send more data
236  */
237 void
238 midi_tickets(struct midi *iep)
239 {
240 	int i, tickets, avail, maxavail;
241 	struct midi *oep;
242 
243 	/*
244 	 * don't request iep->ops->fill() too often as it generates
245 	 * useless network traffic: wait until we reach half of the
246 	 * max tickets count. As in the worst case (see comment below)
247 	 * one ticket may consume two bytes, the max ticket count is
248 	 * BUFSZ / 2 and halt of it is simply BUFSZ / 4.
249 	 */
250 	if (iep->tickets >= MIDI_BUFSZ / 4)
251 		return;
252 
253 	maxavail = MIDI_BUFSZ;
254 	for (i = 0; i < MIDI_NEP ; i++) {
255 		if ((iep->txmask & (1 << i)) == 0)
256 			continue;
257 		oep = midi_ep + i;
258 		avail = oep->obuf.len - oep->obuf.used;
259 		if (maxavail > avail)
260 			maxavail = avail;
261 	}
262 
263 	/*
264 	 * in the worst case output message is twice the
265 	 * input message (2-byte messages with running status)
266 	 */
267 	tickets = maxavail / 2 - iep->tickets;
268 	if (tickets > 0) {
269 		iep->tickets += tickets;
270 		iep->ops->fill(iep->arg, tickets);
271 	}
272 }
273 
274 /*
275  * recalculate tickets of endpoints sending data to this one
276  */
277 void
278 midi_fill(struct midi *oep)
279 {
280 	int i;
281 	struct midi *iep;
282 
283 	for (i = 0; i < MIDI_NEP; i++) {
284 		iep = midi_ep + i;
285 		if (iep->txmask & oep->self)
286 			midi_tickets(iep);
287 	}
288 }
289 
290 /*
291  * parse then give data chunk, and calling imsg() for each message
292  */
293 void
294 midi_in(struct midi *iep, unsigned char *idata, int icount)
295 {
296 	int i;
297 	unsigned char c;
298 
299 	for (i = 0; i < icount; i++) {
300 		c = *idata++;
301 		if (c >= 0xf8) {
302 			if (c != MIDI_ACK)
303 				iep->ops->imsg(iep->arg, &c, 1);
304 		} else if (c == SYSEX_END) {
305 			if (iep->st == SYSEX_START) {
306 				iep->msg[iep->idx++] = c;
307 				iep->ops->imsg(iep->arg, iep->msg, iep->idx);
308 			}
309 
310 			/*
311 			 * There are bogus MIDI sources that keep
312 			 * state across sysex; Linux virmidi ports fed
313 			 * by the sequencer is an example. We
314 			 * workaround this by saving the current
315 			 * status and restoring it at the end of the
316 			 * sysex.
317 			 */
318 			iep->st = iep->last_st;
319 			if (iep->st)
320 				iep->len = voice_len[(iep->st >> 4) & 7];
321 			iep->idx = 0;
322 		} else if (c >= 0xf0) {
323 			iep->msg[0] = c;
324 			iep->len = common_len[c & 7];
325 			iep->st = c;
326 			iep->idx = 1;
327 		} else if (c >= 0x80) {
328 			iep->msg[0] = c;
329 			iep->len = voice_len[(c >> 4) & 7];
330 			iep->last_st = iep->st = c;
331 			iep->idx = 1;
332 		} else if (iep->st) {
333 			if (iep->idx == 0 && iep->st != SYSEX_START)
334 				iep->msg[iep->idx++] = iep->st;
335 			iep->msg[iep->idx++] = c;
336 			if (iep->idx == iep->len) {
337 				iep->ops->imsg(iep->arg, iep->msg, iep->idx);
338 				if (iep->st >= 0xf0)
339 					iep->st = 0;
340 				iep->idx = 0;
341 			} else if (iep->idx == MIDI_MSGMAX) {
342 				/* sysex continued */
343 				iep->ops->imsg(iep->arg, iep->msg, iep->idx);
344 				iep->idx = 0;
345 			}
346 		}
347 	}
348 	iep->tickets -= icount;
349 	if (iep->tickets < 0)
350 		iep->tickets = 0;
351 	midi_tickets(iep);
352 }
353 
354 /*
355  * store the given message in the output buffer
356  */
357 void
358 midi_out(struct midi *oep, unsigned char *idata, int icount)
359 {
360 	unsigned char *odata;
361 	int ocount;
362 #ifdef DEBUG
363 	int i;
364 #endif
365 
366 	while (icount > 0) {
367 		if (oep->obuf.used == oep->obuf.len) {
368 #ifdef DEBUG
369 			if (log_level >= 2) {
370 				midi_log(oep);
371 				log_puts(": too slow, discarding ");
372 				log_putu(oep->obuf.used);
373 				log_puts(" bytes\n");
374 			}
375 #endif
376 			abuf_rdiscard(&oep->obuf, oep->obuf.used);
377 			oep->owner = NULL;
378 			return;
379 		}
380 		odata = abuf_wgetblk(&oep->obuf, &ocount);
381 		if (ocount > icount)
382 			ocount = icount;
383 		memcpy(odata, idata, ocount);
384 #ifdef DEBUG
385 		if (log_level >= 4) {
386 			midi_log(oep);
387 			log_puts(": out: ");
388 			for (i = 0; i < ocount; i++) {
389 				log_puts(" ");
390 				log_putx(odata[i]);
391 			}
392 			log_puts("\n");
393 		}
394 #endif
395 		abuf_wcommit(&oep->obuf, ocount);
396 		icount -= ocount;
397 		idata += ocount;
398 	}
399 }
400 
401 void
402 port_log(struct port *p)
403 {
404 	midi_log(p->midi);
405 }
406 
407 void
408 port_imsg(void *arg, unsigned char *msg, int size)
409 {
410 	struct port *p = arg;
411 
412 	midi_send(p->midi, msg, size);
413 }
414 
415 
416 void
417 port_omsg(void *arg, unsigned char *msg, int size)
418 {
419 	struct port *p = arg;
420 
421 	midi_out(p->midi, msg, size);
422 }
423 
424 void
425 port_fill(void *arg, int count)
426 {
427 	/* no flow control */
428 }
429 
430 void
431 port_exit(void *arg)
432 {
433 #ifdef DEBUG
434 	struct port *p = arg;
435 
436 	if (log_level >= 3) {
437 		port_log(p);
438 		log_puts(": port exit\n");
439 		panic();
440 	}
441 #endif
442 }
443 
444 /*
445  * create a new midi port
446  */
447 struct port *
448 port_new(char *path, unsigned int mode, int hold)
449 {
450 	struct port *c;
451 
452 	c = xmalloc(sizeof(struct port));
453 	c->path_list = NULL;
454 	namelist_add(&c->path_list, path);
455 	c->state = PORT_CFG;
456 	c->hold = hold;
457 	c->midi = midi_new(&port_midiops, c, mode);
458 	c->num = 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 	namelist_clear(&c->path_list);
485 	xfree(c);
486 }
487 
488 int
489 port_ref(struct port *c)
490 {
491 #ifdef DEBUG
492 	if (log_level >= 3) {
493 		port_log(c);
494 		log_puts(": port requested\n");
495 	}
496 #endif
497 	if (c->state == PORT_CFG && !port_open(c))
498 		return 0;
499 	return 1;
500 }
501 
502 void
503 port_unref(struct port *c)
504 {
505 	int i, rxmask;
506 
507 #ifdef DEBUG
508 	if (log_level >= 3) {
509 		port_log(c);
510 		log_puts(": port released\n");
511 	}
512 #endif
513 	for (rxmask = 0, i = 0; i < MIDI_NEP; i++)
514 		rxmask |= midi_ep[i].txmask;
515 	if ((rxmask & c->midi->self) == 0 && c->midi->txmask == 0 &&
516 	    c->state == PORT_INIT && !c->hold)
517 		port_drain(c);
518 }
519 
520 struct port *
521 port_bynum(int num)
522 {
523 	struct port *p;
524 
525 	for (p = port_list; p != NULL; p = p->next) {
526 		if (p->num == num)
527 			return p;
528 	}
529 	return NULL;
530 }
531 
532 int
533 port_open(struct port *c)
534 {
535 	if (!port_mio_open(c)) {
536 		if (log_level >= 1) {
537 			port_log(c);
538 			log_puts(": failed to open midi port\n");
539 		}
540 		return 0;
541 	}
542 	c->state = PORT_INIT;
543 	return 1;
544 }
545 
546 void
547 port_exitall(struct port *c)
548 {
549 	int i;
550 	struct midi *ep;
551 
552 	for (i = 0; i < MIDI_NEP; i++) {
553 		ep = midi_ep + i;
554 		if ((ep->txmask & c->midi->self) ||
555 		    (c->midi->txmask & ep->self))
556 			ep->ops->exit(ep->arg);
557 	}
558 }
559 
560 int
561 port_close(struct port *c)
562 {
563 #ifdef DEBUG
564 	if (c->state == PORT_CFG) {
565 		port_log(c);
566 		log_puts(": can't close port (not opened)\n");
567 		panic();
568 	}
569 #endif
570 	c->state = PORT_CFG;
571 	port_mio_close(c);
572 
573 	port_exitall(c);
574 	return 1;
575 }
576 
577 void
578 port_drain(struct port *c)
579 {
580 	struct midi *ep = c->midi;
581 
582 	if (!(ep->mode & MODE_MIDIOUT) || ep->obuf.used == 0)
583 		port_close(c);
584 	else {
585 		c->state = PORT_DRAIN;
586 #ifdef DEBUG
587 		if (log_level >= 3) {
588 			port_log(c);
589 			log_puts(": draining\n");
590 		}
591 #endif
592 	}
593 }
594 
595 int
596 port_init(struct port *c)
597 {
598 	if (c->hold)
599 		return port_open(c);
600 	return 1;
601 }
602 
603 void
604 port_done(struct port *c)
605 {
606 	if (c->state == PORT_INIT)
607 		port_drain(c);
608 }
609 
610 int
611 port_reopen(struct port *p)
612 {
613 	if (p->state == PORT_CFG)
614 		return 1;
615 
616 	if (!port_mio_reopen(p))
617 		return 0;
618 
619 	return 1;
620 }
621