1 /* $NetBSD: opl.c,v 1.21 2004/04/22 00:17:11 itojun 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 /* 40 * The OPL3 (YMF262) manual can be found at 41 * ftp://ftp.yamahayst.com/Fax_Back_Doc/sound/YMF262.PDF 42 */ 43 44 #include <sys/cdefs.h> 45 __KERNEL_RCSID(0, "$NetBSD: opl.c,v 1.21 2004/04/22 00:17:11 itojun Exp $"); 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/errno.h> 50 #include <sys/ioctl.h> 51 #include <sys/syslog.h> 52 #include <sys/device.h> 53 #include <sys/select.h> 54 55 #include <machine/cpu.h> 56 #include <machine/bus.h> 57 58 #include <sys/audioio.h> 59 #include <sys/midiio.h> 60 #include <dev/audio_if.h> 61 62 #include <dev/midi_if.h> 63 #include <dev/midivar.h> 64 #include <dev/midisynvar.h> 65 66 #include <dev/ic/oplreg.h> 67 #include <dev/ic/oplvar.h> 68 69 #ifdef AUDIO_DEBUG 70 #define DPRINTF(x) if (opldebug) printf x 71 #define DPRINTFN(n,x) if (opldebug >= (n)) printf x 72 int opldebug = 0; 73 #else 74 #define DPRINTF(x) 75 #define DPRINTFN(n,x) 76 #endif 77 78 struct real_voice { 79 u_int8_t voice_num; 80 u_int8_t voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */ 81 u_int8_t iooffs; /* I/O port (left or right side) */ 82 u_int8_t op[4]; /* Operator offsets */ 83 }; 84 85 const struct opl_voice voicetab[] = { 86 /* No I/O offs OP1 OP2 OP3 OP4 */ 87 /* --------------------------------------------- */ 88 { 0, OPL_L, {0x00, 0x03, 0x08, 0x0b}}, 89 { 1, OPL_L, {0x01, 0x04, 0x09, 0x0c}}, 90 { 2, OPL_L, {0x02, 0x05, 0x0a, 0x0d}}, 91 92 { 3, OPL_L, {0x08, 0x0b, 0x00, 0x00}}, 93 { 4, OPL_L, {0x09, 0x0c, 0x00, 0x00}}, 94 { 5, OPL_L, {0x0a, 0x0d, 0x00, 0x00}}, 95 96 { 6, OPL_L, {0x10, 0x13, 0x00, 0x00}}, 97 { 7, OPL_L, {0x11, 0x14, 0x00, 0x00}}, 98 { 8, OPL_L, {0x12, 0x15, 0x00, 0x00}}, 99 100 { 0, OPL_R, {0x00, 0x03, 0x08, 0x0b}}, 101 { 1, OPL_R, {0x01, 0x04, 0x09, 0x0c}}, 102 { 2, OPL_R, {0x02, 0x05, 0x0a, 0x0d}}, 103 { 3, OPL_R, {0x08, 0x0b, 0x00, 0x00}}, 104 { 4, OPL_R, {0x09, 0x0c, 0x00, 0x00}}, 105 { 5, OPL_R, {0x0a, 0x0d, 0x00, 0x00}}, 106 107 { 6, OPL_R, {0x10, 0x13, 0x00, 0x00}}, 108 { 7, OPL_R, {0x11, 0x14, 0x00, 0x00}}, 109 { 8, OPL_R, {0x12, 0x15, 0x00, 0x00}} 110 }; 111 112 static void opl_command(struct opl_softc *, int, int, int); 113 void opl_reset(struct opl_softc *); 114 void opl_freq_to_fnum (int freq, int *block, int *fnum); 115 116 int oplsyn_open __P((midisyn *ms, int)); 117 void oplsyn_close __P((midisyn *)); 118 void oplsyn_reset __P((void *)); 119 void oplsyn_noteon __P((midisyn *, u_int32_t, u_int32_t, u_int32_t)); 120 void oplsyn_noteoff __P((midisyn *, u_int32_t, u_int32_t, u_int32_t)); 121 void oplsyn_keypressure __P((midisyn *, u_int32_t, u_int32_t, u_int32_t)); 122 void oplsyn_ctlchange __P((midisyn *, u_int32_t, u_int32_t, u_int32_t)); 123 void oplsyn_programchange __P((midisyn *, u_int32_t, u_int32_t)); 124 void oplsyn_pitchbend __P((midisyn *, u_int32_t, u_int32_t, u_int32_t)); 125 void oplsyn_loadpatch __P((midisyn *, struct sysex_info *, struct uio *)); 126 127 128 void opl_set_op_reg __P((struct opl_softc *, int, int, int, u_char)); 129 void opl_set_ch_reg __P((struct opl_softc *, int, int, u_char)); 130 void opl_load_patch __P((struct opl_softc *, int)); 131 u_int32_t opl_get_block_fnum __P((int freq)); 132 int opl_calc_vol __P((int regbyte, int volume, int main_vol)); 133 134 struct midisyn_methods opl3_midi = { 135 oplsyn_open, 136 oplsyn_close, 137 0, 138 0, 139 oplsyn_noteon, 140 oplsyn_noteoff, 141 oplsyn_keypressure, 142 oplsyn_ctlchange, 143 oplsyn_programchange, 144 0, 145 oplsyn_pitchbend, 146 0 147 }; 148 149 void 150 opl_attach(sc) 151 struct opl_softc *sc; 152 { 153 int i; 154 155 if (!opl_find(sc)) { 156 printf("\nopl: find failed\n"); 157 return; 158 } 159 160 sc->syn.mets = &opl3_midi; 161 snprintf(sc->syn.name, sizeof(sc->syn.name), "%sYamaha OPL%d", 162 sc->syn.name, sc->model); 163 sc->syn.data = sc; 164 sc->syn.nvoice = sc->model == OPL_2 ? OPL2_NVOICE : OPL3_NVOICE; 165 sc->syn.flags = MS_DOALLOC | MS_FREQXLATE; 166 midisyn_attach(&sc->mididev, &sc->syn); 167 168 /* Set up voice table */ 169 for (i = 0; i < OPL3_NVOICE; i++) 170 sc->voices[i] = voicetab[i]; 171 172 opl_reset(sc); 173 174 printf(": model OPL%d", sc->model); 175 176 /* Set up panpot */ 177 sc->panl = OPL_VOICE_TO_LEFT; 178 sc->panr = OPL_VOICE_TO_RIGHT; 179 if (sc->model == OPL_3 && 180 sc->mididev.dev.dv_cfdata->cf_flags & OPL_FLAGS_SWAP_LR) { 181 sc->panl = OPL_VOICE_TO_RIGHT; 182 sc->panr = OPL_VOICE_TO_LEFT; 183 printf(": LR swapped"); 184 } 185 186 printf("\n"); 187 188 sc->sc_mididev = 189 midi_attach_mi(&midisyn_hw_if, &sc->syn, &sc->mididev.dev); 190 } 191 192 int 193 opl_detach(sc, flags) 194 struct opl_softc *sc; 195 int flags; 196 { 197 int rv = 0; 198 199 if (sc->sc_mididev != NULL) 200 rv = config_detach(sc->sc_mididev, flags); 201 202 return(rv); 203 } 204 205 static void 206 opl_command(sc, offs, addr, data) 207 struct opl_softc *sc; 208 int offs; 209 int addr, data; 210 { 211 DPRINTFN(4, ("opl_command: sc=%p, offs=%d addr=0x%02x data=0x%02x\n", 212 sc, offs, addr, data)); 213 offs += sc->offs; 214 bus_space_write_1(sc->iot, sc->ioh, OPL_ADDR+offs, addr); 215 if (sc->model == OPL_2) 216 delay(10); 217 else 218 delay(6); 219 bus_space_write_1(sc->iot, sc->ioh, OPL_DATA+offs, data); 220 if (sc->model == OPL_2) 221 delay(30); 222 else 223 delay(6); 224 } 225 226 int 227 opl_find(sc) 228 struct opl_softc *sc; 229 { 230 u_int8_t status1, status2; 231 232 DPRINTFN(2,("opl_find: ioh=0x%x\n", (int)sc->ioh)); 233 sc->model = OPL_2; /* worst case assumption */ 234 235 /* Reset timers 1 and 2 */ 236 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, 237 OPL_TIMER1_MASK | OPL_TIMER2_MASK); 238 /* Reset the IRQ of the FM chip */ 239 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET); 240 241 /* get status bits */ 242 status1 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs); 243 244 opl_command(sc, OPL_L, OPL_TIMER1, -2); /* wait 2 ticks */ 245 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, /* start timer1 */ 246 OPL_TIMER1_START | OPL_TIMER2_MASK); 247 delay(1000); /* wait for timer to expire */ 248 249 /* get status bits again */ 250 status2 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs); 251 252 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, 253 OPL_TIMER1_MASK | OPL_TIMER2_MASK); 254 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET); 255 256 DPRINTFN(2,("opl_find: %02x %02x\n", status1, status2)); 257 258 if ((status1 & OPL_STATUS_MASK) != 0 || 259 (status2 & OPL_STATUS_MASK) != (OPL_STATUS_IRQ | OPL_STATUS_FT1)) 260 return (0); 261 262 switch(status1) { 263 case 0x00: 264 case 0x0f: 265 sc->model = OPL_3; 266 break; 267 case 0x06: 268 sc->model = OPL_2; 269 break; 270 default: 271 return (0); 272 } 273 274 DPRINTFN(2,("opl_find: OPL%d at 0x%x detected\n", 275 sc->model, (int)sc->ioh)); 276 return (1); 277 } 278 279 void 280 opl_set_op_reg(sc, base, voice, op, value) 281 struct opl_softc *sc; 282 int base; 283 int voice; 284 int op; 285 u_char value; 286 { 287 struct opl_voice *v = &sc->voices[voice]; 288 opl_command(sc, v->iooffs, base + v->op[op], value); 289 } 290 291 void 292 opl_set_ch_reg(sc, base, voice, value) 293 struct opl_softc *sc; 294 int base; 295 int voice; 296 u_char value; 297 { 298 struct opl_voice *v = &sc->voices[voice]; 299 opl_command(sc, v->iooffs, base + v->voiceno, value); 300 } 301 302 303 void 304 opl_load_patch(sc, v) 305 struct opl_softc *sc; 306 int v; 307 { 308 const struct opl_operators *p = sc->voices[v].patch; 309 310 opl_set_op_reg(sc, OPL_AM_VIB, v, 0, p->ops[OO_CHARS+0]); 311 opl_set_op_reg(sc, OPL_AM_VIB, v, 1, p->ops[OO_CHARS+1]); 312 opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 0, p->ops[OO_KSL_LEV+0]); 313 opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 1, p->ops[OO_KSL_LEV+1]); 314 opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 0, p->ops[OO_ATT_DEC+0]); 315 opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 1, p->ops[OO_ATT_DEC+1]); 316 opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 0, p->ops[OO_SUS_REL+0]); 317 opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 1, p->ops[OO_SUS_REL+1]); 318 opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 0, p->ops[OO_WAV_SEL+0]); 319 opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 1, p->ops[OO_WAV_SEL+1]); 320 opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, v, p->ops[OO_FB_CONN]); 321 } 322 323 #define OPL_FNUM_FAIL 0xffff 324 u_int32_t 325 opl_get_block_fnum(freq) 326 int freq; 327 { 328 u_int32_t f_num = freq / 3125; 329 u_int32_t block = 0; 330 331 while (f_num > 0x3ff && block < 8) { 332 block++; 333 f_num >>= 1; 334 } 335 336 if (block > 7) 337 return (OPL_FNUM_FAIL); 338 else 339 return ((block << 10) | f_num); 340 } 341 342 343 void 344 opl_reset(sc) 345 struct opl_softc *sc; 346 { 347 int i; 348 349 for (i = 1; i <= OPL_MAXREG; i++) 350 opl_command(sc, OPL_L, OPL_KEYON_BLOCK + i, 0); 351 352 opl_command(sc, OPL_L, OPL_TEST, OPL_ENABLE_WAVE_SELECT); 353 opl_command(sc, OPL_L, OPL_PERCUSSION, 0); 354 if (sc->model == OPL_3) { 355 opl_command(sc, OPL_R, OPL_MODE, OPL3_ENABLE); 356 opl_command(sc, OPL_R,OPL_CONNECTION_SELECT,OPL_NOCONNECTION); 357 } 358 359 sc->volume = 64; 360 361 for (i = 0; i < MIDI_MAX_CHANS; i++) 362 sc->pan[i] = OPL_VOICE_TO_LEFT | OPL_VOICE_TO_RIGHT; 363 } 364 365 int 366 oplsyn_open(ms, flags) 367 midisyn *ms; 368 int flags; 369 { 370 struct opl_softc *sc = ms->data; 371 372 DPRINTFN(2, ("oplsyn_open: %d\n", flags)); 373 374 #ifndef AUDIO_NO_POWER_CTL 375 if (sc->powerctl) 376 sc->powerctl(sc->powerarg, 1); 377 #endif 378 opl_reset(ms->data); 379 if (sc->spkrctl) 380 sc->spkrctl(sc->spkrarg, 1); 381 return (0); 382 } 383 384 void 385 oplsyn_close(ms) 386 midisyn *ms; 387 { 388 struct opl_softc *sc = ms->data; 389 390 DPRINTFN(2, ("oplsyn_close:\n")); 391 392 /*opl_reset(ms->data);*/ 393 if (sc->spkrctl) 394 sc->spkrctl(sc->spkrarg, 0); 395 #ifndef AUDIO_NO_POWER_CTL 396 if (sc->powerctl) 397 sc->powerctl(sc->powerarg, 0); 398 #endif 399 } 400 401 #if 0 402 void 403 oplsyn_getinfo(addr, sd) 404 void *addr; 405 struct synth_dev *sd; 406 { 407 struct opl_softc *sc = addr; 408 409 sd->name = sc->model == OPL_2 ? "Yamaha OPL2" : "Yamaha OPL3"; 410 sd->type = SYNTH_TYPE_FM; 411 sd->subtype = sc->model == OPL_2 ? SYNTH_SUB_FM_TYPE_ADLIB 412 : SYNTH_SUB_FM_TYPE_OPL3; 413 sd->capabilities = 0; 414 } 415 #endif 416 417 void 418 oplsyn_reset(addr) 419 void *addr; 420 { 421 struct opl_softc *sc = addr; 422 DPRINTFN(3, ("oplsyn_reset:\n")); 423 opl_reset(sc); 424 } 425 426 const int8_t opl_volume_table[128] = 427 {-64, -48, -40, -35, -32, -29, -27, -26, 428 -24, -23, -21, -20, -19, -18, -18, -17, 429 -16, -15, -15, -14, -13, -13, -12, -12, 430 -11, -11, -10, -10, -10, -9, -9, -8, 431 -8, -8, -7, -7, -7, -6, -6, -6, 432 -5, -5, -5, -5, -4, -4, -4, -4, 433 -3, -3, -3, -3, -2, -2, -2, -2, 434 -2, -1, -1, -1, -1, 0, 0, 0, 435 0, 0, 0, 1, 1, 1, 1, 1, 436 1, 2, 2, 2, 2, 2, 2, 2, 437 3, 3, 3, 3, 3, 3, 3, 4, 438 4, 4, 4, 4, 4, 4, 4, 5, 439 5, 5, 5, 5, 5, 5, 5, 5, 440 6, 6, 6, 6, 6, 6, 6, 6, 441 6, 7, 7, 7, 7, 7, 7, 7, 442 7, 7, 7, 8, 8, 8, 8, 8}; 443 444 int 445 opl_calc_vol(regbyte, volume, mainvol) 446 int regbyte; 447 int volume; 448 int mainvol; 449 { 450 int level = ~regbyte & OPL_TOTAL_LEVEL_MASK; 451 452 if (mainvol > 127) 453 mainvol = 127; 454 455 volume = (volume * mainvol) / 127; 456 457 if (level) 458 level += opl_volume_table[volume]; 459 460 if (level > OPL_TOTAL_LEVEL_MASK) 461 level = OPL_TOTAL_LEVEL_MASK; 462 if (level < 0) 463 level = 0; 464 465 return (~level & OPL_TOTAL_LEVEL_MASK); 466 } 467 468 void 469 oplsyn_noteon(ms, voice, freq, vel) 470 midisyn *ms; 471 u_int32_t voice, freq, vel; 472 { 473 struct opl_softc *sc = ms->data; 474 struct opl_voice *v; 475 const struct opl_operators *p; 476 u_int32_t block_fnum; 477 int mult; 478 int c_mult, m_mult; 479 u_int32_t chan; 480 u_int8_t chars0, chars1, ksl0, ksl1, fbc; 481 u_int8_t r20m, r20c, r40m, r40c, rA0, rB0; 482 u_int8_t vol0, vol1; 483 484 DPRINTFN(3, ("oplsyn_noteon: %p %d %d\n", sc, voice, 485 MIDISYN_FREQ_TO_HZ(freq))); 486 487 #ifdef DIAGNOSTIC 488 if (voice < 0 || voice >= sc->syn.nvoice) { 489 printf("oplsyn_noteon: bad voice %d\n", voice); 490 return; 491 } 492 #endif 493 /* Turn off old note */ 494 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, 0xff); 495 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, 0xff); 496 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, 0); 497 498 v = &sc->voices[voice]; 499 500 chan = MS_GETCHAN(&ms->voices[voice]); 501 p = &opl2_instrs[ms->pgms[chan]]; 502 v->patch = p; 503 opl_load_patch(sc, voice); 504 505 mult = 1; 506 for (;;) { 507 block_fnum = opl_get_block_fnum(freq / mult); 508 if (block_fnum != OPL_FNUM_FAIL) 509 break; 510 mult *= 2; 511 if (mult == 16) 512 mult = 15; 513 } 514 515 chars0 = p->ops[OO_CHARS+0]; 516 chars1 = p->ops[OO_CHARS+1]; 517 m_mult = (chars0 & OPL_MULTIPLE_MASK) * mult; 518 c_mult = (chars1 & OPL_MULTIPLE_MASK) * mult; 519 if ((block_fnum == OPL_FNUM_FAIL) || (m_mult > 15) || (c_mult > 15)) { 520 printf("oplsyn_noteon: frequency out of range %d\n", 521 MIDISYN_FREQ_TO_HZ(freq)); 522 return; 523 } 524 r20m = (chars0 &~ OPL_MULTIPLE_MASK) | m_mult; 525 r20c = (chars1 &~ OPL_MULTIPLE_MASK) | c_mult; 526 527 /* 2 voice */ 528 ksl0 = p->ops[OO_KSL_LEV+0]; 529 ksl1 = p->ops[OO_KSL_LEV+1]; 530 if (p->ops[OO_FB_CONN] & 0x01) { 531 vol0 = opl_calc_vol(ksl0, vel, sc->volume); 532 vol1 = opl_calc_vol(ksl1, vel, sc->volume); 533 } else { 534 vol0 = ksl0; 535 vol1 = opl_calc_vol(ksl1, vel, sc->volume); 536 } 537 r40m = (ksl0 & OPL_KSL_MASK) | vol0; 538 r40c = (ksl1 & OPL_KSL_MASK) | vol1; 539 540 rA0 = block_fnum & 0xFF; 541 rB0 = (block_fnum >> 8) | OPL_KEYON_BIT; 542 543 v->rB0 = rB0; 544 545 fbc = p->ops[OO_FB_CONN]; 546 if (sc->model == OPL_3) { 547 fbc &= ~OPL_STEREO_BITS; 548 fbc |= sc->pan[chan]; 549 } 550 opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, voice, fbc); 551 552 opl_set_op_reg(sc, OPL_AM_VIB, voice, 0, r20m); 553 opl_set_op_reg(sc, OPL_AM_VIB, voice, 1, r20c); 554 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, r40m); 555 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, r40c); 556 opl_set_ch_reg(sc, OPL_FNUM_LOW, voice, rA0); 557 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, rB0); 558 } 559 560 void 561 oplsyn_noteoff(ms, voice, note, vel) 562 midisyn *ms; 563 u_int32_t voice, note, vel; 564 { 565 struct opl_softc *sc = ms->data; 566 struct opl_voice *v; 567 568 DPRINTFN(3, ("oplsyn_noteoff: %p %d %d\n", sc, voice, 569 MIDISYN_FREQ_TO_HZ(note))); 570 571 #ifdef DIAGNOSTIC 572 if (voice < 0 || voice >= sc->syn.nvoice) { 573 printf("oplsyn_noteoff: bad voice %d\n", voice); 574 return; 575 } 576 #endif 577 v = &sc->voices[voice]; 578 opl_set_ch_reg(sc, 0xB0, voice, v->rB0 & ~OPL_KEYON_BIT); 579 } 580 581 void 582 oplsyn_keypressure(ms, voice, note, vel) 583 midisyn *ms; 584 u_int32_t voice, note, vel; 585 { 586 #ifdef AUDIO_DEBUG 587 struct opl_softc *sc = ms->data; 588 DPRINTFN(1, ("oplsyn_keypressure: %p %d\n", sc, note)); 589 #endif 590 } 591 592 void 593 oplsyn_ctlchange(ms, chan, parm, w14) 594 midisyn *ms; 595 u_int32_t chan, parm, w14; 596 { 597 struct opl_softc *sc = ms->data; 598 599 DPRINTFN(1, ("oplsyn_ctlchange: %p %d\n", sc, chan)); 600 switch (parm) { 601 case MIDI_CTRL_PAN_MSB: 602 sc->pan[chan] = 603 (w14 <= OPL_MIDI_CENTER_MAX ? sc->panl : 0) | 604 (w14 >= OPL_MIDI_CENTER_MIN ? sc->panr : 0); 605 break; 606 } 607 } 608 609 /* PROGRAM CHANGE midi event: */ 610 void 611 oplsyn_programchange(ms, chan, prog) 612 midisyn *ms; 613 u_int32_t chan; 614 u_int32_t prog; 615 { 616 /* sanity checks */ 617 if (chan >= MIDI_MAX_CHANS || prog >= OPL_NINSTR) 618 return; 619 620 ms->pgms[chan] = prog; 621 } 622 623 void 624 oplsyn_pitchbend(ms, voice, parm, x) 625 midisyn *ms; 626 u_int32_t voice, parm, x; 627 { 628 #ifdef AUDIO_DEBUG 629 struct opl_softc *sc = ms->data; 630 DPRINTFN(1, ("oplsyn_pitchbend: %p %d\n", sc, voice)); 631 #endif 632 } 633 634 void 635 oplsyn_loadpatch(ms, sysex, uio) 636 midisyn *ms; 637 struct sysex_info *sysex; 638 struct uio *uio; 639 { 640 #if 0 641 struct opl_softc *sc = ms->data; 642 struct sbi_instrument ins; 643 644 DPRINTFN(1, ("oplsyn_loadpatch: %p\n", sc)); 645 646 memcpy(&ins, sysex, sizeof *sysex); 647 if (uio->uio_resid >= sizeof ins - sizeof *sysex) 648 return EINVAL; 649 uiomove((char *)&ins + sizeof *sysex, sizeof ins - sizeof *sysex, uio); 650 /* XXX */ 651 #endif 652 } 653