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