xref: /openbsd-src/usr.bin/sndiod/midi.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: midi.c,v 1.15 2016/01/08 16:17:31 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 unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
57 unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
58 
59 void
60 midi_log(struct midi *ep)
61 {
62 	log_puts("midi");
63 	log_putu(ep - midi_ep);
64 }
65 
66 void
67 midi_init(void)
68 {
69 }
70 
71 void
72 midi_done(void)
73 {
74 }
75 
76 struct midi *
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->txmask = 0;
95 	ep->self = 1 << i;
96 	ep->tickets = 0;
97 	ep->mode = mode;
98 
99 	/*
100 	 * the output buffer is the client intput
101 	 */
102 	if (ep->mode & MODE_MIDIIN)
103 		abuf_init(&ep->obuf, MIDI_BUFSZ);
104 	midi_tickets(ep);
105 	return ep;
106 }
107 
108 void
109 midi_del(struct midi *ep)
110 {
111 	int i;
112 	struct midi *peer;
113 
114 	ep->txmask = 0;
115 	for (i = 0; i < MIDI_NEP; i++) {
116 		peer = midi_ep + i;
117 		if (peer->txmask & ep->self) {
118 			peer->txmask &= ~ep->self;
119 			midi_tickets(peer);
120 		}
121 	}
122 	for (i = 0; i < MIDITHRU_NMAX; i++) {
123 		midithru[i].txmask &= ~ep->self;
124 		midithru[i].rxmask &= ~ep->self;
125 	}
126 	ep->ops = NULL;
127 	if (ep->mode & MODE_MIDIIN) {
128 		abuf_done(&ep->obuf);
129 	}
130 }
131 
132 /*
133  * connect two midi endpoints
134  */
135 void
136 midi_link(struct midi *ep, struct midi *peer)
137 {
138 	if (ep->mode & MODE_MIDIOUT) {
139 		ep->txmask |= peer->self;
140 		midi_tickets(ep);
141 	}
142 	if (ep->mode & MODE_MIDIIN) {
143 #ifdef DEBUG
144 		if (ep->obuf.used > 0) {
145 			midi_log(ep);
146 			log_puts(": linked with non-empty buffer\n");
147 			panic();
148 		}
149 #endif
150 		/* ep has empry buffer, so no need to call midi_tickets() */
151 		peer->txmask |= ep->self;
152 	}
153 }
154 
155 /*
156  * add the midi endpoint in the ``tag'' midi thru box
157  */
158 void
159 midi_tag(struct midi *ep, unsigned int tag)
160 {
161 	struct midi *peer;
162 	struct midithru *t = midithru + tag;
163 	int i;
164 
165 	if (ep->mode & MODE_MIDIOUT) {
166 		ep->txmask |= t->txmask;
167 		midi_tickets(ep);
168 	}
169 	if (ep->mode & MODE_MIDIIN) {
170 #ifdef DEBUG
171 		if (ep->obuf.used > 0) {
172 			midi_log(ep);
173 			log_puts(": tagged with non-empty buffer\n");
174 			panic();
175 		}
176 #endif
177 		for (i = 0; i < MIDI_NEP; i++) {
178 			if (!(t->rxmask & (1 << i)))
179 				continue;
180 			peer = midi_ep + i;
181 			peer->txmask |= ep->self;
182 		}
183 	}
184 	if (ep->mode & MODE_MIDIOUT)
185 		t->rxmask |= ep->self;
186 	if (ep->mode & MODE_MIDIIN)
187 		t->txmask |= ep->self;
188 }
189 
190 /*
191  * broadcast the given message to other endpoints
192  */
193 void
194 midi_send(struct midi *iep, unsigned char *msg, int size)
195 {
196 	struct midi *oep;
197 	int i;
198 
199 #ifdef DEBUG
200 	if (log_level >= 4) {
201 		midi_log(iep);
202 		log_puts(": sending:");
203 		for (i = 0; i < size; i++) {
204 			log_puts(" ");
205 			log_putx(msg[i]);
206 		}
207 		log_puts("\n");
208 	}
209 #endif
210 	for (i = 0; i < MIDI_NEP ; i++) {
211 		if ((iep->txmask & (1 << i)) == 0)
212 			continue;
213 		oep = midi_ep + i;
214 		if (msg[0] <= 0x7f) {
215 			if (oep->owner != iep)
216 				continue;
217 		} else if (msg[0] <= 0xf7)
218 			oep->owner = iep;
219 #ifdef DEBUG
220 		if (log_level >= 4) {
221 			midi_log(iep);
222 			log_puts(" -> ");
223 			midi_log(oep);
224 			log_puts("\n");
225 		}
226 #endif
227 		oep->ops->omsg(oep->arg, msg, size);
228 	}
229 }
230 
231 /*
232  * determine if we have gained more input tickets, and if so call the
233  * fill() call-back to notify the i/o layer that it can send more data
234  */
235 void
236 midi_tickets(struct midi *iep)
237 {
238 	int i, tickets, avail, maxavail;
239 	struct midi *oep;
240 
241 	maxavail = MIDI_BUFSZ;
242 	for (i = 0; i < MIDI_NEP ; i++) {
243 		if ((iep->txmask & (1 << i)) == 0)
244 			continue;
245 		oep = midi_ep + i;
246 		avail = oep->obuf.len - oep->obuf.used;
247 		if (maxavail > avail)
248 			maxavail = avail;
249 	}
250 
251 	/*
252 	 * in the worst case output message is twice the
253 	 * input message (2-byte messages with running status)
254 	 */
255 	tickets = maxavail / 2 - iep->tickets;
256 	if (tickets > 0) {
257 		iep->tickets += tickets;
258 		iep->ops->fill(iep->arg, tickets);
259 	}
260 }
261 
262 /*
263  * recalculate tickets of endpoints sending data to this one
264  */
265 void
266 midi_fill(struct midi *oep)
267 {
268 	int i;
269 	struct midi *iep;
270 
271 	for (i = 0; i < MIDI_NEP; i++) {
272 		iep = midi_ep + i;
273 		if (iep->txmask & oep->self)
274 			midi_tickets(iep);
275 	}
276 }
277 
278 /*
279  * parse then give data chunk, and calling imsg() for each message
280  */
281 void
282 midi_in(struct midi *iep, unsigned char *idata, int icount)
283 {
284 	int i;
285 	unsigned char c;
286 
287 	for (i = 0; i < icount; i++) {
288 		c = *idata++;
289 		if (c >= 0xf8) {
290 			if (c != MIDI_ACK)
291 				iep->ops->imsg(iep->arg, &c, 1);
292 		} else if (c == SYSEX_END) {
293 			if (iep->st == SYSEX_START) {
294 				iep->msg[iep->idx++] = c;
295 				iep->ops->imsg(iep->arg, iep->msg, iep->idx);
296 			}
297 			iep->st = 0;
298 			iep->idx = 0;
299 		} else if (c >= 0xf0) {
300 			iep->msg[0] = c;
301 			iep->len = common_len[c & 7];
302 			iep->st = c;
303 			iep->idx = 1;
304 		} else if (c >= 0x80) {
305 			iep->msg[0] = c;
306 			iep->len = voice_len[(c >> 4) & 7];
307 			iep->st = c;
308 			iep->idx = 1;
309 		} else if (iep->st) {
310 			if (iep->idx == 0 && iep->st != SYSEX_START)
311 				iep->msg[iep->idx++] = iep->st;
312 			iep->msg[iep->idx++] = c;
313 			if (iep->idx == iep->len) {
314 				iep->ops->imsg(iep->arg, iep->msg, iep->idx);
315 				if (iep->st >= 0xf0)
316 					iep->st = 0;
317 				iep->idx = 0;
318 			} else if (iep->idx == MIDI_MSGMAX) {
319 				/* sysex continued */
320 				iep->ops->imsg(iep->arg, iep->msg, iep->idx);
321 				iep->idx = 0;
322 			}
323 		}
324 	}
325 	iep->tickets -= icount;
326 	if (iep->tickets < 0)
327 		iep->tickets = 0;
328 	midi_tickets(iep);
329 }
330 
331 /*
332  * store the given message in the output buffer
333  */
334 void
335 midi_out(struct midi *oep, unsigned char *idata, int icount)
336 {
337 	unsigned char *odata;
338 	int ocount;
339 #ifdef DEBUG
340 	int i;
341 #endif
342 
343 	while (icount > 0) {
344 		if (oep->obuf.used == oep->obuf.len) {
345 #ifdef DEBUG
346 			if (log_level >= 2) {
347 				midi_log(oep);
348 				log_puts(": too slow, discarding ");
349 				log_putu(oep->obuf.used);
350 				log_puts(" bytes\n");
351 			}
352 #endif
353 			abuf_rdiscard(&oep->obuf, oep->obuf.used);
354 			oep->owner = NULL;
355 			return;
356 		}
357 		odata = abuf_wgetblk(&oep->obuf, &ocount);
358 		if (ocount > icount)
359 			ocount = icount;
360 		memcpy(odata, idata, ocount);
361 #ifdef DEBUG
362 		if (log_level >= 4) {
363 			midi_log(oep);
364 			log_puts(": out: ");
365 			for (i = 0; i < ocount; i++) {
366 				log_puts(" ");
367 				log_putx(odata[i]);
368 			}
369 			log_puts("\n");
370 		}
371 #endif
372 		abuf_wcommit(&oep->obuf, ocount);
373 		icount -= ocount;
374 		idata += ocount;
375 	}
376 }
377 
378 void
379 port_log(struct port *p)
380 {
381 	midi_log(p->midi);
382 }
383 
384 void
385 port_imsg(void *arg, unsigned char *msg, int size)
386 {
387 	struct port *p = arg;
388 
389 	midi_send(p->midi, msg, size);
390 }
391 
392 
393 void
394 port_omsg(void *arg, unsigned char *msg, int size)
395 {
396 	struct port *p = arg;
397 
398 	midi_out(p->midi, msg, size);
399 }
400 
401 void
402 port_fill(void *arg, int count)
403 {
404 	/* no flow control */
405 }
406 
407 void
408 port_exit(void *arg)
409 {
410 #ifdef DEBUG
411 	struct port *p = arg;
412 
413 	if (log_level >= 3) {
414 		port_log(p);
415 		log_puts(": port exit\n");
416 		panic();
417 	}
418 #endif
419 }
420 
421 /*
422  * create a new midi port
423  */
424 struct port *
425 port_new(char *path, unsigned int mode, int hold)
426 {
427 	struct port *c;
428 
429 	c = xmalloc(sizeof(struct port));
430 	c->path = xstrdup(path);
431 	c->state = PORT_CFG;
432 	c->hold = hold;
433 	c->midi = midi_new(&port_midiops, c, mode);
434 	c->num = midi_portnum++;
435 	c->next = port_list;
436 	port_list = c;
437 	return c;
438 }
439 
440 /*
441  * destroy the given midi port
442  */
443 void
444 port_del(struct port *c)
445 {
446 	struct port **p;
447 
448 	if (c->state != PORT_CFG)
449 		port_close(c);
450 	midi_del(c->midi);
451 	for (p = &port_list; *p != c; p = &(*p)->next) {
452 #ifdef DEBUG
453 		if (*p == NULL) {
454 			log_puts("port to delete not on list\n");
455 			panic();
456 		}
457 #endif
458 	}
459 	*p = c->next;
460 	xfree(c->path);
461 	xfree(c);
462 }
463 
464 int
465 port_ref(struct port *c)
466 {
467 #ifdef DEBUG
468 	if (log_level >= 3) {
469 		port_log(c);
470 		log_puts(": port requested\n");
471 	}
472 #endif
473 	if (c->state == PORT_CFG && !port_open(c))
474 		return 0;
475 	return 1;
476 }
477 
478 void
479 port_unref(struct port *c)
480 {
481 	int i, rxmask;
482 
483 #ifdef DEBUG
484 	if (log_level >= 3) {
485 		port_log(c);
486 		log_puts(": port released\n");
487 	}
488 #endif
489 	for (rxmask = 0, i = 0; i < MIDI_NEP; i++)
490 		rxmask |= midi_ep[i].txmask;
491 	if ((rxmask & c->midi->self) == 0 && c->midi->txmask == 0 &&
492 	    c->state == PORT_INIT && !c->hold)
493 		port_drain(c);
494 }
495 
496 struct port *
497 port_bynum(int num)
498 {
499 	struct port *p;
500 
501 	for (p = port_list; p != NULL; p = p->next) {
502 		if (p->num == num)
503 			return p;
504 	}
505 	return NULL;
506 }
507 
508 int
509 port_open(struct port *c)
510 {
511 	if (!port_mio_open(c)) {
512 		if (log_level >= 1) {
513 			log_puts(c->path);
514 			log_puts(": failed to open midi port\n");
515 		}
516 		return 0;
517 	}
518 	c->state = PORT_INIT;
519 	return 1;
520 }
521 
522 int
523 port_close(struct port *c)
524 {
525 	int i;
526 	struct midi *ep;
527 #ifdef DEBUG
528 	if (c->state == PORT_CFG) {
529 		port_log(c);
530 		log_puts(": can't close port (not opened)\n");
531 		panic();
532 	}
533 #endif
534 	c->state = PORT_CFG;
535 	port_mio_close(c);
536 
537 	for (i = 0; i < MIDI_NEP; i++) {
538 		ep = midi_ep + i;
539 		if ((ep->txmask & c->midi->self) ||
540 		    (c->midi->txmask & ep->self))
541 			ep->ops->exit(ep->arg);
542 	}
543 	return 1;
544 }
545 
546 void
547 port_drain(struct port *c)
548 {
549 	struct midi *ep = c->midi;
550 
551 	if (!(ep->mode & MODE_MIDIOUT) || ep->obuf.used == 0)
552 		port_close(c);
553 	else {
554 		c->state = PORT_DRAIN;
555 #ifdef DEBUG
556 		if (log_level >= 3) {
557 			port_log(c);
558 			log_puts(": draining\n");
559 		}
560 #endif
561 	}
562 }
563 
564 int
565 port_init(struct port *c)
566 {
567 	if (c->hold)
568 		return port_open(c);
569 	return 1;
570 }
571 
572 void
573 port_done(struct port *c)
574 {
575 	if (c->state == PORT_INIT)
576 		port_drain(c);
577 }
578