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