Annotation of sys/dev/midisyn.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: midisyn.c,v 1.6 2006/04/07 22:41:32 jsg Exp $ */
2: /* $NetBSD: midisyn.c,v 1.5 1998/11/25 22:17:07 augustss Exp $ */
3:
4: /*
5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Lennart Augustsson (augustss@netbsd.org).
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: #include <sys/param.h>
41: #include <sys/ioctl.h>
42: #include <sys/fcntl.h>
43: #include <sys/vnode.h>
44: #include <sys/selinfo.h>
45: #include <sys/proc.h>
46: #include <sys/malloc.h>
47: #include <sys/systm.h>
48: #include <sys/syslog.h>
49: #include <sys/kernel.h>
50: #include <sys/conf.h>
51: #include <sys/audioio.h>
52: #include <sys/midiio.h>
53: #include <sys/device.h>
54:
55: #include <dev/audio_if.h>
56: #include <dev/midi_if.h>
57: #include <dev/midivar.h>
58: #include <dev/midisynvar.h>
59:
60: #ifdef AUDIO_DEBUG
61: #define DPRINTF(x) if (midisyndebug) printf x
62: #define DPRINTFN(n,x) if (midisyndebug >= (n)) printf x
63: int midisyndebug = 0;
64: #else
65: #define DPRINTF(x)
66: #define DPRINTFN(n,x)
67: #endif
68:
69: int midisyn_findvoice(midisyn *, int, int);
70: void midisyn_freevoice(midisyn *, int);
71: int midisyn_allocvoice(midisyn *, u_int32_t, u_int32_t);
72: u_int32_t midisyn_note_to_freq(int);
73: u_int32_t midisyn_finetune(u_int32_t, int, int, int);
74:
75: int midisyn_open(void *, int,
76: void (*iintr)(void *, int),
77: void (*ointr)(void *), void *arg);
78: void midisyn_close(void *);
79: int midisyn_output(void *, int);
80: void midisyn_getinfo(void *, struct midi_info *);
81: int midisyn_ioctl(void *, u_long, caddr_t, int, struct proc *);
82:
83: struct midi_hw_if midisyn_hw_if = {
84: midisyn_open,
85: midisyn_close,
86: midisyn_output,
87: NULL, /* flush */
88: midisyn_getinfo,
89: midisyn_ioctl,
90: };
91:
92: static int midi_lengths[] = { 3,3,3,3,2,2,3,1 };
93: /* Number of bytes in a MIDI command, including status */
94: #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
95:
96: int
97: midisyn_open(addr, flags, iintr, ointr, arg)
98: void *addr;
99: int flags;
100: void (*iintr)(void *, int);
101: void (*ointr)(void *);
102: void *arg;
103: {
104: midisyn *ms = addr;
105:
106: DPRINTF(("midisyn_open: ms=%p ms->mets=%p\n", ms, ms->mets));
107: if (ms->mets->open)
108: return (ms->mets->open(ms, flags));
109: else
110: return (0);
111: }
112:
113: void
114: midisyn_close(addr)
115: void *addr;
116: {
117: midisyn *ms = addr;
118: struct midisyn_methods *fs;
119: int v;
120:
121: DPRINTF(("midisyn_close: ms=%p ms->mets=%p\n", ms, ms->mets));
122: fs = ms->mets;
123: for (v = 0; v < ms->nvoice; v++)
124: if (ms->voices[v].inuse) {
125: fs->noteoff(ms, v, 0, 0);
126: midisyn_freevoice(ms, v);
127: }
128: if (fs->close)
129: fs->close(ms);
130: }
131:
132: void
133: midisyn_getinfo(addr, mi)
134: void *addr;
135: struct midi_info *mi;
136: {
137: midisyn *ms = addr;
138:
139: mi->name = ms->name;
140: mi->props = 0;
141: }
142:
143: int
144: midisyn_ioctl(maddr, cmd, addr, flag, p)
145: void *maddr;
146: u_long cmd;
147: caddr_t addr;
148: int flag;
149: struct proc *p;
150: {
151: midisyn *ms = maddr;
152:
153: if (ms->mets->ioctl)
154: return (ms->mets->ioctl(ms, cmd, addr, flag, p));
155: else
156: return (EINVAL);
157: }
158:
159: int
160: midisyn_findvoice(ms, chan, note)
161: midisyn *ms;
162: int chan, note;
163: {
164: u_int cn;
165: int v;
166:
167: if (!(ms->flags & MS_DOALLOC))
168: return (chan);
169: cn = MS_CHANNOTE(chan, note);
170: for (v = 0; v < ms->nvoice; v++)
171: if (ms->voices[v].chan_note == cn && ms->voices[v].inuse)
172: return (v);
173: return (-1);
174: }
175:
176: void
177: midisyn_attach(sc, ms)
178: struct midi_softc *sc;
179: midisyn *ms;
180: {
181: if (ms->flags & MS_DOALLOC) {
182: ms->voices = malloc(ms->nvoice * sizeof (struct voice),
183: M_DEVBUF, M_WAITOK);
184: memset(ms->voices, 0, ms->nvoice * sizeof (struct voice));
185: ms->seqno = 1;
186: if (ms->mets->allocv == 0)
187: ms->mets->allocv = &midisyn_allocvoice;
188: }
189: sc->hw_if = &midisyn_hw_if;
190: sc->hw_hdl = ms;
191: DPRINTF(("midisyn_attach: ms=%p\n", sc->hw_hdl));
192: }
193:
194: void
195: midisyn_freevoice(ms, voice)
196: midisyn *ms;
197: int voice;
198: {
199: if (!(ms->flags & MS_DOALLOC))
200: return;
201: ms->voices[voice].inuse = 0;
202: }
203:
204: int
205: midisyn_allocvoice(ms, chan, note)
206: midisyn *ms;
207: u_int32_t chan, note;
208: {
209: int bestv, v;
210: u_int bestseq, s;
211:
212: if (!(ms->flags & MS_DOALLOC))
213: return (chan);
214: /* Find a free voice, or if no free voice is found the oldest. */
215: bestv = 0;
216: bestseq = ms->voices[0].seqno + (ms->voices[0].inuse ? 0x40000000 : 0);
217: for (v = 1; v < ms->nvoice; v++) {
218: s = ms->voices[v].seqno;
219: if (ms->voices[v].inuse)
220: s += 0x40000000;
221: if (s < bestseq) {
222: bestseq = s;
223: bestv = v;
224: }
225: }
226: DPRINTFN(10,("midisyn_allocvoice: v=%d seq=%d cn=%x inuse=%d\n",
227: bestv, ms->voices[bestv].seqno,
228: ms->voices[bestv].chan_note,
229: ms->voices[bestv].inuse));
230: #ifdef AUDIO_DEBUG
231: if (ms->voices[bestv].inuse)
232: DPRINTFN(1,("midisyn_allocvoice: steal %x\n",
233: ms->voices[bestv].chan_note));
234: #endif
235: ms->voices[bestv].chan_note = MS_CHANNOTE(chan, note);
236: ms->voices[bestv].seqno = ms->seqno++;
237: ms->voices[bestv].inuse = 1;
238: return (bestv);
239: }
240:
241: int
242: midisyn_output(addr, b)
243: void *addr;
244: int b;
245: {
246: midisyn *ms = addr;
247: u_int8_t status, chan;
248: int voice = 0; /* initialize to keep gcc quiet */
249: struct midisyn_methods *fs;
250: u_int32_t note, vel;
251:
252: DPRINTF(("midisyn_output: ms=%p b=0x%02x\n", ms, b));
253: fs = ms->mets;
254: if (ms->pos < 0) {
255: /* Doing SYSEX */
256: DPRINTF(("midisyn_output: sysex 0x%02x\n", b));
257: if (fs->sysex)
258: fs->sysex(ms, b);
259: if (b == MIDI_SYSEX_END)
260: ms->pos = 0;
261: return (0);
262: }
263: if (ms->pos == 0 && !MIDI_IS_STATUS(b))
264: ms->pos++; /* repeat last status byte */
265: ms->buf[ms->pos++] = b;
266: status = ms->buf[0];
267: if (ms->pos < MIDI_LENGTH(status))
268: return (0);
269: /* Decode the MIDI command */
270: chan = MIDI_GET_CHAN(status);
271: note = ms->buf[1];
272: if (ms->flags & MS_FREQXLATE)
273: note = midisyn_note_to_freq(note);
274: vel = ms->buf[2];
275: switch (MIDI_GET_STATUS(status)) {
276: case MIDI_NOTEOFF:
277: voice = midisyn_findvoice(ms, chan, ms->buf[1]);
278: if (voice >= 0) {
279: fs->noteoff(ms, voice, note, vel);
280: midisyn_freevoice(ms, voice);
281: }
282: break;
283: case MIDI_NOTEON:
284: voice = fs->allocv(ms, chan, ms->buf[1]);
285: fs->noteon(ms, voice, note, vel);
286: break;
287: case MIDI_KEY_PRESSURE:
288: if (fs->keypres) {
289: voice = midisyn_findvoice(ms, voice, ms->buf[1]);
290: if (voice >= 0)
291: fs->keypres(ms, voice, note, vel);
292: }
293: break;
294: case MIDI_CTL_CHANGE:
295: if (fs->ctlchg)
296: fs->ctlchg(ms, chan, ms->buf[1], vel);
297: break;
298: case MIDI_PGM_CHANGE:
299: if (fs->pgmchg)
300: fs->pgmchg(ms, chan, ms->buf[1]);
301: break;
302: case MIDI_CHN_PRESSURE:
303: if (fs->chnpres) {
304: voice = midisyn_findvoice(ms, chan, ms->buf[1]);
305: if (voice >= 0)
306: fs->chnpres(ms, voice, note);
307: }
308: break;
309: case MIDI_PITCH_BEND:
310: if (fs->pitchb) {
311: voice = midisyn_findvoice(ms, chan, ms->buf[1]);
312: if (voice >= 0)
313: fs->pitchb(ms, chan, note, vel);
314: }
315: break;
316: case MIDI_SYSTEM_PREFIX:
317: if (fs->sysex)
318: fs->sysex(ms, status);
319: ms->pos = -1;
320: return (0);
321: }
322: ms->pos = 0;
323: return (0);
324: }
325:
326: /*
327: * Convert a MIDI note to the corresponding frequency.
328: * The frequency is scaled by 2^16.
329: */
330: u_int32_t
331: midisyn_note_to_freq(note)
332: int note;
333: {
334: int o, n, f;
335: #define BASE_OCTAVE 5
336: static u_int32_t notes[] = {
337: 17145893, 18165441, 19245614, 20390018, 21602472, 22887021,
338: 24247954, 25689813, 27217409, 28835840, 30550508, 32367136
339: };
340:
341:
342: o = note / 12;
343: n = note % 12;
344:
345: f = notes[n];
346:
347: if (o < BASE_OCTAVE)
348: f >>= (BASE_OCTAVE - o);
349: else if (o > BASE_OCTAVE)
350: f <<= (o - BASE_OCTAVE);
351: return (f);
352: }
353:
354: u_int32_t
355: midisyn_finetune(base_freq, bend, range, vibrato_cents)
356: u_int32_t base_freq;
357: int bend;
358: int range;
359: int vibrato_cents;
360: {
361: static u_int16_t semitone_tuning[24] =
362: {
363: /* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983,
364: /* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784,
365: /* 16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755
366: };
367: static u_int16_t cent_tuning[100] =
368: {
369: /* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041,
370: /* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087,
371: /* 16 */ 10093, 10099, 10105, 10110, 10116, 10122, 10128, 10134,
372: /* 24 */ 10140, 10145, 10151, 10157, 10163, 10169, 10175, 10181,
373: /* 32 */ 10187, 10192, 10198, 10204, 10210, 10216, 10222, 10228,
374: /* 40 */ 10234, 10240, 10246, 10251, 10257, 10263, 10269, 10275,
375: /* 48 */ 10281, 10287, 10293, 10299, 10305, 10311, 10317, 10323,
376: /* 56 */ 10329, 10335, 10341, 10347, 10353, 10359, 10365, 10371,
377: /* 64 */ 10377, 10383, 10389, 10395, 10401, 10407, 10413, 10419,
378: /* 72 */ 10425, 10431, 10437, 10443, 10449, 10455, 10461, 10467,
379: /* 80 */ 10473, 10479, 10485, 10491, 10497, 10503, 10509, 10515,
380: /* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564,
381: /* 96 */ 10570, 10576, 10582, 10589
382: };
383: u_int32_t amount;
384: int negative, semitones, cents, multiplier;
385:
386: if (range == 0)
387: return base_freq;
388:
389: if (base_freq == 0)
390: return base_freq;
391:
392: if (range >= 8192)
393: range = 8192;
394:
395: bend = bend * range / 8192;
396: bend += vibrato_cents;
397:
398: if (bend == 0)
399: return base_freq;
400:
401: if (bend < 0) {
402: bend = -bend;
403: negative = 1;
404: } else
405: negative = 0;
406:
407: if (bend > range)
408: bend = range;
409:
410: multiplier = 1;
411: while (bend > 2399) {
412: multiplier *= 4;
413: bend -= 2400;
414: }
415:
416: semitones = bend / 100;
417: if (semitones > 23)
418: semitones = 23;
419: cents = bend % 100;
420:
421: amount = semitone_tuning[semitones] * multiplier * cent_tuning[cents]
422: / 10000;
423:
424: if (negative)
425: return (base_freq * 10000 / amount); /* Bend down */
426: else
427: return (base_freq * amount / 10000); /* Bend up */
428: }
429:
CVSweb