Annotation of src/usr.bin/aucat/midi.c, Revision 1.9
1.9 ! ratchov 1: /* $OpenBSD: midi.c,v 1.8 2009/08/29 14:46:44 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: /*
73: * send the message stored in of ibuf->mdata to obuf
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:
81: itodo = ibuf->mused;
82: idata = ibuf->mdata;
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: }
98: ibuf->mused = 0;
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) {
148: if (ibuf->mindex == 0 && ibuf->mstatus) {
149: ibuf->mdata[ibuf->mused++] = ibuf->mstatus;
150: ibuf->mindex++;
151: }
152: ibuf->mdata[ibuf->mused++] = c;
153: ibuf->mindex++;
154: if (ibuf->mindex == ibuf->mlen) {
155: thru_flush(p, ibuf, obuf);
156: if (ibuf->mstatus >= 0xf0)
157: ibuf->mstatus = 0;
158: ibuf->mindex = 0;
159: }
160: if (ibuf->mused == MDATA_NMAX) {
161: if (ibuf->mused == ibuf->mindex ||
162: p->u.thru.owner == ibuf)
163: thru_flush(p, ibuf, obuf);
164: else
165: ibuf->mused = 0;
166: }
167: } else if (c < 0xf8) {
168: if (ibuf->mused == ibuf->mindex ||
169: p->u.thru.owner == ibuf) {
170: thru_flush(p, ibuf, obuf);
171: } else
172: ibuf->mused = 0;
173: ibuf->mdata[0] = c;
174: ibuf->mused = 1;
175: ibuf->mlen = (c >= 0xf0) ?
176: common_len[c & 7] :
177: voice_len[(c >> 4) & 7];
178: if (ibuf->mlen == 1) {
179: thru_flush(p, ibuf, obuf);
180: ibuf->mindex = 0;
181: ibuf->mstatus = 0;
182: ibuf->mlen = 0;
183: } else {
184: ibuf->mstatus = c;
185: ibuf->mindex = 1;
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;
201: if (ibuf->mtickets == 0) {
202: return 0;
203: }
204: todo = ibuf->used;
205: if (todo > ibuf->mtickets)
206: todo = ibuf->mtickets;
207: ibuf->mtickets -= todo;
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: {
228: }
229:
230: void
231: thru_hup(struct aproc *p, struct abuf *obuf)
232: {
233: }
234:
235: void
236: thru_newin(struct aproc *p, struct abuf *ibuf)
237: {
238: ibuf->mused = 0;
239: ibuf->mlen = 0;
240: ibuf->mindex = 0;
241: ibuf->mstatus = 0;
242: ibuf->mtickets = MIDITHRU_XFER;
243: }
244:
245: void
246: thru_done(struct aproc *p)
247: {
248: timo_del(&p->u.thru.timo);
249: }
250:
251: struct aproc_ops thru_ops = {
252: "thru",
253: thru_in,
254: thru_out,
255: thru_eof,
256: thru_hup,
257: thru_newin,
258: NULL, /* newout */
259: NULL, /* ipos */
260: NULL, /* opos */
261: thru_done
262: };
263:
1.7 ratchov 264: /*
265: * call-back invoked periodically to implement throttling at each invocation
266: * gain more ``tickets'' for processing. If one of the buffer was blocked by
267: * the throttelling mechanism, then run it
268: */
1.1 ratchov 269: void
270: thru_cb(void *addr)
271: {
272: struct aproc *p = (struct aproc *)addr;
273: struct abuf *i, *inext;
274: unsigned tickets;
275:
276: timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
277:
278: for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
279: inext = LIST_NEXT(i, ient);
280: tickets = i->mtickets;
281: i->mtickets = MIDITHRU_XFER;
282: if (tickets == 0)
283: abuf_run(i);
284: }
285: }
286:
287: struct aproc *
288: thru_new(char *name)
289: {
290: struct aproc *p;
291:
292: p = aproc_new(&thru_ops, name);
293: p->u.thru.owner = NULL;
294: timo_set(&p->u.thru.timo, thru_cb, p);
295: timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
1.3 ratchov 296: return p;
297: }
298:
1.7 ratchov 299: /*
300: * broadcast a message to all output buffers on the behalf of ibuf.
301: * ie. don't sent back the message to the sender
302: */
1.3 ratchov 303: void
304: ctl_sendmsg(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len)
305: {
306: unsigned ocount, itodo;
307: unsigned char *odata, *idata;
308: struct abuf *i, *inext;
309:
310: for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
311: inext = LIST_NEXT(i, oent);
312: if (i->duplex == ibuf)
313: continue;
314: itodo = len;
315: idata = msg;
316: while (itodo > 0) {
317: if (!ABUF_WOK(i)) {
318: abuf_rdiscard(i, i->used);
319: }
320: odata = abuf_wgetblk(i, &ocount, 0);
321: if (ocount > itodo)
322: ocount = itodo;
323: memcpy(odata, idata, ocount);
324: abuf_wcommit(i, ocount);
325: itodo -= ocount;
326: idata += ocount;
327: }
328: (void)abuf_flush(i);
329: }
330: }
331:
1.7 ratchov 332: /*
333: * allocate a new slot (ie midi channel), register the given call-back
334: * to be called volume is changed by MIDI. The call-back is invoked at
335: * initialization to restore the saved volume.
336: */
1.3 ratchov 337: int
1.5 ratchov 338: ctl_slotnew(struct aproc *p, char *who, void (*cb)(void *, unsigned), void *arg)
1.3 ratchov 339: {
340: char *s;
341: struct ctl_slot *slot;
1.4 ratchov 342: char name[CTL_NAMEMAX];
343: unsigned i, unit, umap = 0;
1.6 ratchov 344: unsigned ser, bestser, bestidx;
1.3 ratchov 345:
1.4 ratchov 346: /*
347: * create a ``valid'' control name (lowcase, remove [^a-z], trucate)
348: */
1.5 ratchov 349: for (i = 0, s = who; ; s++) {
1.4 ratchov 350: if (i == CTL_NAMEMAX - 1 || *s == '\0') {
351: name[i] = '\0';
352: break;
353: } else if (*s >= 'A' && *s <= 'Z') {
354: name[i++] = *s + 'a' - 'A';
355: } else if (*s >= 'a' && *s <= 'z')
356: name[i++] = *s;
357: }
358: if (i == 0)
359: strlcpy(name, "noname", CTL_NAMEMAX);
360:
361: /*
362: * find the instance number of the control name
363: */
364: for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.5 ratchov 365: if (slot->cb == NULL)
1.4 ratchov 366: continue;
367: if (strcmp(slot->name, name) == 0)
368: umap |= (1 << i);
369: }
370: for (unit = 0; unit < CTL_NSLOT; unit++) {
371: if (unit == CTL_NSLOT)
1.3 ratchov 372: return -1;
1.4 ratchov 373: if ((umap & (1 << i)) == 0)
1.3 ratchov 374: break;
375: }
1.4 ratchov 376: /*
377: * find a free controller slot with the same name/unit
378: */
379: for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.5 ratchov 380: if (slot->cb == NULL &&
1.4 ratchov 381: strcmp(slot->name, name) == 0 &&
382: slot->unit == unit) {
1.5 ratchov 383: slot->cb = cb;
384: slot->arg = arg;
1.7 ratchov 385: slot->cb(slot->arg, slot->vol);
386: ctl_slotvol(p, i, slot->vol);
1.4 ratchov 387: return i;
388: }
389: }
390:
391: /*
1.6 ratchov 392: * couldn't find a matching slot, pick oldest free slot
1.4 ratchov 393: */
1.6 ratchov 394: bestser = 0;
395: bestidx = CTL_NSLOT;
396: for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
397: if (slot->cb != NULL)
398: continue;
399: ser = p->u.ctl.serial - slot->serial;
400: if (ser > bestser) {
401: bestser = ser;
402: bestidx = i;
403: }
1.3 ratchov 404: }
1.6 ratchov 405: if (bestidx == CTL_NSLOT)
406: return -1;
407: slot = p->u.ctl.slot + bestidx;
1.4 ratchov 408: strlcpy(slot->name, name, CTL_NAMEMAX);
1.6 ratchov 409: slot->serial = p->u.ctl.serial++;
1.4 ratchov 410: slot->unit = unit;
1.7 ratchov 411: slot->vol = MIDI_MAXCTL;
1.5 ratchov 412: slot->cb = cb;
413: slot->arg = arg;
1.7 ratchov 414: slot->cb(slot->arg, slot->vol);
415: ctl_slotvol(p, bestidx, slot->vol);
1.6 ratchov 416: return bestidx;
1.3 ratchov 417: }
418:
1.7 ratchov 419: /*
420: * release the given slot
421: */
1.3 ratchov 422: void
423: ctl_slotdel(struct aproc *p, int index)
424: {
1.5 ratchov 425: p->u.ctl.slot[index].cb = NULL;
1.3 ratchov 426: }
427:
1.7 ratchov 428: /*
429: * notifty the mixer that volume changed, called by whom allocad the slot using
430: * ctl_slotnew(). Note: it doesn't make sens to call this from within the
431: * call-back.
432: */
1.3 ratchov 433: void
434: ctl_slotvol(struct aproc *p, int slot, unsigned vol)
435: {
436: unsigned char msg[3];
437:
1.7 ratchov 438: p->u.ctl.slot[slot].vol = vol;
1.3 ratchov 439: msg[0] = MIDI_CTL | slot;
440: msg[1] = MIDI_CTLVOL;
441: msg[2] = vol;
442: ctl_sendmsg(p, NULL, msg, 3);
443: }
444:
1.7 ratchov 445: /*
446: * handle a MIDI event received from ibuf
447: */
1.3 ratchov 448: void
449: ctl_ev(struct aproc *p, struct abuf *ibuf)
450: {
451: unsigned chan;
1.5 ratchov 452: struct ctl_slot *slot;
1.3 ratchov 453: if ((ibuf->mdata[0] & MIDI_CMDMASK) == MIDI_CTL &&
454: ibuf->mdata[1] == MIDI_CTLVOL) {
455: chan = ibuf->mdata[0] & MIDI_CHANMASK;
456: if (chan >= CTL_NSLOT)
457: return;
1.5 ratchov 458: slot = p->u.ctl.slot + chan;
459: if (slot->cb == NULL)
1.3 ratchov 460: return;
1.7 ratchov 461: slot->vol = ibuf->mdata[2];
462: slot->cb(slot->arg, slot->vol);
1.3 ratchov 463: ctl_sendmsg(p, ibuf, ibuf->mdata, ibuf->mlen);
464: }
465: }
466:
467: int
468: ctl_in(struct aproc *p, struct abuf *ibuf)
469: {
470: unsigned char *idata;
471: unsigned c, i, icount;
472:
473: if (!ABUF_ROK(ibuf))
474: return 0;
475: idata = abuf_rgetblk(ibuf, &icount, 0);
476: for (i = 0; i < icount; i++) {
477: c = *idata++;
1.8 ratchov 478: if (c >= 0xf8) {
479: /* clock events not used yet */
480: } else if (c >= 0xf0) {
481: if (ibuf->mstatus == 0xf0 && c == 0xf7 &&
482: ibuf->mindex < MDATA_NMAX) {
483: ibuf->mdata[ibuf->mindex++] = c;
484: ctl_ev(p, ibuf);
485: continue;
486: }
487: ibuf->mdata[0] = c;
488: ibuf->mlen = common_len[c & 7];
489: ibuf->mstatus = c;
490: ibuf->mindex = 1;
1.3 ratchov 491: } else if (c >= 0x80) {
492: ibuf->mdata[0] = c;
493: ibuf->mlen = voice_len[(c >> 4) & 7];
494: ibuf->mstatus = c;
495: ibuf->mindex = 1;
496: } else if (ibuf->mstatus) {
1.8 ratchov 497: if (ibuf->mindex == MDATA_NMAX)
498: continue;
1.3 ratchov 499: if (ibuf->mindex == 0)
500: ibuf->mdata[ibuf->mindex++] = ibuf->mstatus;
501: ibuf->mdata[ibuf->mindex++] = c;
502: if (ibuf->mindex == ibuf->mlen) {
503: ctl_ev(p, ibuf);
504: ibuf->mindex = 0;
505: }
506: }
507: }
508: abuf_rdiscard(ibuf, icount);
509: return 1;
510: }
511:
512: int
513: ctl_out(struct aproc *p, struct abuf *obuf)
514: {
515: return 0;
516: }
517:
518: void
519: ctl_eof(struct aproc *p, struct abuf *ibuf)
520: {
521: }
522:
523: void
524: ctl_hup(struct aproc *p, struct abuf *obuf)
525: {
526: }
527:
528: void
529: ctl_newin(struct aproc *p, struct abuf *ibuf)
530: {
531: ibuf->mused = 0;
532: ibuf->mlen = 0;
533: ibuf->mindex = 0;
534: ibuf->mstatus = 0;
535: }
536:
537: void
538: ctl_done(struct aproc *p)
539: {
540: }
541:
542: struct aproc_ops ctl_ops = {
543: "ctl",
544: ctl_in,
545: ctl_out,
546: ctl_eof,
547: ctl_hup,
548: ctl_newin,
549: NULL, /* newout */
550: NULL, /* ipos */
551: NULL, /* opos */
552: ctl_done
553: };
554:
555: struct aproc *
556: ctl_new(char *name)
557: {
558: struct aproc *p;
1.5 ratchov 559: struct ctl_slot *s;
1.3 ratchov 560: unsigned i;
561:
562: p = aproc_new(&ctl_ops, name);
1.6 ratchov 563: p->u.ctl.serial = 0;
1.5 ratchov 564: for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
1.3 ratchov 565: p->u.ctl.slot[i].unit = i;
1.5 ratchov 566: p->u.ctl.slot[i].cb = NULL;
1.7 ratchov 567: p->u.ctl.slot[i].vol = MIDI_MAXCTL;
1.6 ratchov 568: p->u.ctl.slot[i].serial = p->u.ctl.serial++;
1.3 ratchov 569: strlcpy(p->u.ctl.slot[i].name, "unknown", CTL_NAMEMAX);
570: }
1.1 ratchov 571: return p;
572: }
573: