midisyn.c revision 1.2
1/* $NetBSD: midisyn.c,v 1.2 1998/08/13 00:13:56 augustss Exp $ */ 2 3/* 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Author: Lennart Augustsson 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the NetBSD 20 * Foundation, Inc. and its contributors. 21 * 4. Neither the name of The NetBSD Foundation nor the names of its 22 * contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38#include <sys/param.h> 39#include <sys/ioctl.h> 40#include <sys/fcntl.h> 41#include <sys/vnode.h> 42#include <sys/select.h> 43#include <sys/proc.h> 44#include <sys/malloc.h> 45#include <sys/systm.h> 46#include <sys/syslog.h> 47#include <sys/kernel.h> 48#include <sys/conf.h> 49#include <sys/audioio.h> 50#include <sys/midiio.h> 51#include <sys/device.h> 52 53#include <dev/audio_if.h> 54#include <dev/midivar.h> 55#include <dev/midisynvar.h> 56 57#ifdef AUDIO_DEBUG 58#define DPRINTF(x) if (midisyndebug) printf x 59#define DPRINTFN(n,x) if (midisyndebug >= (n)) printf x 60int midisyndebug = 0; 61#else 62#define DPRINTF(x) 63#define DPRINTFN(n,x) 64#endif 65 66int midisyn_findvoice __P((midisyn *, int, int)); 67void midisyn_freevoice __P((midisyn *, int)); 68int midisyn_allocvoice __P((midisyn *, u_int32_t, u_int32_t)); 69u_int32_t midisyn_note_to_freq __P((int)); 70 71int midisyn_open __P((void *, int, 72 void (*iintr)__P((void *, int)), 73 void (*ointr)__P((void *)), void *arg)); 74void midisyn_close __P((void *)); 75int midisyn_output __P((void *, int)); 76void midisyn_getinfo __P((void *, struct midi_info *)); 77int midisyn_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); 78 79struct midi_hw_if midisyn_hw_if = { 80 midisyn_open, 81 midisyn_close, 82 midisyn_output, 83 midisyn_getinfo, 84 midisyn_ioctl, 85}; 86 87static int midi_lengths[] = { 3,3,3,3,2,2,3,1 }; 88/* Number of bytes in a MIDI command, including status */ 89#define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7]) 90 91int 92midisyn_open(addr, flags, iintr, ointr, arg) 93 void *addr; 94 int flags; 95 void (*iintr)__P((void *, int)); 96 void (*ointr)__P((void *)); 97 void *arg; 98{ 99 midisyn *ms = addr; 100 101 DPRINTF(("midisyn_open: ms=%p ms->mets=%p\n", ms, ms->mets)); 102 if (ms->mets->open) 103 return (ms->mets->open(ms, flags)); 104 else 105 return (0); 106} 107 108void 109midisyn_close(addr) 110 void *addr; 111{ 112 midisyn *ms = addr; 113 114 DPRINTF(("midisyn_close: ms=%p ms->mets=%p\n", ms, ms->mets)); 115 if (ms->mets->close) 116 ms->mets->close(ms); 117} 118 119void 120midisyn_getinfo(addr, mi) 121 void *addr; 122 struct midi_info *mi; 123{ 124 midisyn *ms = addr; 125 126 mi->name = ms->name; 127 mi->props = 0; 128} 129 130int 131midisyn_ioctl(maddr, cmd, addr, flag, p) 132 void *maddr; 133 u_long cmd; 134 caddr_t addr; 135 int flag; 136 struct proc *p; 137{ 138 midisyn *ms = maddr; 139 140 if (ms->mets->ioctl) 141 return (ms->mets->ioctl(ms, cmd, addr, flag, p)); 142 else 143 return (EINVAL); 144} 145 146int 147midisyn_findvoice(ms, chan, note) 148 midisyn *ms; 149 int chan, note; 150{ 151 u_int cn; 152 int v; 153 154 if (!(ms->flags & MS_DOALLOC)) 155 return (chan); 156 cn = CHANNOTE(chan, note); 157 for (v = 0; v < ms->nvoice; v++) 158 if (ms->voices[v].chan_note == cn) 159 return (v); 160 return (-1); 161} 162 163void 164midisyn_attach(sc, ms, parent) 165 struct midi_softc *sc; 166 midisyn *ms; 167 struct device *parent; 168{ 169 if (ms->flags & MS_DOALLOC) { 170 ms->voices = malloc(ms->nvoice * sizeof (struct voice), 171 M_DEVBUF, M_WAITOK); 172 memset(ms->voices, 0, ms->nvoice * sizeof (struct voice)); 173 ms->seqno = 1; 174 if (ms->mets->allocv == 0) 175 ms->mets->allocv = &midisyn_allocvoice; 176 } 177 sc->hw_if = &midisyn_hw_if; 178 sc->hw_hdl = ms; 179 DPRINTF(("midisyn_attach: ms=%p\n", sc->hw_hdl)); 180 midi_attach(sc, parent); 181} 182 183void 184midisyn_freevoice(ms, voice) 185 midisyn *ms; 186 int voice; 187{ 188 if (!(ms->flags & MS_DOALLOC)) 189 return; 190 ms->voices[voice].chan_note = ~0; 191} 192 193int 194midisyn_allocvoice(ms, chan, note) 195 midisyn *ms; 196 u_int32_t chan, note; 197{ 198 int bestv, v; 199 u_int bestseq, s; 200 201 if (!(ms->flags & MS_DOALLOC)) 202 return (chan); 203 /* Find a free voice, or if no free voice is found the oldest. */ 204 bestv = 0; 205 bestseq = ms->voices[0].seqno; 206 for (v = 1; v < ms->nvoice; v++) { 207 s = ms->voices[v].seqno; 208 if (s < bestseq) { 209 bestseq = s; 210 bestv = v; 211 } 212 } 213 ms->voices[bestv].chan_note = CHANNOTE(chan, note); 214 ms->voices[bestv].seqno = ms->seqno++; 215 return (bestv); 216} 217 218int 219midisyn_output(addr, b) 220 void *addr; 221 int b; 222{ 223 midisyn *ms = addr; 224 u_int8_t status, chan; 225 int voice = 0; /* initialize to keep gcc quiet */ 226 struct midisyn_methods *fs; 227 u_int32_t note, vel; 228 229 DPRINTF(("midisyn_output: ms=%p b=0x%02x\n", ms, b)); 230 fs = ms->mets; 231 if (ms->pos < 0) { 232 /* Doing SYSEX */ 233 DPRINTF(("midisyn_output: sysex 0x%02x\n", b)); 234 if (fs->sysex) 235 fs->sysex(ms, b); 236 if (b == MIDI_SYSEX_END) 237 ms->pos = 0; 238 return (0); 239 } 240 if (ms->pos == 0 && !MIDI_IS_STATUS(b)) 241 ms->pos++; /* repeat last status byte */ 242 ms->buf[ms->pos++] = b; 243 status = ms->buf[0]; 244 if (ms->pos < MIDI_LENGTH(status)) 245 return (0); 246 /* Decode the MIDI command */ 247 chan = MIDI_GET_CHAN(status); 248 note = ms->buf[1]; 249 if (ms->flags & MS_FREQXLATE) 250 note = midisyn_note_to_freq(note); 251 vel = ms->buf[2]; 252 switch (MIDI_GET_STATUS(status)) { 253 case MIDI_NOTEOFF: 254 voice = midisyn_findvoice(ms, chan, ms->buf[1]); 255 if (voice >= 0) { 256 fs->noteoff(ms, voice, note, vel); 257 midisyn_freevoice(ms, voice); 258 } 259 break; 260 case MIDI_NOTEON: 261 voice = fs->allocv(ms, chan, ms->buf[1]); 262 fs->noteon(ms, voice, note, vel); 263 break; 264 case MIDI_KEY_PRESSURE: 265 if (fs->keypres) { 266 voice = midisyn_findvoice(ms, voice, ms->buf[1]); 267 if (voice >= 0) 268 fs->keypres(ms, voice, note, vel); 269 } 270 break; 271 case MIDI_CTL_CHANGE: 272 if (fs->ctlchg) 273 fs->ctlchg(ms, chan, ms->buf[1], vel); 274 break; 275 case MIDI_PGM_CHANGE: 276 if (fs->pgmchg) 277 fs->pgmchg(ms, chan, ms->buf[1]); 278 break; 279 case MIDI_CHN_PRESSURE: 280 if (fs->chnpres) { 281 voice = midisyn_findvoice(ms, chan, ms->buf[1]); 282 if (voice >= 0) 283 fs->chnpres(ms, voice, note); 284 } 285 break; 286 case MIDI_PITCH_BEND: 287 if (fs->pitchb) { 288 voice = midisyn_findvoice(ms, chan, ms->buf[1]); 289 if (voice >= 0) 290 fs->pitchb(ms, chan, note, vel); 291 } 292 break; 293 case MIDI_SYSTEM_PREFIX: 294 if (fs->sysex) 295 fs->sysex(ms, status); 296 ms->pos = -1; 297 return (0); 298 } 299 ms->pos = 0; 300 return (0); 301} 302 303/* 304 * Convert a MIDI note to the corresponding frequency. 305 * The frequency is scaled by 2^16. 306 */ 307u_int32_t 308midisyn_note_to_freq(note) 309 int note; 310{ 311 int o, n, f; 312#define BASE_OCTAVE 5 313 static u_int32_t notes[] = { 314 17145893, 18165441, 19245614, 20390018, 21602472, 22887021, 315 24247954, 25689813, 27217409, 28835840, 30550508, 32367136 316 }; 317 318 319 o = note / 12; 320 n = note % 12; 321 322 f = notes[n]; 323 324 if (o < BASE_OCTAVE) 325 f >>= (BASE_OCTAVE - o); 326 else if (o > BASE_OCTAVE) 327 f <<= (o - BASE_OCTAVE); 328 return (f); 329} 330 331