Annotation of src/usr.bin/aucat/midi.c, Revision 1.12
1.12 ! ratchov 1: /* $OpenBSD: midi.c,v 1.11 2009/10/10 12:43:09 ratchov Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2008 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: /*
18: * TODO
19: *
1.7 ratchov 20: * use shadow variables (to save NRPNs, LSB of controller)
21: * in the midi merger
1.1 ratchov 22: *
23: * make output and input identical when only one
24: * input is used (fix running status)
25: */
26: #include <stdio.h>
27: #include <stdlib.h>
28: #include <string.h>
29:
30: #include "abuf.h"
31: #include "aproc.h"
1.3 ratchov 32: #include "conf.h"
33: #include "dev.h"
1.1 ratchov 34: #include "midi.h"
35:
36: /*
37: * input data rate is XFER / TIMO (in bytes per microsecond),
38: * it must be slightly larger than the MIDI standard 3125 bytes/s
39: */
40: #define MIDITHRU_XFER 340
41: #define MIDITHRU_TIMO 100000
42:
1.3 ratchov 43: /*
44: * masks to extract command and channel of status byte
45: */
46: #define MIDI_CMDMASK 0xf0
47: #define MIDI_CHANMASK 0x0f
48:
49: /*
50: * MIDI status bytes of voice messages
51: */
52: #define MIDI_NOFF 0x80 /* note off */
53: #define MIDI_NON 0x90 /* note on */
54: #define MIDI_KAT 0xa0 /* key after touch */
55: #define MIDI_CTL 0xb0 /* controller */
56: #define MIDI_PC 0xc0 /* program change */
57: #define MIDI_CAT 0xd0 /* channel after touch */
58: #define MIDI_BEND 0xe0 /* pitch bend */
59:
60: /*
61: * MIDI controller numbers
62: */
63: #define MIDI_CTLVOL 7 /* volume */
64: #define MIDI_CTLPAN 11 /* pan */
65:
66: /*
67: * length of voice and common messages (status byte included)
68: */
1.1 ratchov 69: unsigned voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
70: unsigned common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
71:
1.7 ratchov 72: /*
1.10 ratchov 73: * send the message stored in of ibuf->r.midi.msg to obuf
1.7 ratchov 74: */
1.1 ratchov 75: void
76: thru_flush(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
77: {
78: unsigned ocount, itodo;
79: unsigned char *odata, *idata;
80:
1.10 ratchov 81: itodo = ibuf->r.midi.used;
82: idata = ibuf->r.midi.msg;
1.1 ratchov 83: while (itodo > 0) {
84: if (!ABUF_WOK(obuf)) {
85: abuf_rdiscard(obuf, obuf->used);
86: if (p->u.thru.owner == ibuf)
87: p->u.thru.owner = NULL;
88: return;
89: }
90: odata = abuf_wgetblk(obuf, &ocount, 0);
91: if (ocount > itodo)
92: ocount = itodo;
93: memcpy(odata, idata, ocount);
94: abuf_wcommit(obuf, ocount);
95: itodo -= ocount;
96: idata += ocount;
97: }
1.10 ratchov 98: ibuf->r.midi.used = 0;
1.1 ratchov 99: p->u.thru.owner = ibuf;
100: }
101:
1.7 ratchov 102: /*
103: * send the real-time message (one byte) to obuf, similar to thrui_flush()
104: */
1.1 ratchov 105: void
106: thru_rt(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned c)
107: {
108: unsigned ocount;
109: unsigned char *odata;
110:
111: if (!ABUF_WOK(obuf)) {
112: abuf_rdiscard(obuf, obuf->used);
113: if (p->u.thru.owner == ibuf)
114: p->u.thru.owner = NULL;
115: }
116: odata = abuf_wgetblk(obuf, &ocount, 0);
117: odata[0] = c;
118: abuf_wcommit(obuf, 1);
119: }
120:
1.7 ratchov 121: /*
122: * parse ibuf contents and store each message into obuf,
123: * use at most ``todo'' bytes (for throttling)
124: */
1.1 ratchov 125: void
126: thru_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned todo)
127: {
128: unsigned char *idata;
129: unsigned c, icount, ioffs;
130:
131: idata = NULL;
132: icount = ioffs = 0;
133: for (;;) {
134: if (icount == 0) {
135: if (todo == 0)
136: break;
137: idata = abuf_rgetblk(ibuf, &icount, ioffs);
138: if (icount > todo)
139: icount = todo;
140: if (icount == 0)
141: break;
142: todo -= icount;
143: ioffs += icount;
144: }
145: c = *idata++;
146: icount--;
147: if (c < 0x80) {
1.10 ratchov 148: if (ibuf->r.midi.idx == 0 && ibuf->r.midi.st) {
149: ibuf->r.midi.msg[ibuf->r.midi.used++] = ibuf->r.midi.st;
150: ibuf->r.midi.idx++;
1.1 ratchov 151: }
1.10 ratchov 152: ibuf->r.midi.msg[ibuf->r.midi.used++] = c;
153: ibuf->r.midi.idx++;
154: if (ibuf->r.midi.idx == ibuf->r.midi.len) {
1.1 ratchov 155: thru_flush(p, ibuf, obuf);
1.10 ratchov 156: if (ibuf->r.midi.st >= 0xf0)
157: ibuf->r.midi.st = 0;
158: ibuf->r.midi.idx = 0;
1.1 ratchov 159: }
1.10 ratchov 160: if (ibuf->r.midi.used == MIDI_MSGMAX) {
161: if (ibuf->r.midi.used == ibuf->r.midi.idx ||
1.1 ratchov 162: p->u.thru.owner == ibuf)
163: thru_flush(p, ibuf, obuf);
164: else
1.10 ratchov 165: ibuf->r.midi.used = 0;
1.1 ratchov 166: }
167: } else if (c < 0xf8) {
1.10 ratchov 168: if (ibuf->r.midi.used == ibuf->r.midi.idx ||
1.1 ratchov 169: p->u.thru.owner == ibuf) {
170: thru_flush(p, ibuf, obuf);
171: } else
1.10 ratchov 172: ibuf->r.midi.used = 0;
173: ibuf->r.midi.msg[0] = c;
174: ibuf->r.midi.used = 1;
175: ibuf->r.midi.len = (c >= 0xf0) ?
1.1 ratchov 176: common_len[c & 7] :
177: voice_len[(c >> 4) & 7];
1.10 ratchov 178: if (ibuf->r.midi.len == 1) {
1.1 ratchov 179: thru_flush(p, ibuf, obuf);
1.10 ratchov 180: ibuf->r.midi.idx = 0;
181: ibuf->r.midi.st = 0;
182: ibuf->r.midi.len = 0;
1.1 ratchov 183: } else {
1.10 ratchov 184: ibuf->r.midi.st = c;
185: ibuf->r.midi.idx = 1;
1.1 ratchov 186: }
187: } else {
188: thru_rt(p, ibuf, obuf, c);
189: }
190: }
191: }
192:
193: int
194: thru_in(struct aproc *p, struct abuf *ibuf)
195: {
196: struct abuf *i, *inext;
197: unsigned todo;
198:
199: if (!ABUF_ROK(ibuf))
200: return 0;
1.10 ratchov 201: if (ibuf->tickets == 0) {
1.1 ratchov 202: return 0;
203: }
204: todo = ibuf->used;
1.10 ratchov 205: if (todo > ibuf->tickets)
206: todo = ibuf->tickets;
207: ibuf->tickets -= todo;
1.1 ratchov 208: for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
209: inext = LIST_NEXT(i, oent);
210: if (ibuf->duplex == i)
211: continue;
212: thru_bcopy(p, ibuf, i, todo);
213: (void)abuf_flush(i);
214: }
215: abuf_rdiscard(ibuf, todo);
216: return 1;
217: }
218:
219: int
220: thru_out(struct aproc *p, struct abuf *obuf)
221: {
222: return 0;
223: }
224:
225: void
226: thru_eof(struct aproc *p, struct abuf *ibuf)
227: {
1.11 ratchov 228: if (!(p->u.thru.flags & THRU_AUTOQUIT))
229: return;
230: if (LIST_EMPTY(&p->obuflist) || LIST_EMPTY(&p->ibuflist))
231: aproc_del(p);
1.1 ratchov 232: }
233:
234: void
235: thru_hup(struct aproc *p, struct abuf *obuf)
236: {
1.11 ratchov 237: if (!(p->u.thru.flags & THRU_AUTOQUIT))
238: return;
239: if (LIST_EMPTY(&p->obuflist) || LIST_EMPTY(&p->ibuflist))
240: aproc_del(p);
1.1 ratchov 241: }
242:
243: void
244: thru_newin(struct aproc *p, struct abuf *ibuf)
245: {
1.10 ratchov 246: ibuf->r.midi.used = 0;
247: ibuf->r.midi.len = 0;
248: ibuf->r.midi.idx = 0;
249: ibuf->r.midi.st = 0;
250: ibuf->tickets = MIDITHRU_XFER;
1.1 ratchov 251: }
252:
253: void
254: thru_done(struct aproc *p)
255: {
256: timo_del(&p->u.thru.timo);
257: }
258:
259: struct aproc_ops thru_ops = {
260: "thru",
261: thru_in,
262: thru_out,
263: thru_eof,
264: thru_hup,
265: thru_newin,
266: NULL, /* newout */
267: NULL, /* ipos */
268: NULL, /* opos */
269: thru_done
270: };
271:
1.7 ratchov 272: /*
273: * call-back invoked periodically to implement throttling at each invocation
274: * gain more ``tickets'' for processing. If one of the buffer was blocked by
275: * the throttelling mechanism, then run it
276: */
1.1 ratchov 277: void
278: thru_cb(void *addr)
279: {
280: struct aproc *p = (struct aproc *)addr;
281: struct abuf *i, *inext;
282: unsigned tickets;
283:
284: timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
285:
286: for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
287: inext = LIST_NEXT(i, ient);
1.10 ratchov 288: tickets = i->tickets;
289: i->tickets = MIDITHRU_XFER;
1.1 ratchov 290: if (tickets == 0)
291: abuf_run(i);
292: }
293: }
294:
295: struct aproc *
296: thru_new(char *name)
297: {
298: struct aproc *p;
299:
300: p = aproc_new(&thru_ops, name);
301: p->u.thru.owner = NULL;
302: timo_set(&p->u.thru.timo, thru_cb, p);
303: timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
1.3 ratchov 304: return p;
305: }
306:
1.12 ! ratchov 307:
1.7 ratchov 308: /*
309: * broadcast a message to all output buffers on the behalf of ibuf.
310: * ie. don't sent back the message to the sender
311: */
1.3 ratchov 312: void
313: ctl_sendmsg(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len)
314: {
315: unsigned ocount, itodo;
316: unsigned char *odata, *idata;
317: struct abuf *i, *inext;
318:
319: for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
320: inext = LIST_NEXT(i, oent);
321: if (i->duplex == ibuf)
322: continue;
323: itodo = len;
324: idata = msg;
325: while (itodo > 0) {
326: if (!ABUF_WOK(i)) {
327: abuf_rdiscard(i, i->used);
328: }
329: odata = abuf_wgetblk(i, &ocount, 0);
330: if (ocount > itodo)
331: ocount = itodo;
332: memcpy(odata, idata, ocount);
333: abuf_wcommit(i, ocount);
334: itodo -= ocount;
335: idata += ocount;
336: }
337: (void)abuf_flush(i);
338: }
339: }
340:
1.7 ratchov 341: /*
1.12 ! ratchov 342: * find the best matching free slot index (ie midi channel).
! 343: * return -1, if there are no free slots anymore
1.7 ratchov 344: */
1.3 ratchov 345: int
1.12 ! ratchov 346: ctl_getidx(struct aproc *p, char *who)
1.3 ratchov 347: {
348: char *s;
349: struct ctl_slot *slot;
1.4 ratchov 350: char name[CTL_NAMEMAX];
351: unsigned i, unit, umap = 0;
1.6 ratchov 352: unsigned ser, bestser, bestidx;
1.3 ratchov 353:
1.4 ratchov 354: /*
355: * create a ``valid'' control name (lowcase, remove [^a-z], trucate)
356: */
1.5 ratchov 357: for (i = 0, s = who; ; s++) {
1.4 ratchov 358: if (i == CTL_NAMEMAX - 1 || *s == '\0') {
359: name[i] = '\0';
360: break;
361: } else if (*s >= 'A' && *s <= 'Z') {
362: name[i++] = *s + 'a' - 'A';
363: } else if (*s >= 'a' && *s <= 'z')
364: name[i++] = *s;
365: }
366: if (i == 0)
367: strlcpy(name, "noname", CTL_NAMEMAX);
368:
369: /*
370: * find the instance number of the control name
371: */
372: for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.12 ! ratchov 373: if (slot->ops == NULL)
1.4 ratchov 374: continue;
375: if (strcmp(slot->name, name) == 0)
376: umap |= (1 << i);
377: }
1.12 ! ratchov 378: for (unit = 0; ; unit++) {
1.4 ratchov 379: if (unit == CTL_NSLOT)
1.3 ratchov 380: return -1;
1.12 ! ratchov 381: if ((umap & (1 << unit)) == 0)
1.3 ratchov 382: break;
383: }
1.4 ratchov 384: /*
385: * find a free controller slot with the same name/unit
386: */
387: for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.12 ! ratchov 388: if (slot->ops == NULL &&
1.4 ratchov 389: strcmp(slot->name, name) == 0 &&
390: slot->unit == unit) {
391: return i;
392: }
393: }
394:
395: /*
1.6 ratchov 396: * couldn't find a matching slot, pick oldest free slot
1.12 ! ratchov 397: * and set its name/unit
1.4 ratchov 398: */
1.6 ratchov 399: bestser = 0;
400: bestidx = CTL_NSLOT;
401: for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.12 ! ratchov 402: if (slot->ops != NULL)
1.6 ratchov 403: continue;
404: ser = p->u.ctl.serial - slot->serial;
405: if (ser > bestser) {
406: bestser = ser;
407: bestidx = i;
408: }
1.3 ratchov 409: }
1.6 ratchov 410: if (bestidx == CTL_NSLOT)
411: return -1;
412: slot = p->u.ctl.slot + bestidx;
1.4 ratchov 413: strlcpy(slot->name, name, CTL_NAMEMAX);
1.6 ratchov 414: slot->serial = p->u.ctl.serial++;
1.4 ratchov 415: slot->unit = unit;
1.7 ratchov 416: slot->vol = MIDI_MAXCTL;
1.6 ratchov 417: return bestidx;
1.3 ratchov 418: }
419:
1.7 ratchov 420: /*
1.12 ! ratchov 421: * allocate a new slot and register the given call-backs
! 422: */
! 423: int
! 424: ctl_slotnew(struct aproc *p, char *who, struct ctl_ops *ops, void *arg)
! 425: {
! 426: int idx;
! 427: struct ctl_slot *s;
! 428:
! 429: idx = ctl_getidx(p, who);
! 430: if (idx < 0)
! 431: return -1;
! 432:
! 433: s = p->u.ctl.slot + idx;
! 434: s->ops = ops;
! 435: s->arg = arg;
! 436: s->ops->vol(s->arg, s->vol);
! 437: ctl_slotvol(p, idx, s->vol);
! 438: return idx;
! 439: }
! 440:
! 441: /*
1.7 ratchov 442: * release the given slot
443: */
1.3 ratchov 444: void
445: ctl_slotdel(struct aproc *p, int index)
446: {
1.12 ! ratchov 447: p->u.ctl.slot[index].ops = NULL;
1.3 ratchov 448: }
449:
1.7 ratchov 450: /*
451: * notifty the mixer that volume changed, called by whom allocad the slot using
452: * ctl_slotnew(). Note: it doesn't make sens to call this from within the
453: * call-back.
454: */
1.3 ratchov 455: void
456: ctl_slotvol(struct aproc *p, int slot, unsigned vol)
457: {
458: unsigned char msg[3];
459:
1.7 ratchov 460: p->u.ctl.slot[slot].vol = vol;
1.3 ratchov 461: msg[0] = MIDI_CTL | slot;
462: msg[1] = MIDI_CTLVOL;
463: msg[2] = vol;
464: ctl_sendmsg(p, NULL, msg, 3);
465: }
466:
1.7 ratchov 467: /*
468: * handle a MIDI event received from ibuf
469: */
1.3 ratchov 470: void
471: ctl_ev(struct aproc *p, struct abuf *ibuf)
472: {
473: unsigned chan;
1.5 ratchov 474: struct ctl_slot *slot;
1.10 ratchov 475: if ((ibuf->r.midi.msg[0] & MIDI_CMDMASK) == MIDI_CTL &&
476: ibuf->r.midi.msg[1] == MIDI_CTLVOL) {
477: chan = ibuf->r.midi.msg[0] & MIDI_CHANMASK;
1.3 ratchov 478: if (chan >= CTL_NSLOT)
479: return;
1.5 ratchov 480: slot = p->u.ctl.slot + chan;
1.12 ! ratchov 481: if (slot->ops == NULL)
1.3 ratchov 482: return;
1.10 ratchov 483: slot->vol = ibuf->r.midi.msg[2];
1.12 ! ratchov 484: slot->ops->vol(slot->arg, slot->vol);
1.10 ratchov 485: ctl_sendmsg(p, ibuf, ibuf->r.midi.msg, ibuf->r.midi.len);
1.3 ratchov 486: }
487: }
488:
489: int
490: ctl_in(struct aproc *p, struct abuf *ibuf)
491: {
492: unsigned char *idata;
493: unsigned c, i, icount;
494:
495: if (!ABUF_ROK(ibuf))
496: return 0;
497: idata = abuf_rgetblk(ibuf, &icount, 0);
498: for (i = 0; i < icount; i++) {
499: c = *idata++;
1.8 ratchov 500: if (c >= 0xf8) {
501: /* clock events not used yet */
502: } else if (c >= 0xf0) {
1.10 ratchov 503: if (ibuf->r.midi.st == 0xf0 && c == 0xf7 &&
504: ibuf->r.midi.idx < MIDI_MSGMAX) {
505: ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
1.8 ratchov 506: ctl_ev(p, ibuf);
507: continue;
508: }
1.10 ratchov 509: ibuf->r.midi.msg[0] = c;
510: ibuf->r.midi.len = common_len[c & 7];
511: ibuf->r.midi.st = c;
512: ibuf->r.midi.idx = 1;
1.3 ratchov 513: } else if (c >= 0x80) {
1.10 ratchov 514: ibuf->r.midi.msg[0] = c;
515: ibuf->r.midi.len = voice_len[(c >> 4) & 7];
516: ibuf->r.midi.st = c;
517: ibuf->r.midi.idx = 1;
518: } else if (ibuf->r.midi.st) {
519: if (ibuf->r.midi.idx == MIDI_MSGMAX)
1.8 ratchov 520: continue;
1.10 ratchov 521: if (ibuf->r.midi.idx == 0)
522: ibuf->r.midi.msg[ibuf->r.midi.idx++] = ibuf->r.midi.st;
523: ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
524: if (ibuf->r.midi.idx == ibuf->r.midi.len) {
1.3 ratchov 525: ctl_ev(p, ibuf);
1.10 ratchov 526: ibuf->r.midi.idx = 0;
1.3 ratchov 527: }
528: }
529: }
530: abuf_rdiscard(ibuf, icount);
531: return 1;
532: }
533:
534: int
535: ctl_out(struct aproc *p, struct abuf *obuf)
536: {
537: return 0;
538: }
539:
540: void
541: ctl_eof(struct aproc *p, struct abuf *ibuf)
542: {
543: }
544:
545: void
546: ctl_hup(struct aproc *p, struct abuf *obuf)
547: {
548: }
549:
550: void
551: ctl_newin(struct aproc *p, struct abuf *ibuf)
552: {
1.10 ratchov 553: ibuf->r.midi.used = 0;
554: ibuf->r.midi.len = 0;
555: ibuf->r.midi.idx = 0;
556: ibuf->r.midi.st = 0;
1.3 ratchov 557: }
558:
559: void
560: ctl_done(struct aproc *p)
561: {
562: }
563:
564: struct aproc_ops ctl_ops = {
565: "ctl",
566: ctl_in,
567: ctl_out,
568: ctl_eof,
569: ctl_hup,
570: ctl_newin,
571: NULL, /* newout */
572: NULL, /* ipos */
573: NULL, /* opos */
574: ctl_done
575: };
576:
577: struct aproc *
578: ctl_new(char *name)
579: {
580: struct aproc *p;
1.5 ratchov 581: struct ctl_slot *s;
1.3 ratchov 582: unsigned i;
583:
584: p = aproc_new(&ctl_ops, name);
1.6 ratchov 585: p->u.ctl.serial = 0;
1.5 ratchov 586: for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
1.3 ratchov 587: p->u.ctl.slot[i].unit = i;
1.12 ! ratchov 588: p->u.ctl.slot[i].ops = NULL;
1.7 ratchov 589: p->u.ctl.slot[i].vol = MIDI_MAXCTL;
1.6 ratchov 590: p->u.ctl.slot[i].serial = p->u.ctl.serial++;
1.3 ratchov 591: strlcpy(p->u.ctl.slot[i].name, "unknown", CTL_NAMEMAX);
592: }
1.1 ratchov 593: return p;
594: }
595: