1 /* $NetBSD: opl.c,v 1.17 2001/11/13 13:14:42 lukem 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.17 2001/11/13 13:14:42 lukem 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 sprintf(sc->syn.name, "%sYamaha OPL%d", sc->syn.name, sc->model); 162 sc->syn.data = sc; 163 sc->syn.nvoice = sc->model == OPL_2 ? OPL2_NVOICE : OPL3_NVOICE; 164 sc->syn.flags = MS_DOALLOC | MS_FREQXLATE; 165 midisyn_attach(&sc->mididev, &sc->syn); 166 167 /* Set up voice table */ 168 for (i = 0; i < OPL3_NVOICE; i++) 169 sc->voices[i] = voicetab[i]; 170 171 opl_reset(sc); 172 173 printf(": model OPL%d", sc->model); 174 175 /* Set up panpot */ 176 for (i = 0; i < MIDI_MAX_CHANS; i++) 177 sc->pan[i] = OPL_VOICE_TO_LEFT | OPL_VOICE_TO_RIGHT; 178 sc->panl = OPL_VOICE_TO_LEFT; 179 sc->panr = OPL_VOICE_TO_RIGHT; 180 if (sc->model == OPL_3 && 181 sc->mididev.dev.dv_cfdata->cf_flags & OPL_FLAGS_SWAP_LR) { 182 sc->panl = OPL_VOICE_TO_RIGHT; 183 sc->panr = OPL_VOICE_TO_LEFT; 184 printf(": LR swapped"); 185 } 186 187 printf("\n"); 188 189 sc->sc_mididev = 190 midi_attach_mi(&midisyn_hw_if, &sc->syn, &sc->mididev.dev); 191 } 192 193 int 194 opl_detach(sc, flags) 195 struct opl_softc *sc; 196 int flags; 197 { 198 int rv = 0; 199 200 if (sc->sc_mididev != NULL) 201 rv = config_detach(sc->sc_mididev, flags); 202 203 return(rv); 204 } 205 206 static void 207 opl_command(sc, offs, addr, data) 208 struct opl_softc *sc; 209 int offs; 210 int addr, data; 211 { 212 DPRINTFN(4, ("opl_command: sc=%p, offs=%d addr=0x%02x data=0x%02x\n", 213 sc, offs, addr, data)); 214 offs += sc->offs; 215 bus_space_write_1(sc->iot, sc->ioh, OPL_ADDR+offs, addr); 216 if (sc->model == OPL_2) 217 delay(10); 218 else 219 delay(6); 220 bus_space_write_1(sc->iot, sc->ioh, OPL_DATA+offs, data); 221 if (sc->model == OPL_2) 222 delay(30); 223 else 224 delay(6); 225 } 226 227 int 228 opl_find(sc) 229 struct opl_softc *sc; 230 { 231 u_int8_t status1, status2; 232 233 DPRINTFN(2,("opl_find: ioh=0x%x\n", (int)sc->ioh)); 234 sc->model = OPL_2; /* worst case assumtion */ 235 236 /* Reset timers 1 and 2 */ 237 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, 238 OPL_TIMER1_MASK | OPL_TIMER2_MASK); 239 /* Reset the IRQ of the FM chip */ 240 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET); 241 242 /* get status bits */ 243 status1 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs); 244 245 opl_command(sc, OPL_L, OPL_TIMER1, -2); /* wait 2 ticks */ 246 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, /* start timer1 */ 247 OPL_TIMER1_START | OPL_TIMER2_MASK); 248 delay(1000); /* wait for timer to expire */ 249 250 /* get status bits again */ 251 status2 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs); 252 253 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, 254 OPL_TIMER1_MASK | OPL_TIMER2_MASK); 255 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET); 256 257 DPRINTFN(2,("opl_find: %02x %02x\n", status1, status2)); 258 259 if ((status1 & OPL_STATUS_MASK) != 0 || 260 (status2 & OPL_STATUS_MASK) != (OPL_STATUS_IRQ | OPL_STATUS_FT1)) 261 return (0); 262 263 switch(status1) { 264 case 0x00: 265 case 0x0f: 266 sc->model = OPL_3; 267 break; 268 case 0x06: 269 sc->model = OPL_2; 270 break; 271 default: 272 return (0); 273 } 274 275 DPRINTFN(2,("opl_find: OPL%d at 0x%x detected\n", 276 sc->model, (int)sc->ioh)); 277 return (1); 278 } 279 280 void 281 opl_set_op_reg(sc, base, voice, op, value) 282 struct opl_softc *sc; 283 int base; 284 int voice; 285 int op; 286 u_char value; 287 { 288 struct opl_voice *v = &sc->voices[voice]; 289 opl_command(sc, v->iooffs, base + v->op[op], value); 290 } 291 292 void 293 opl_set_ch_reg(sc, base, voice, value) 294 struct opl_softc *sc; 295 int base; 296 int voice; 297 u_char value; 298 { 299 struct opl_voice *v = &sc->voices[voice]; 300 opl_command(sc, v->iooffs, base + v->voiceno, value); 301 } 302 303 304 void 305 opl_load_patch(sc, v) 306 struct opl_softc *sc; 307 int v; 308 { 309 const struct opl_operators *p = sc->voices[v].patch; 310 311 opl_set_op_reg(sc, OPL_AM_VIB, v, 0, p->ops[OO_CHARS+0]); 312 opl_set_op_reg(sc, OPL_AM_VIB, v, 1, p->ops[OO_CHARS+1]); 313 opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 0, p->ops[OO_KSL_LEV+0]); 314 opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 1, p->ops[OO_KSL_LEV+1]); 315 opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 0, p->ops[OO_ATT_DEC+0]); 316 opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 1, p->ops[OO_ATT_DEC+1]); 317 opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 0, p->ops[OO_SUS_REL+0]); 318 opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 1, p->ops[OO_SUS_REL+1]); 319 opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 0, p->ops[OO_WAV_SEL+0]); 320 opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 1, p->ops[OO_WAV_SEL+1]); 321 opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, v, p->ops[OO_FB_CONN]); 322 } 323 324 #define OPL_FNUM_FAIL 0xffff 325 u_int32_t 326 opl_get_block_fnum(freq) 327 int freq; 328 { 329 u_int32_t f_num = freq / 3125; 330 u_int32_t block = 0; 331 332 while (f_num > 0x3ff && block < 8) { 333 block++; 334 f_num >>= 1; 335 } 336 337 if (block > 7) 338 return (OPL_FNUM_FAIL); 339 else 340 return ((block << 10) | f_num); 341 } 342 343 344 void 345 opl_reset(sc) 346 struct opl_softc *sc; 347 { 348 int i; 349 350 for (i = 1; i <= OPL_MAXREG; i++) 351 opl_command(sc, OPL_L, OPL_KEYON_BLOCK + i, 0); 352 353 opl_command(sc, OPL_L, OPL_TEST, OPL_ENABLE_WAVE_SELECT); 354 opl_command(sc, OPL_L, OPL_PERCUSSION, 0); 355 if (sc->model == OPL_3) { 356 opl_command(sc, OPL_R, OPL_MODE, OPL3_ENABLE); 357 opl_command(sc, OPL_R,OPL_CONNECTION_SELECT,OPL_NOCONNECTION); 358 } 359 360 sc->volume = 64; 361 } 362 363 int 364 oplsyn_open(ms, flags) 365 midisyn *ms; 366 int flags; 367 { 368 struct opl_softc *sc = ms->data; 369 370 DPRINTFN(2, ("oplsyn_open: %d\n", flags)); 371 372 #ifndef AUDIO_NO_POWER_CTL 373 if (sc->powerctl) 374 sc->powerctl(sc->powerarg, 1); 375 #endif 376 opl_reset(ms->data); 377 if (sc->spkrctl) 378 sc->spkrctl(sc->spkrarg, 1); 379 return (0); 380 } 381 382 void 383 oplsyn_close(ms) 384 midisyn *ms; 385 { 386 struct opl_softc *sc = ms->data; 387 388 DPRINTFN(2, ("oplsyn_close:\n")); 389 390 /*opl_reset(ms->data);*/ 391 if (sc->spkrctl) 392 sc->spkrctl(sc->spkrarg, 0); 393 #ifndef AUDIO_NO_POWER_CTL 394 if (sc->powerctl) 395 sc->powerctl(sc->powerarg, 0); 396 #endif 397 } 398 399 #if 0 400 void 401 oplsyn_getinfo(addr, sd) 402 void *addr; 403 struct synth_dev *sd; 404 { 405 struct opl_softc *sc = addr; 406 407 sd->name = sc->model == OPL_2 ? "Yamaha OPL2" : "Yamaha OPL3"; 408 sd->type = SYNTH_TYPE_FM; 409 sd->subtype = sc->model == OPL_2 ? SYNTH_SUB_FM_TYPE_ADLIB 410 : SYNTH_SUB_FM_TYPE_OPL3; 411 sd->capabilities = 0; 412 } 413 #endif 414 415 void 416 oplsyn_reset(addr) 417 void *addr; 418 { 419 struct opl_softc *sc = addr; 420 DPRINTFN(3, ("oplsyn_reset:\n")); 421 opl_reset(sc); 422 } 423 424 const int8_t opl_volume_table[128] = 425 {-64, -48, -40, -35, -32, -29, -27, -26, 426 -24, -23, -21, -20, -19, -18, -18, -17, 427 -16, -15, -15, -14, -13, -13, -12, -12, 428 -11, -11, -10, -10, -10, -9, -9, -8, 429 -8, -8, -7, -7, -7, -6, -6, -6, 430 -5, -5, -5, -5, -4, -4, -4, -4, 431 -3, -3, -3, -3, -2, -2, -2, -2, 432 -2, -1, -1, -1, -1, 0, 0, 0, 433 0, 0, 0, 1, 1, 1, 1, 1, 434 1, 2, 2, 2, 2, 2, 2, 2, 435 3, 3, 3, 3, 3, 3, 3, 4, 436 4, 4, 4, 4, 4, 4, 4, 5, 437 5, 5, 5, 5, 5, 5, 5, 5, 438 6, 6, 6, 6, 6, 6, 6, 6, 439 6, 7, 7, 7, 7, 7, 7, 7, 440 7, 7, 7, 8, 8, 8, 8, 8}; 441 442 int 443 opl_calc_vol(regbyte, volume, mainvol) 444 int regbyte; 445 int volume; 446 int mainvol; 447 { 448 int level = ~regbyte & OPL_TOTAL_LEVEL_MASK; 449 450 if (mainvol > 127) 451 mainvol = 127; 452 453 volume = (volume * mainvol) / 127; 454 455 if (level) 456 level += opl_volume_table[volume]; 457 458 if (level > OPL_TOTAL_LEVEL_MASK) 459 level = OPL_TOTAL_LEVEL_MASK; 460 if (level < 0) 461 level = 0; 462 463 return (~level & OPL_TOTAL_LEVEL_MASK); 464 } 465 466 void 467 oplsyn_noteon(ms, voice, freq, vel) 468 midisyn *ms; 469 u_int32_t voice, freq, vel; 470 { 471 struct opl_softc *sc = ms->data; 472 struct opl_voice *v; 473 const struct opl_operators *p; 474 u_int32_t block_fnum; 475 int mult; 476 int c_mult, m_mult; 477 u_int32_t chan; 478 u_int8_t chars0, chars1, ksl0, ksl1, fbc; 479 u_int8_t r20m, r20c, r40m, r40c, rA0, rB0; 480 u_int8_t vol0, vol1; 481 482 DPRINTFN(3, ("oplsyn_noteon: %p %d %d\n", sc, voice, 483 MIDISYN_FREQ_TO_HZ(freq))); 484 485 #ifdef DIAGNOSTIC 486 if (voice < 0 || voice >= sc->syn.nvoice) { 487 printf("oplsyn_noteon: bad voice %d\n", voice); 488 return; 489 } 490 #endif 491 /* Turn off old note */ 492 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, 0xff); 493 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, 0xff); 494 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, 0); 495 496 v = &sc->voices[voice]; 497 498 chan = MS_GETCHAN(&ms->voices[voice]); 499 p = &opl2_instrs[ms->pgms[chan]]; 500 v->patch = p; 501 opl_load_patch(sc, voice); 502 503 mult = 1; 504 for (;;) { 505 block_fnum = opl_get_block_fnum(freq / mult); 506 if (block_fnum != OPL_FNUM_FAIL) 507 break; 508 mult *= 2; 509 if (mult == 16) 510 mult = 15; 511 } 512 513 chars0 = p->ops[OO_CHARS+0]; 514 chars1 = p->ops[OO_CHARS+1]; 515 m_mult = (chars0 & OPL_MULTIPLE_MASK) * mult; 516 c_mult = (chars1 & OPL_MULTIPLE_MASK) * mult; 517 if ((block_fnum == OPL_FNUM_FAIL) || (m_mult > 15) || (c_mult > 15)) { 518 printf("oplsyn_noteon: frequency out of range %d\n", 519 MIDISYN_FREQ_TO_HZ(freq)); 520 return; 521 } 522 r20m = (chars0 &~ OPL_MULTIPLE_MASK) | m_mult; 523 r20c = (chars1 &~ OPL_MULTIPLE_MASK) | c_mult; 524 525 /* 2 voice */ 526 ksl0 = p->ops[OO_KSL_LEV+0]; 527 ksl1 = p->ops[OO_KSL_LEV+1]; 528 if (p->ops[OO_FB_CONN] & 0x01) { 529 vol0 = opl_calc_vol(ksl0, vel, sc->volume); 530 vol1 = opl_calc_vol(ksl1, vel, sc->volume); 531 } else { 532 vol0 = ksl0; 533 vol1 = opl_calc_vol(ksl1, vel, sc->volume); 534 } 535 r40m = (ksl0 & OPL_KSL_MASK) | vol0; 536 r40c = (ksl1 & OPL_KSL_MASK) | vol1; 537 538 rA0 = block_fnum & 0xFF; 539 rB0 = (block_fnum >> 8) | OPL_KEYON_BIT; 540 541 v->rB0 = rB0; 542 543 fbc = p->ops[OO_FB_CONN]; 544 if (sc->model == OPL_3) { 545 fbc &= ~OPL_STEREO_BITS; 546 fbc |= sc->pan[chan]; 547 } 548 opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, voice, fbc); 549 550 opl_set_op_reg(sc, OPL_AM_VIB, voice, 0, r20m); 551 opl_set_op_reg(sc, OPL_AM_VIB, voice, 1, r20c); 552 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, r40m); 553 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, r40c); 554 opl_set_ch_reg(sc, OPL_FNUM_LOW, voice, rA0); 555 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, rB0); 556 } 557 558 void 559 oplsyn_noteoff(ms, voice, note, vel) 560 midisyn *ms; 561 u_int32_t voice, note, vel; 562 { 563 struct opl_softc *sc = ms->data; 564 struct opl_voice *v; 565 566 DPRINTFN(3, ("oplsyn_noteoff: %p %d %d\n", sc, voice, 567 MIDISYN_FREQ_TO_HZ(note))); 568 569 #ifdef DIAGNOSTIC 570 if (voice < 0 || voice >= sc->syn.nvoice) { 571 printf("oplsyn_noteoff: bad voice %d\n", voice); 572 return; 573 } 574 #endif 575 v = &sc->voices[voice]; 576 opl_set_ch_reg(sc, 0xB0, voice, v->rB0 & ~OPL_KEYON_BIT); 577 } 578 579 void 580 oplsyn_keypressure(ms, voice, note, vel) 581 midisyn *ms; 582 u_int32_t voice, note, vel; 583 { 584 #ifdef AUDIO_DEBUG 585 struct opl_softc *sc = ms->data; 586 DPRINTFN(1, ("oplsyn_keypressure: %p %d\n", sc, note)); 587 #endif 588 } 589 590 void 591 oplsyn_ctlchange(ms, chan, parm, w14) 592 midisyn *ms; 593 u_int32_t chan, parm, w14; 594 { 595 struct opl_softc *sc = ms->data; 596 597 DPRINTFN(1, ("oplsyn_ctlchange: %p %d\n", sc, chan)); 598 switch (parm) { 599 case MIDI_CTRL_PAN_MSB: 600 sc->pan[chan] = 601 (w14 <= OPL_MIDI_CENTER_MAX ? sc->panl : 0) | 602 (w14 >= OPL_MIDI_CENTER_MIN ? sc->panr : 0); 603 break; 604 } 605 } 606 607 /* PROGRAM CHANGE midi event: */ 608 void 609 oplsyn_programchange(ms, chan, prog) 610 midisyn *ms; 611 u_int32_t chan; 612 u_int32_t prog; 613 { 614 /* sanity checks */ 615 if (chan >= MIDI_MAX_CHANS || prog >= OPL_NINSTR) 616 return; 617 618 ms->pgms[chan] = prog; 619 } 620 621 void 622 oplsyn_pitchbend(ms, voice, parm, x) 623 midisyn *ms; 624 u_int32_t voice, parm, x; 625 { 626 #ifdef AUDIO_DEBUG 627 struct opl_softc *sc = ms->data; 628 DPRINTFN(1, ("oplsyn_pitchbend: %p %d\n", sc, voice)); 629 #endif 630 } 631 632 void 633 oplsyn_loadpatch(ms, sysex, uio) 634 midisyn *ms; 635 struct sysex_info *sysex; 636 struct uio *uio; 637 { 638 #if 0 639 struct opl_softc *sc = ms->data; 640 struct sbi_instrument ins; 641 642 DPRINTFN(1, ("oplsyn_loadpatch: %p\n", sc)); 643 644 memcpy(&ins, sysex, sizeof *sysex); 645 if (uio->uio_resid >= sizeof ins - sizeof *sysex) 646 return EINVAL; 647 uiomove((char *)&ins + sizeof *sysex, sizeof ins - sizeof *sysex, uio); 648 /* XXX */ 649 #endif 650 } 651