Annotation of src/usr.bin/aucat/midi.c, Revision 1.2
1.2 ! ratchov 1: /* $OpenBSD: midi.c,v 1.1 2009/07/25 08:44:27 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 "conf.h"
33: #include "abuf.h"
34: #include "aproc.h"
35: #include "midi.h"
36:
37: /*
38: * input data rate is XFER / TIMO (in bytes per microsecond),
39: * it must be slightly larger than the MIDI standard 3125 bytes/s
40: */
41: #define MIDITHRU_XFER 340
42: #define MIDITHRU_TIMO 100000
43:
44: unsigned voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
45: unsigned common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
46:
47: void
48: thru_flush(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
49: {
50: unsigned ocount, itodo;
51: unsigned char *odata, *idata;
52:
53: itodo = ibuf->mused;
54: idata = ibuf->mdata;
55: DPRINTFN(4, "thru_flush: mused = %u\n", itodo);
56: while (itodo > 0) {
57: if (!ABUF_WOK(obuf)) {
58: abuf_rdiscard(obuf, obuf->used);
59: DPRINTFN(2, "thru_flush: discarded %u\n", obuf->used);
60: if (p->u.thru.owner == ibuf)
61: p->u.thru.owner = NULL;
62: return;
63: }
64: odata = abuf_wgetblk(obuf, &ocount, 0);
65: if (ocount > itodo)
66: ocount = itodo;
67: memcpy(odata, idata, ocount);
68: abuf_wcommit(obuf, ocount);
69: itodo -= ocount;
70: idata += ocount;
71: }
72: ibuf->mused = 0;
73: p->u.thru.owner = ibuf;
74: }
75:
76: void
77: thru_rt(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned c)
78: {
79: unsigned ocount;
80: unsigned char *odata;
81:
82: DPRINTFN(4, "thru_rt:\n");
83: if (!ABUF_WOK(obuf)) {
84: DPRINTFN(2, "thru_rt: discarded %u\n", obuf->used);
85: abuf_rdiscard(obuf, obuf->used);
86: if (p->u.thru.owner == ibuf)
87: p->u.thru.owner = NULL;
88: }
89: odata = abuf_wgetblk(obuf, &ocount, 0);
90: odata[0] = c;
91: abuf_wcommit(obuf, 1);
92: }
93:
94:
95: void
96: thru_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned todo)
97: {
98: unsigned char *idata;
99: unsigned c, icount, ioffs;
100:
101: idata = NULL;
102: icount = ioffs = 0;
103: for (;;) {
104: if (icount == 0) {
105: if (todo == 0)
106: break;
107: idata = abuf_rgetblk(ibuf, &icount, ioffs);
108: if (icount > todo)
109: icount = todo;
110: if (icount == 0)
111: break;
112: todo -= icount;
113: ioffs += icount;
114: }
115: c = *idata++;
116: icount--;
117: if (c < 0x80) {
118: if (ibuf->mindex == 0 && ibuf->mstatus) {
119: ibuf->mdata[ibuf->mused++] = ibuf->mstatus;
120: ibuf->mindex++;
121: }
122: ibuf->mdata[ibuf->mused++] = c;
123: ibuf->mindex++;
124: if (ibuf->mindex == ibuf->mlen) {
125: thru_flush(p, ibuf, obuf);
126: if (ibuf->mstatus >= 0xf0)
127: ibuf->mstatus = 0;
128: ibuf->mindex = 0;
129: }
130: if (ibuf->mused == MDATA_NMAX) {
131: if (ibuf->mused == ibuf->mindex ||
132: p->u.thru.owner == ibuf)
133: thru_flush(p, ibuf, obuf);
134: else
135: ibuf->mused = 0;
136: }
137: } else if (c < 0xf8) {
138: if (ibuf->mused == ibuf->mindex ||
139: p->u.thru.owner == ibuf) {
140: thru_flush(p, ibuf, obuf);
141: } else
142: ibuf->mused = 0;
143: ibuf->mdata[0] = c;
144: ibuf->mused = 1;
145: ibuf->mlen = (c >= 0xf0) ?
146: common_len[c & 7] :
147: voice_len[(c >> 4) & 7];
148: if (ibuf->mlen == 1) {
149: thru_flush(p, ibuf, obuf);
150: ibuf->mindex = 0;
151: ibuf->mstatus = 0;
152: ibuf->mlen = 0;
153: } else {
154: ibuf->mstatus = c;
155: ibuf->mindex = 1;
156: }
157: } else {
158: thru_rt(p, ibuf, obuf, c);
159: }
160: }
161: }
162:
163: int
164: thru_in(struct aproc *p, struct abuf *ibuf)
165: {
166: struct abuf *i, *inext;
167: unsigned todo;
168:
169: DPRINTFN(3, "thru_in: %s\n", p->name);
170:
171: if (!ABUF_ROK(ibuf))
172: return 0;
173: if (ibuf->mtickets == 0) {
174: DPRINTFN(2, "thru_in: out of tickets\n");
175: return 0;
176: }
177: todo = ibuf->used;
178: if (todo > ibuf->mtickets)
179: todo = ibuf->mtickets;
180: ibuf->mtickets -= todo;
181: for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
182: inext = LIST_NEXT(i, oent);
183: if (ibuf->duplex == i)
184: continue;
185: thru_bcopy(p, ibuf, i, todo);
186: (void)abuf_flush(i);
187: }
188: abuf_rdiscard(ibuf, todo);
189: return 1;
190: }
191:
192: int
193: thru_out(struct aproc *p, struct abuf *obuf)
194: {
195: return 0;
196: }
197:
198: void
199: thru_eof(struct aproc *p, struct abuf *ibuf)
200: {
201: DPRINTF("thru_eof: %s: eof\n", p->name);
202: }
203:
204: void
205: thru_hup(struct aproc *p, struct abuf *obuf)
206: {
207: DPRINTF("thru_hup: %s: detached\n", p->name);
208: }
209:
210: void
211: thru_newin(struct aproc *p, struct abuf *ibuf)
212: {
213: ibuf->mused = 0;
214: ibuf->mlen = 0;
215: ibuf->mindex = 0;
216: ibuf->mstatus = 0;
217: ibuf->mtickets = MIDITHRU_XFER;
218: }
219:
220: void
221: thru_done(struct aproc *p)
222: {
223: timo_del(&p->u.thru.timo);
224: }
225:
226: struct aproc_ops thru_ops = {
227: "thru",
228: thru_in,
229: thru_out,
230: thru_eof,
231: thru_hup,
232: thru_newin,
233: NULL, /* newout */
234: NULL, /* ipos */
235: NULL, /* opos */
236: thru_done
237: };
238:
239: void
240: thru_cb(void *addr)
241: {
242: struct aproc *p = (struct aproc *)addr;
243: struct abuf *i, *inext;
244: unsigned tickets;
245:
246: timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
247:
248: for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
249: inext = LIST_NEXT(i, ient);
250: tickets = i->mtickets;
251: i->mtickets = MIDITHRU_XFER;
252: if (tickets == 0)
253: abuf_run(i);
254: }
255: }
256:
257: struct aproc *
258: thru_new(char *name)
259: {
260: struct aproc *p;
261:
262: p = aproc_new(&thru_ops, name);
263: p->u.thru.owner = NULL;
264: timo_set(&p->u.thru.timo, thru_cb, p);
265: timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
266: return p;
267: }
268: