xref: /openbsd-src/usr.bin/sndiod/midi.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: midi.c,v 1.10 2013/09/28 18:49:32 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 #ifdef DEBUG
379 void
380 port_log(struct port *p)
381 {
382 	midi_log(p->midi);
383 }
384 #endif
385 
386 void
387 port_imsg(void *arg, unsigned char *msg, int size)
388 {
389 	struct port *p = arg;
390 
391 	midi_send(p->midi, msg, size);
392 }
393 
394 
395 void
396 port_omsg(void *arg, unsigned char *msg, int size)
397 {
398 	struct port *p = arg;
399 
400 	midi_out(p->midi, msg, size);
401 }
402 
403 void
404 port_fill(void *arg, int count)
405 {
406 	/* no flow control */
407 }
408 
409 void
410 port_exit(void *arg)
411 {
412 #ifdef DEBUG
413 	struct port *p = arg;
414 
415 	if (log_level >= 3) {
416 		port_log(p);
417 		log_puts(": port exit\n");
418 		panic();
419 	}
420 #endif
421 }
422 
423 /*
424  * create a new midi port
425  */
426 struct port *
427 port_new(char *path, unsigned int mode, int hold)
428 {
429 	struct port *c, **pc;
430 
431 	c = xmalloc(sizeof(struct port));
432 	c->path = path;
433 	c->state = PORT_CFG;
434 	c->hold = hold;
435 	c->midi = midi_new(&port_midiops, c, mode);
436 	midi_portnum++;
437 	for (pc = &port_list; *pc != NULL; pc = &(*pc)->next)
438 		; /* nothing */
439 	c->next = NULL;
440 	*pc = c;
441 	return c;
442 }
443 
444 /*
445  * destroy the given midi port
446  */
447 void
448 port_del(struct port *c)
449 {
450 	struct port **p;
451 
452 	if (c->state != PORT_CFG)
453 		port_close(c);
454 	midi_del(c->midi);
455 	for (p = &port_list; *p != c; p = &(*p)->next) {
456 #ifdef DEBUG
457 		if (*p == NULL) {
458 			log_puts("port to delete not on list\n");
459 			panic();
460 		}
461 #endif
462 	}
463 	*p = c->next;
464 	xfree(c);
465 }
466 
467 int
468 port_ref(struct port *c)
469 {
470 #ifdef DEBUG
471 	if (log_level >= 3) {
472 		port_log(c);
473 		log_puts(": port requested\n");
474 	}
475 #endif
476 	if (c->state == PORT_CFG && !port_open(c))
477 		return 0;
478 	return 1;
479 }
480 
481 void
482 port_unref(struct port *c)
483 {
484 	int i, rxmask;
485 
486 #ifdef DEBUG
487 	if (log_level >= 3) {
488 		port_log(c);
489 		log_puts(": port released\n");
490 	}
491 #endif
492 	for (rxmask = 0, i = 0; i < MIDI_NEP; i++)
493 		rxmask |= midi_ep[i].txmask;
494 	if ((rxmask & c->midi->self) == 0 && c->midi->txmask == 0 &&
495 	    c->state == PORT_INIT && !c->hold)
496 		port_drain(c);
497 }
498 
499 struct port *
500 port_bynum(int num)
501 {
502 	struct port *p;
503 
504 	for (p = port_list; p != NULL; p = p->next) {
505 		if (num-- == 0)
506 			return p;
507 	}
508 	return NULL;
509 }
510 
511 int
512 port_open(struct port *c)
513 {
514 	if (!port_mio_open(c)) {
515 		if (log_level >= 1) {
516 			log_puts(c->path);
517 			log_puts(": failed to open midi port\n");
518 		}
519 		return 0;
520 	}
521 	c->state = PORT_INIT;
522 	return 1;
523 }
524 
525 int
526 port_close(struct port *c)
527 {
528 	int i;
529 	struct midi *ep;
530 #ifdef DEBUG
531 	if (c->state == PORT_CFG) {
532 		port_log(c);
533 		log_puts(": can't close port (not opened)\n");
534 		panic();
535 	}
536 #endif
537 	c->state = PORT_CFG;
538 	port_mio_close(c);
539 
540 	for (i = 0; i < MIDI_NEP; i++) {
541 		ep = midi_ep + i;
542 		if ((ep->txmask & c->midi->self) ||
543 		    (c->midi->txmask & ep->self))
544 			ep->ops->exit(ep->arg);
545 	}
546 	return 1;
547 }
548 
549 void
550 port_drain(struct port *c)
551 {
552 	struct midi *ep = c->midi;
553 
554 	if (!(ep->mode & MODE_MIDIOUT) || ep->obuf.used == 0)
555 		port_close(c);
556 	else {
557 		c->state = PORT_DRAIN;
558 #ifdef DEBUG
559 		if (log_level >= 3) {
560 			port_log(c);
561 			log_puts(": draining\n");
562 		}
563 #endif
564 	}
565 }
566 
567 int
568 port_init(struct port *c)
569 {
570 	if (c->hold)
571 		return port_open(c);
572 	return 1;
573 }
574 
575 void
576 port_done(struct port *c)
577 {
578 	if (c->state == PORT_INIT)
579 		port_drain(c);
580 }
581