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