Annotation of src/usr.bin/aucat/midi.c, Revision 1.6
1.6 ! ratchov 1: /* $OpenBSD: midi.c,v 1.5 2009/08/26 06:10:15 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: *
20: * use abuf->duplex to implement bidirectionnal sockets
21: * that don't receive what they send
22: *
23: * use shadow variables in the midi merger
24: *
25: * make output and input identical when only one
26: * input is used (fix running status)
27: */
28: #include <stdio.h>
29: #include <stdlib.h>
30: #include <string.h>
31:
32: #include "abuf.h"
33: #include "aproc.h"
1.3 ratchov 34: #include "conf.h"
35: #include "dev.h"
1.1 ratchov 36: #include "midi.h"
37:
38: /*
39: * input data rate is XFER / TIMO (in bytes per microsecond),
40: * it must be slightly larger than the MIDI standard 3125 bytes/s
41: */
42: #define MIDITHRU_XFER 340
43: #define MIDITHRU_TIMO 100000
44:
1.3 ratchov 45: /*
46: * masks to extract command and channel of status byte
47: */
48: #define MIDI_CMDMASK 0xf0
49: #define MIDI_CHANMASK 0x0f
50:
51: /*
52: * MIDI status bytes of voice messages
53: */
54: #define MIDI_NOFF 0x80 /* note off */
55: #define MIDI_NON 0x90 /* note on */
56: #define MIDI_KAT 0xa0 /* key after touch */
57: #define MIDI_CTL 0xb0 /* controller */
58: #define MIDI_PC 0xc0 /* program change */
59: #define MIDI_CAT 0xd0 /* channel after touch */
60: #define MIDI_BEND 0xe0 /* pitch bend */
61:
62: /*
63: * MIDI controller numbers
64: */
65: #define MIDI_CTLVOL 7 /* volume */
66: #define MIDI_CTLPAN 11 /* pan */
67:
68: /*
69: * length of voice and common messages (status byte included)
70: */
1.1 ratchov 71: unsigned voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
72: unsigned common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
73:
74: void
75: thru_flush(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
76: {
77: unsigned ocount, itodo;
78: unsigned char *odata, *idata;
79:
80: itodo = ibuf->mused;
81: idata = ibuf->mdata;
82: DPRINTFN(4, "thru_flush: mused = %u\n", itodo);
83: while (itodo > 0) {
84: if (!ABUF_WOK(obuf)) {
85: abuf_rdiscard(obuf, obuf->used);
86: DPRINTFN(2, "thru_flush: discarded %u\n", obuf->used);
87: if (p->u.thru.owner == ibuf)
88: p->u.thru.owner = NULL;
89: return;
90: }
91: odata = abuf_wgetblk(obuf, &ocount, 0);
92: if (ocount > itodo)
93: ocount = itodo;
94: memcpy(odata, idata, ocount);
95: abuf_wcommit(obuf, ocount);
96: itodo -= ocount;
97: idata += ocount;
98: }
99: ibuf->mused = 0;
100: p->u.thru.owner = ibuf;
101: }
102:
103: void
104: thru_rt(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned c)
105: {
106: unsigned ocount;
107: unsigned char *odata;
108:
109: DPRINTFN(4, "thru_rt:\n");
110: if (!ABUF_WOK(obuf)) {
111: DPRINTFN(2, "thru_rt: discarded %u\n", obuf->used);
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:
121:
122: void
123: thru_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned todo)
124: {
125: unsigned char *idata;
126: unsigned c, icount, ioffs;
127:
128: idata = NULL;
129: icount = ioffs = 0;
130: for (;;) {
131: if (icount == 0) {
132: if (todo == 0)
133: break;
134: idata = abuf_rgetblk(ibuf, &icount, ioffs);
135: if (icount > todo)
136: icount = todo;
137: if (icount == 0)
138: break;
139: todo -= icount;
140: ioffs += icount;
141: }
142: c = *idata++;
143: icount--;
144: if (c < 0x80) {
145: if (ibuf->mindex == 0 && ibuf->mstatus) {
146: ibuf->mdata[ibuf->mused++] = ibuf->mstatus;
147: ibuf->mindex++;
148: }
149: ibuf->mdata[ibuf->mused++] = c;
150: ibuf->mindex++;
151: if (ibuf->mindex == ibuf->mlen) {
152: thru_flush(p, ibuf, obuf);
153: if (ibuf->mstatus >= 0xf0)
154: ibuf->mstatus = 0;
155: ibuf->mindex = 0;
156: }
157: if (ibuf->mused == MDATA_NMAX) {
158: if (ibuf->mused == ibuf->mindex ||
159: p->u.thru.owner == ibuf)
160: thru_flush(p, ibuf, obuf);
161: else
162: ibuf->mused = 0;
163: }
164: } else if (c < 0xf8) {
165: if (ibuf->mused == ibuf->mindex ||
166: p->u.thru.owner == ibuf) {
167: thru_flush(p, ibuf, obuf);
168: } else
169: ibuf->mused = 0;
170: ibuf->mdata[0] = c;
171: ibuf->mused = 1;
172: ibuf->mlen = (c >= 0xf0) ?
173: common_len[c & 7] :
174: voice_len[(c >> 4) & 7];
175: if (ibuf->mlen == 1) {
176: thru_flush(p, ibuf, obuf);
177: ibuf->mindex = 0;
178: ibuf->mstatus = 0;
179: ibuf->mlen = 0;
180: } else {
181: ibuf->mstatus = c;
182: ibuf->mindex = 1;
183: }
184: } else {
185: thru_rt(p, ibuf, obuf, c);
186: }
187: }
188: }
189:
190: int
191: thru_in(struct aproc *p, struct abuf *ibuf)
192: {
193: struct abuf *i, *inext;
194: unsigned todo;
195:
196: DPRINTFN(3, "thru_in: %s\n", p->name);
197:
198: if (!ABUF_ROK(ibuf))
199: return 0;
200: if (ibuf->mtickets == 0) {
201: DPRINTFN(2, "thru_in: out of tickets\n");
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: DPRINTF("thru_eof: %s: eof\n", p->name);
229: }
230:
231: void
232: thru_hup(struct aproc *p, struct abuf *obuf)
233: {
234: DPRINTF("thru_hup: %s: detached\n", p->name);
235: }
236:
237: void
238: thru_newin(struct aproc *p, struct abuf *ibuf)
239: {
240: ibuf->mused = 0;
241: ibuf->mlen = 0;
242: ibuf->mindex = 0;
243: ibuf->mstatus = 0;
244: ibuf->mtickets = MIDITHRU_XFER;
245: }
246:
247: void
248: thru_done(struct aproc *p)
249: {
250: timo_del(&p->u.thru.timo);
251: }
252:
253: struct aproc_ops thru_ops = {
254: "thru",
255: thru_in,
256: thru_out,
257: thru_eof,
258: thru_hup,
259: thru_newin,
260: NULL, /* newout */
261: NULL, /* ipos */
262: NULL, /* opos */
263: thru_done
264: };
265:
266: void
267: thru_cb(void *addr)
268: {
269: struct aproc *p = (struct aproc *)addr;
270: struct abuf *i, *inext;
271: unsigned tickets;
272:
273: timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
274:
275: for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
276: inext = LIST_NEXT(i, ient);
277: tickets = i->mtickets;
278: i->mtickets = MIDITHRU_XFER;
279: if (tickets == 0)
280: abuf_run(i);
281: }
282: }
283:
284: struct aproc *
285: thru_new(char *name)
286: {
287: struct aproc *p;
288:
289: p = aproc_new(&thru_ops, name);
290: p->u.thru.owner = NULL;
291: timo_set(&p->u.thru.timo, thru_cb, p);
292: timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
1.3 ratchov 293: return p;
294: }
295:
296: void
297: ctl_sendmsg(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len)
298: {
299: unsigned ocount, itodo;
300: unsigned char *odata, *idata;
301: struct abuf *i, *inext;
302:
303: for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
304: inext = LIST_NEXT(i, oent);
305: if (i->duplex == ibuf)
306: continue;
307: itodo = len;
308: idata = msg;
309: while (itodo > 0) {
310: if (!ABUF_WOK(i)) {
311: DPRINTFN(2, "ctl_sendmsg: lost %u\n", i->used);
312: abuf_rdiscard(i, i->used);
313: }
314: odata = abuf_wgetblk(i, &ocount, 0);
315: if (ocount > itodo)
316: ocount = itodo;
317: DPRINTFN(2, "ctl_sendmsg: xfer %u\n", ocount);
318: memcpy(odata, idata, ocount);
319: abuf_wcommit(i, ocount);
320: itodo -= ocount;
321: idata += ocount;
322: }
323: (void)abuf_flush(i);
324: }
325: }
326:
327: int
1.5 ratchov 328: ctl_slotnew(struct aproc *p, char *who, void (*cb)(void *, unsigned), void *arg)
1.3 ratchov 329: {
330: char *s;
331: struct ctl_slot *slot;
1.4 ratchov 332: char name[CTL_NAMEMAX];
333: unsigned i, unit, umap = 0;
1.6 ! ratchov 334: unsigned ser, bestser, bestidx;
1.3 ratchov 335:
1.4 ratchov 336: /*
337: * create a ``valid'' control name (lowcase, remove [^a-z], trucate)
338: */
1.5 ratchov 339: for (i = 0, s = who; ; s++) {
1.4 ratchov 340: if (i == CTL_NAMEMAX - 1 || *s == '\0') {
341: name[i] = '\0';
342: break;
343: } else if (*s >= 'A' && *s <= 'Z') {
344: name[i++] = *s + 'a' - 'A';
345: } else if (*s >= 'a' && *s <= 'z')
346: name[i++] = *s;
347: }
348: if (i == 0)
349: strlcpy(name, "noname", CTL_NAMEMAX);
350:
351: /*
352: * find the instance number of the control name
353: */
354: for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.5 ratchov 355: if (slot->cb == NULL)
1.4 ratchov 356: continue;
357: if (strcmp(slot->name, name) == 0)
358: umap |= (1 << i);
359: }
360: for (unit = 0; unit < CTL_NSLOT; unit++) {
361: if (unit == CTL_NSLOT)
1.3 ratchov 362: return -1;
1.4 ratchov 363: if ((umap & (1 << i)) == 0)
1.3 ratchov 364: break;
365: }
1.4 ratchov 366:
367: DPRINTF("ctl_newslot: using %s%u as control name\n", name, unit);
368:
369: /*
370: * find a free controller slot with the same name/unit
371: */
372: for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
1.5 ratchov 373: if (slot->cb == NULL &&
1.4 ratchov 374: strcmp(slot->name, name) == 0 &&
375: slot->unit == unit) {
1.5 ratchov 376: slot->cb = cb;
377: slot->arg = arg;
1.4 ratchov 378: DPRINTFN(1, "ctl_newslot: reusing %u\n", i);
379: return i;
380: }
381: }
382:
383: /*
1.6 ! ratchov 384: * couldn't find a matching slot, pick oldest free slot
1.4 ratchov 385: */
1.6 ! ratchov 386: bestser = 0;
! 387: bestidx = CTL_NSLOT;
! 388: for (i = 0, slot = p->u.ctl.slot; i < CTL_NSLOT; i++, slot++) {
! 389: if (slot->cb != NULL)
! 390: continue;
! 391: ser = p->u.ctl.serial - slot->serial;
! 392: if (ser > bestser) {
! 393: bestser = ser;
! 394: bestidx = i;
! 395: }
1.3 ratchov 396: }
1.6 ! ratchov 397: if (bestidx == CTL_NSLOT)
! 398: return -1;
! 399: slot = p->u.ctl.slot + bestidx;
1.4 ratchov 400: strlcpy(slot->name, name, CTL_NAMEMAX);
1.6 ! ratchov 401: slot->serial = p->u.ctl.serial++;
1.4 ratchov 402: slot->unit = unit;
1.5 ratchov 403: slot->cb = cb;
404: slot->arg = arg;
1.6 ! ratchov 405: DPRINTFN(1, "ctl_newslot: %u overwritten)\n", bestidx);
! 406: return bestidx;
1.3 ratchov 407: }
408:
409: void
410: ctl_slotdel(struct aproc *p, int index)
411: {
1.5 ratchov 412: p->u.ctl.slot[index].cb = NULL;
1.3 ratchov 413: }
414:
415: void
416: ctl_slotvol(struct aproc *p, int slot, unsigned vol)
417: {
418: unsigned char msg[3];
419:
420: DPRINTFN(1, "ctl_slotvol: [%u] -> %u\n", slot, vol);
421: msg[0] = MIDI_CTL | slot;
422: msg[1] = MIDI_CTLVOL;
423: msg[2] = vol;
424: ctl_sendmsg(p, NULL, msg, 3);
425: }
426:
427: void
428: ctl_ev(struct aproc *p, struct abuf *ibuf)
429: {
430: unsigned i;
431: unsigned chan;
1.5 ratchov 432: struct ctl_slot *slot;
1.3 ratchov 433:
434: #ifdef DEBUG
435: if (debug_level > 0) {
436: fprintf(stderr, "ctl_ev:");
437: for (i = 0; i < ibuf->mlen; i++)
438: fprintf(stderr, " %02x", ibuf->mdata[i]);
439: fprintf(stderr, "\n");
440: }
441: #endif
442: if ((ibuf->mdata[0] & MIDI_CMDMASK) == MIDI_CTL &&
443: ibuf->mdata[1] == MIDI_CTLVOL) {
444: chan = ibuf->mdata[0] & MIDI_CHANMASK;
445: if (chan >= CTL_NSLOT)
446: return;
1.5 ratchov 447: slot = p->u.ctl.slot + chan;
448: if (slot->cb == NULL)
1.3 ratchov 449: return;
1.5 ratchov 450: slot->cb(slot->arg, ibuf->mdata[2]);
1.3 ratchov 451: ctl_sendmsg(p, ibuf, ibuf->mdata, ibuf->mlen);
452: }
453: }
454:
455: int
456: ctl_in(struct aproc *p, struct abuf *ibuf)
457: {
458: unsigned char *idata;
459: unsigned c, i, icount;
460:
461: if (!ABUF_ROK(ibuf))
462: return 0;
463: idata = abuf_rgetblk(ibuf, &icount, 0);
464: for (i = 0; i < icount; i++) {
465: c = *idata++;
466: if (c >= 0xf0) {
467: /* clock and common events not used yet */
468: } else if (c >= 0x80) {
469: ibuf->mdata[0] = c;
470: ibuf->mlen = voice_len[(c >> 4) & 7];
471: ibuf->mstatus = c;
472: ibuf->mindex = 1;
473: } else if (ibuf->mstatus) {
474: if (ibuf->mindex == 0)
475: ibuf->mdata[ibuf->mindex++] = ibuf->mstatus;
476: ibuf->mdata[ibuf->mindex++] = c;
477: if (ibuf->mindex == ibuf->mlen) {
478: ctl_ev(p, ibuf);
479: ibuf->mindex = 0;
480: }
481: }
482: }
483: abuf_rdiscard(ibuf, icount);
484: return 1;
485: }
486:
487: int
488: ctl_out(struct aproc *p, struct abuf *obuf)
489: {
490: return 0;
491: }
492:
493: void
494: ctl_eof(struct aproc *p, struct abuf *ibuf)
495: {
496: DPRINTF("ctl_eof: %s: eof\n", p->name);
497: }
498:
499: void
500: ctl_hup(struct aproc *p, struct abuf *obuf)
501: {
502: DPRINTF("ctl_hup: %s: detached\n", p->name);
503: }
504:
505: void
506: ctl_newin(struct aproc *p, struct abuf *ibuf)
507: {
508: ibuf->mused = 0;
509: ibuf->mlen = 0;
510: ibuf->mindex = 0;
511: ibuf->mstatus = 0;
512: }
513:
514: void
515: ctl_done(struct aproc *p)
516: {
517: unsigned i;
518: struct ctl_slot *s;
519:
520: for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
1.5 ratchov 521: if (s->cb != NULL)
1.6 ! ratchov 522: DPRINTF("ctl_done: %s%u in use\n", s->name, s->unit);
1.3 ratchov 523: }
524: }
525:
526: struct aproc_ops ctl_ops = {
527: "ctl",
528: ctl_in,
529: ctl_out,
530: ctl_eof,
531: ctl_hup,
532: ctl_newin,
533: NULL, /* newout */
534: NULL, /* ipos */
535: NULL, /* opos */
536: ctl_done
537: };
538:
539: struct aproc *
540: ctl_new(char *name)
541: {
542: struct aproc *p;
1.5 ratchov 543: struct ctl_slot *s;
1.3 ratchov 544: unsigned i;
545:
546: p = aproc_new(&ctl_ops, name);
1.6 ! ratchov 547: p->u.ctl.serial = 0;
1.5 ratchov 548: for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
1.3 ratchov 549: p->u.ctl.slot[i].unit = i;
1.5 ratchov 550: p->u.ctl.slot[i].cb = NULL;
1.6 ! ratchov 551: p->u.ctl.slot[i].serial = p->u.ctl.serial++;
1.3 ratchov 552: strlcpy(p->u.ctl.slot[i].name, "unknown", CTL_NAMEMAX);
553: }
1.1 ratchov 554: return p;
555: }
556: