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