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