1 /* $NetBSD: opl.c,v 1.34 2008/04/28 20:23:51 martin 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * The OPL3 (YMF262) manual can be found at 34 * ftp://ftp.yamahayst.com/Fax_Back_Doc/sound/YMF262.PDF 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: opl.c,v 1.34 2008/04/28 20:23:51 martin Exp $"); 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/errno.h> 43 #include <sys/ioctl.h> 44 #include <sys/syslog.h> 45 #include <sys/device.h> 46 #include <sys/select.h> 47 #include <sys/malloc.h> 48 49 #include <sys/cpu.h> 50 #include <sys/bus.h> 51 52 #include <sys/audioio.h> 53 #include <sys/midiio.h> 54 #include <dev/audio_if.h> 55 56 #include <dev/midi_if.h> 57 #include <dev/midivar.h> 58 #include <dev/midisynvar.h> 59 60 #include <dev/ic/oplreg.h> 61 #include <dev/ic/oplvar.h> 62 63 #ifdef AUDIO_DEBUG 64 #define DPRINTF(x) if (opldebug) printf x 65 #define DPRINTFN(n,x) if (opldebug >= (n)) printf x 66 int opldebug = 0; 67 #else 68 #define DPRINTF(x) 69 #define DPRINTFN(n,x) 70 #endif 71 72 struct real_voice { 73 u_int8_t voice_num; 74 u_int8_t voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */ 75 u_int8_t iooffs; /* I/O port (left or right side) */ 76 u_int8_t op[4]; /* Operator offsets */ 77 }; 78 79 const struct opl_voice voicetab[] = { 80 /* No I/O offs OP1 OP2 OP3 OP4 */ 81 /* --------------------------------------------- */ 82 { 0, OPL_L, {0x00, 0x03, 0x08, 0x0b}, NULL, 0, }, 83 { 1, OPL_L, {0x01, 0x04, 0x09, 0x0c}, NULL, 0, }, 84 { 2, OPL_L, {0x02, 0x05, 0x0a, 0x0d}, NULL, 0, }, 85 86 { 3, OPL_L, {0x08, 0x0b, 0x00, 0x00}, NULL, 0, }, 87 { 4, OPL_L, {0x09, 0x0c, 0x00, 0x00}, NULL, 0, }, 88 { 5, OPL_L, {0x0a, 0x0d, 0x00, 0x00}, NULL, 0, }, 89 90 { 6, OPL_L, {0x10, 0x13, 0x00, 0x00}, NULL, 0, }, 91 { 7, OPL_L, {0x11, 0x14, 0x00, 0x00}, NULL, 0, }, 92 { 8, OPL_L, {0x12, 0x15, 0x00, 0x00}, NULL, 0, }, 93 94 { 0, OPL_R, {0x00, 0x03, 0x08, 0x0b}, NULL, 0, }, 95 { 1, OPL_R, {0x01, 0x04, 0x09, 0x0c}, NULL, 0, }, 96 { 2, OPL_R, {0x02, 0x05, 0x0a, 0x0d}, NULL, 0, }, 97 { 3, OPL_R, {0x08, 0x0b, 0x00, 0x00}, NULL, 0, }, 98 { 4, OPL_R, {0x09, 0x0c, 0x00, 0x00}, NULL, 0, }, 99 { 5, OPL_R, {0x0a, 0x0d, 0x00, 0x00}, NULL, 0, }, 100 101 { 6, OPL_R, {0x10, 0x13, 0x00, 0x00}, NULL, 0, }, 102 { 7, OPL_R, {0x11, 0x14, 0x00, 0x00}, NULL, 0, }, 103 { 8, OPL_R, {0x12, 0x15, 0x00, 0x00}, NULL, 0, } 104 }; 105 106 static void opl_command(struct opl_softc *, int, int, int); 107 void opl_reset(struct opl_softc *); 108 void opl_freq_to_fnum (int freq, int *block, int *fnum); 109 110 int oplsyn_open(midisyn *ms, int); 111 void oplsyn_close(midisyn *); 112 void oplsyn_reset(void *); 113 void oplsyn_attackv(midisyn *, uint_fast16_t, midipitch_t, int16_t); 114 static void oplsyn_repitchv(midisyn *, uint_fast16_t, midipitch_t); 115 static void oplsyn_relevelv(midisyn *, uint_fast16_t, int16_t); 116 static void oplsyn_setv(midisyn *, uint_fast16_t, midipitch_t, int16_t, int); 117 void oplsyn_releasev(midisyn *, uint_fast16_t, uint_fast8_t); 118 int oplsyn_ctlnotice(midisyn *, midictl_evt, uint_fast8_t, uint_fast16_t); 119 void oplsyn_programchange(midisyn *, uint_fast8_t, uint_fast8_t); 120 void oplsyn_loadpatch(midisyn *, struct sysex_info *, struct uio *); 121 static void oplsyn_panhandler(midisyn *, uint_fast8_t); 122 123 void opl_set_op_reg(struct opl_softc *, int, int, int, u_char); 124 void opl_set_ch_reg(struct opl_softc *, int, int, u_char); 125 void opl_load_patch(struct opl_softc *, int); 126 u_int32_t opl_get_block_fnum(midipitch_t mp); 127 int opl_calc_vol(int regbyte, int16_t level_cB); 128 129 struct midisyn_methods opl3_midi = { 130 .open = oplsyn_open, 131 .close = oplsyn_close, 132 .attackv = oplsyn_attackv, 133 .repitchv = oplsyn_repitchv, 134 .relevelv = oplsyn_relevelv, 135 .releasev = oplsyn_releasev, 136 .pgmchg = oplsyn_programchange, 137 .ctlnotice = oplsyn_ctlnotice, 138 }; 139 140 void 141 opl_attach(sc) 142 struct opl_softc *sc; 143 { 144 int i; 145 146 if (!opl_find(sc)) { 147 printf("\nopl: find failed\n"); 148 return; 149 } 150 151 sc->syn.mets = &opl3_midi; 152 snprintf(sc->syn.name, sizeof(sc->syn.name), "%sYamaha OPL%d", 153 sc->syn.name, sc->model); 154 sc->syn.data = sc; 155 sc->syn.nvoice = sc->model == OPL_2 ? OPL2_NVOICE : OPL3_NVOICE; 156 midisyn_attach(&sc->mididev, &sc->syn); 157 158 /* Set up voice table */ 159 for (i = 0; i < OPL3_NVOICE; i++) 160 sc->voices[i] = voicetab[i]; 161 162 opl_reset(sc); 163 164 printf(": model OPL%d", sc->model); 165 166 /* Set up panpot */ 167 sc->panl = OPL_VOICE_TO_LEFT; 168 sc->panr = OPL_VOICE_TO_RIGHT; 169 if (sc->model == OPL_3 && 170 device_cfdata(sc->mididev.dev)->cf_flags & OPL_FLAGS_SWAP_LR) { 171 sc->panl = OPL_VOICE_TO_RIGHT; 172 sc->panr = OPL_VOICE_TO_LEFT; 173 printf(": LR swapped"); 174 } 175 176 printf("\n"); 177 178 sc->sc_mididev = 179 midi_attach_mi(&midisyn_hw_if, &sc->syn, sc->mididev.dev); 180 } 181 182 int 183 opl_detach(sc, flags) 184 struct opl_softc *sc; 185 int flags; 186 { 187 int rv = 0; 188 189 if (sc->sc_mididev != NULL) 190 rv = config_detach(sc->sc_mididev, flags); 191 192 return(rv); 193 } 194 195 static void 196 opl_command(sc, offs, addr, data) 197 struct opl_softc *sc; 198 int offs; 199 int addr, data; 200 { 201 DPRINTFN(4, ("opl_command: sc=%p, offs=%d addr=0x%02x data=0x%02x\n", 202 sc, offs, addr, data)); 203 offs += sc->offs; 204 bus_space_write_1(sc->iot, sc->ioh, OPL_ADDR+offs, addr); 205 if (sc->model == OPL_2) 206 delay(10); 207 else 208 delay(6); 209 bus_space_write_1(sc->iot, sc->ioh, OPL_DATA+offs, data); 210 if (sc->model == OPL_2) 211 delay(30); 212 else 213 delay(6); 214 } 215 216 int 217 opl_match(bus_space_tag_t iot, bus_space_handle_t ioh, int offs) 218 { 219 struct opl_softc *sc; 220 int rv; 221 222 sc = malloc(sizeof(*sc), M_TEMP, M_WAITOK|M_ZERO); 223 sc->iot = iot; 224 sc->ioh = ioh; 225 sc->offs = offs; 226 rv = opl_find(sc); 227 free(sc, M_TEMP); 228 return rv; 229 } 230 231 int 232 opl_find(sc) 233 struct opl_softc *sc; 234 { 235 u_int8_t status1, status2; 236 237 DPRINTFN(2,("opl_find: ioh=0x%x\n", (int)sc->ioh)); 238 sc->model = OPL_2; /* worst case assumption */ 239 240 /* Reset timers 1 and 2 */ 241 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, 242 OPL_TIMER1_MASK | OPL_TIMER2_MASK); 243 /* Reset the IRQ of the FM chip */ 244 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET); 245 246 /* get status bits */ 247 status1 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs); 248 249 opl_command(sc, OPL_L, OPL_TIMER1, -2); /* wait 2 ticks */ 250 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, /* start timer1 */ 251 OPL_TIMER1_START | OPL_TIMER2_MASK); 252 delay(1000); /* wait for timer to expire */ 253 254 /* get status bits again */ 255 status2 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs); 256 257 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, 258 OPL_TIMER1_MASK | OPL_TIMER2_MASK); 259 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET); 260 261 DPRINTFN(2,("opl_find: %02x %02x\n", status1, status2)); 262 263 if ((status1 & OPL_STATUS_MASK) != 0 || 264 (status2 & OPL_STATUS_MASK) != (OPL_STATUS_IRQ | OPL_STATUS_FT1)) 265 return (0); 266 267 switch(status1) { 268 case 0x00: 269 case 0x0f: 270 sc->model = OPL_3; 271 break; 272 case 0x06: 273 sc->model = OPL_2; 274 break; 275 default: 276 return (0); 277 } 278 279 DPRINTFN(2,("opl_find: OPL%d at 0x%x detected\n", 280 sc->model, (int)sc->ioh)); 281 return (1); 282 } 283 284 /* 285 * idea: opl_command does a lot of busywaiting, and the driver typically sets 286 * a lot of registers each time a voice-attack happens. some kind of 287 * caching to remember what was last written to each register could save 288 * a lot of cpu. It would have to be smart enough not to interfere with 289 * any necessary sequences of register access expected by the hardware... 290 */ 291 void 292 opl_set_op_reg(sc, base, voice, op, value) 293 struct opl_softc *sc; 294 int base; 295 int voice; 296 int op; 297 u_char value; 298 { 299 struct opl_voice *v = &sc->voices[voice]; 300 opl_command(sc, v->iooffs, base + v->op[op], value); 301 } 302 303 void 304 opl_set_ch_reg(sc, base, voice, value) 305 struct opl_softc *sc; 306 int base; 307 int voice; 308 u_char value; 309 { 310 struct opl_voice *v = &sc->voices[voice]; 311 opl_command(sc, v->iooffs, base + v->voiceno, value); 312 } 313 314 315 void 316 opl_load_patch(sc, v) 317 struct opl_softc *sc; 318 int v; 319 { 320 const struct opl_operators *p = sc->voices[v].patch; 321 322 opl_set_op_reg(sc, OPL_AM_VIB, v, 0, p->ops[OO_CHARS+0]); 323 opl_set_op_reg(sc, OPL_AM_VIB, v, 1, p->ops[OO_CHARS+1]); 324 opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 0, p->ops[OO_KSL_LEV+0]); 325 opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 1, p->ops[OO_KSL_LEV+1]); 326 opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 0, p->ops[OO_ATT_DEC+0]); 327 opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 1, p->ops[OO_ATT_DEC+1]); 328 opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 0, p->ops[OO_SUS_REL+0]); 329 opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 1, p->ops[OO_SUS_REL+1]); 330 opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 0, p->ops[OO_WAV_SEL+0]); 331 opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 1, p->ops[OO_WAV_SEL+1]); 332 opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, v, p->ops[OO_FB_CONN]); 333 } 334 335 uint32_t 336 opl_get_block_fnum(midipitch_t mp) 337 { 338 midihz18_t hz18; 339 uint32_t block; 340 uint32_t f_num; 341 342 /* 343 * We can get to about note 30 before needing to switch from block 0. 344 * Thereafter, switch block every octave; that will keep f_num in the 345 * upper end of its range, making the most bits available for 346 * resolution. 347 */ 348 block = ( mp - MIDIPITCH_FROM_KEY(19) ) / MIDIPITCH_OCTAVE; 349 if ( block > 7 ) /* subtract wrapped */ 350 block = 0; 351 /* 352 * Could subtract block*MIDIPITCH_OCTAVE here, or >>block later. Later. 353 */ 354 355 hz18 = MIDIPITCH_TO_HZ18(mp); 356 hz18 >>= block; 357 358 /* 359 * The formula in the manual is f_num = ((hz<<19)/fs)>>(block-1) (though 360 * block==0 implies >>-1 which is a C unspecified result). As we already 361 * have hz<<18 and I omitted the -1 when shifting above, what's left to 362 * do now is multiply by 4 and divide by fs, the sampling frequency of 363 * the chip. fs is the master clock frequency fM / 288, fM is 14.32 MHz 364 * so fs is a goofy number around 49.7kHz. The 5th convergent of the 365 * continued fraction matches 4/fs to 9+ significant figures. Doing the 366 * shift first (above) ensures there's room in hz18 to multiply by 9. 367 */ 368 369 f_num = (9 * hz18) / 111875; 370 return ((block << 10) | f_num); 371 } 372 373 374 void 375 opl_reset(sc) 376 struct opl_softc *sc; 377 { 378 int i; 379 380 for (i = 1; i <= OPL_MAXREG; i++) 381 opl_command(sc, OPL_L, OPL_KEYON_BLOCK + i, 0); 382 383 opl_command(sc, OPL_L, OPL_TEST, OPL_ENABLE_WAVE_SELECT); 384 opl_command(sc, OPL_L, OPL_PERCUSSION, 0); 385 if (sc->model == OPL_3) { 386 opl_command(sc, OPL_R, OPL_MODE, OPL3_ENABLE); 387 opl_command(sc, OPL_R,OPL_CONNECTION_SELECT,OPL_NOCONNECTION); 388 } 389 390 for (i = 0; i < MIDI_MAX_CHANS; i++) 391 sc->pan[i] = OPL_VOICE_TO_LEFT | OPL_VOICE_TO_RIGHT; 392 } 393 394 int 395 oplsyn_open(midisyn *ms, int flags) 396 { 397 struct opl_softc *sc = ms->data; 398 399 DPRINTFN(2, ("oplsyn_open: %d\n", flags)); 400 401 #ifndef AUDIO_NO_POWER_CTL 402 if (sc->powerctl) 403 sc->powerctl(sc->powerarg, 1); 404 #endif 405 opl_reset(ms->data); 406 if (sc->spkrctl) 407 sc->spkrctl(sc->spkrarg, 1); 408 return (0); 409 } 410 411 void 412 oplsyn_close(ms) 413 midisyn *ms; 414 { 415 struct opl_softc *sc = ms->data; 416 417 DPRINTFN(2, ("oplsyn_close:\n")); 418 419 /*opl_reset(ms->data);*/ 420 if (sc->spkrctl) 421 sc->spkrctl(sc->spkrarg, 0); 422 #ifndef AUDIO_NO_POWER_CTL 423 if (sc->powerctl) 424 sc->powerctl(sc->powerarg, 0); 425 #endif 426 } 427 428 #if 0 429 void 430 oplsyn_getinfo(addr, sd) 431 void *addr; 432 struct synth_dev *sd; 433 { 434 struct opl_softc *sc = addr; 435 436 sd->name = sc->model == OPL_2 ? "Yamaha OPL2" : "Yamaha OPL3"; 437 sd->type = SYNTH_TYPE_FM; 438 sd->subtype = sc->model == OPL_2 ? SYNTH_SUB_FM_TYPE_ADLIB 439 : SYNTH_SUB_FM_TYPE_OPL3; 440 sd->capabilities = 0; 441 } 442 #endif 443 444 void 445 oplsyn_reset(addr) 446 void *addr; 447 { 448 struct opl_softc *sc = addr; 449 DPRINTFN(3, ("oplsyn_reset:\n")); 450 opl_reset(sc); 451 } 452 453 int 454 opl_calc_vol(int regbyte, int16_t level_cB) 455 { 456 int level = regbyte & OPL_TOTAL_LEVEL_MASK; 457 458 /* 459 * level is a six-bit attenuation, from 0 (full output) 460 * to -48dB (but without the minus sign) in steps of .75 dB. 461 * We'll just add level_cB, after scaling it because it's 462 * in centibels instead and has the customary minus sign. 463 */ 464 465 level += ( -4 * level_cB ) / 30; 466 467 if (level > OPL_TOTAL_LEVEL_MASK) 468 level = OPL_TOTAL_LEVEL_MASK; 469 if (level < 0) 470 level = 0; 471 472 return level & OPL_TOTAL_LEVEL_MASK; 473 } 474 475 #define OPLACT_ARTICULATE 1 476 #define OPLACT_PITCH 2 477 #define OPLACT_LEVEL 4 478 479 void 480 oplsyn_attackv(midisyn *ms, 481 uint_fast16_t voice, midipitch_t mp, int16_t level_cB) 482 { 483 oplsyn_setv(ms, voice, mp, level_cB, 484 OPLACT_ARTICULATE | OPLACT_PITCH | OPLACT_LEVEL); 485 } 486 487 static void 488 oplsyn_repitchv(midisyn *ms, uint_fast16_t voice, midipitch_t mp) 489 { 490 oplsyn_setv(ms, voice, mp, 0, OPLACT_PITCH); 491 } 492 493 static void 494 oplsyn_relevelv(midisyn *ms, uint_fast16_t voice, int16_t level_cB) 495 { 496 oplsyn_setv(ms, voice, 0, level_cB, OPLACT_LEVEL); 497 } 498 499 static void 500 oplsyn_setv(midisyn *ms, 501 uint_fast16_t voice, midipitch_t mp, int16_t level_cB, int act) 502 { 503 struct opl_softc *sc = ms->data; 504 struct opl_voice *v; 505 const struct opl_operators *p; 506 u_int32_t block_fnum; 507 int mult; 508 int c_mult, m_mult; 509 u_int32_t chan; 510 u_int8_t chars0, chars1, ksl0, ksl1, fbc; 511 u_int8_t r20m, r20c, r40m, r40c, rA0, rB0; 512 u_int8_t vol0, vol1; 513 514 DPRINTFN(3, ("%s: %p %d %u %d\n", __func__, sc, voice, 515 mp, level_cB)); 516 517 #ifdef DIAGNOSTIC 518 if (voice >= sc->syn.nvoice) { 519 printf("%s: bad voice %d\n", __func__, voice); 520 return; 521 } 522 #endif 523 v = &sc->voices[voice]; 524 525 if ( act & OPLACT_ARTICULATE ) { 526 /* Turn off old note */ 527 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, 0xff); 528 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, 0xff); 529 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, 0); 530 531 chan = MS_GETCHAN(&ms->voices[voice]); 532 p = &opl2_instrs[ms->pgms[chan]]; 533 v->patch = p; 534 opl_load_patch(sc, voice); 535 536 fbc = p->ops[OO_FB_CONN]; 537 if (sc->model == OPL_3) { 538 fbc &= ~OPL_STEREO_BITS; 539 fbc |= sc->pan[chan]; 540 } 541 opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, voice, fbc); 542 } else 543 p = v->patch; 544 545 if ( act & OPLACT_LEVEL ) { 546 /* 2 voice */ 547 ksl0 = p->ops[OO_KSL_LEV+0]; 548 ksl1 = p->ops[OO_KSL_LEV+1]; 549 if (p->ops[OO_FB_CONN] & 0x01) { 550 vol0 = opl_calc_vol(ksl0, level_cB); 551 vol1 = opl_calc_vol(ksl1, level_cB); 552 } else { 553 vol0 = ksl0; 554 vol1 = opl_calc_vol(ksl1, level_cB); 555 } 556 r40m = (ksl0 & OPL_KSL_MASK) | vol0; 557 r40c = (ksl1 & OPL_KSL_MASK) | vol1; 558 559 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, r40m); 560 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, r40c); 561 } 562 563 if ( act & OPLACT_PITCH ) { 564 mult = 1; 565 if ( mp > MIDIPITCH_FROM_KEY(114) ) { /* out of mult 1 range */ 566 mult = 4; /* will cover remaining MIDI range */ 567 mp -= 2*MIDIPITCH_OCTAVE; 568 } 569 570 block_fnum = opl_get_block_fnum(mp); 571 572 chars0 = p->ops[OO_CHARS+0]; 573 chars1 = p->ops[OO_CHARS+1]; 574 m_mult = (chars0 & OPL_MULTIPLE_MASK) * mult; 575 c_mult = (chars1 & OPL_MULTIPLE_MASK) * mult; 576 577 if ( 4 == mult ) { 578 if ( 0 == m_mult ) /* The OPL uses 0 to represent .5 */ 579 m_mult = 2; /* but of course 0*mult above did */ 580 if ( 0 == c_mult ) /* not DTRT */ 581 c_mult = 2; 582 } 583 584 if ((m_mult > 15) || (c_mult > 15)) { 585 printf("%s: frequency out of range %u (mult %d)\n", 586 __func__, mp, mult); 587 return; 588 } 589 r20m = (chars0 &~ OPL_MULTIPLE_MASK) | m_mult; 590 r20c = (chars1 &~ OPL_MULTIPLE_MASK) | c_mult; 591 592 rA0 = block_fnum & 0xFF; 593 rB0 = (block_fnum >> 8) | OPL_KEYON_BIT; 594 595 v->rB0 = rB0; 596 597 opl_set_op_reg(sc, OPL_AM_VIB, voice, 0, r20m); 598 opl_set_op_reg(sc, OPL_AM_VIB, voice, 1, r20c); 599 600 opl_set_ch_reg(sc, OPL_FNUM_LOW, voice, rA0); 601 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, rB0); 602 } 603 } 604 605 void 606 oplsyn_releasev(midisyn *ms, uint_fast16_t voice, uint_fast8_t vel) 607 { 608 struct opl_softc *sc = ms->data; 609 struct opl_voice *v; 610 611 DPRINTFN(1, ("%s: %p %d\n", __func__, sc, voice)); 612 613 #ifdef DIAGNOSTIC 614 if (voice >= sc->syn.nvoice) { 615 printf("oplsyn_noteoff: bad voice %d\n", voice); 616 return; 617 } 618 #endif 619 v = &sc->voices[voice]; 620 opl_set_ch_reg(sc, 0xB0, voice, v->rB0 & ~OPL_KEYON_BIT); 621 } 622 623 int 624 oplsyn_ctlnotice(midisyn *ms, 625 midictl_evt evt, uint_fast8_t chan, uint_fast16_t key) 626 { 627 628 DPRINTFN(1, ("%s: %p %d\n", __func__, ms->data, chan)); 629 630 switch (evt) { 631 case MIDICTL_RESET: 632 oplsyn_panhandler(ms, chan); 633 return 1; 634 635 case MIDICTL_CTLR: 636 switch (key) { 637 case MIDI_CTRL_PAN_MSB: 638 oplsyn_panhandler(ms, chan); 639 return 1; 640 } 641 return 0; 642 default: 643 return 0; 644 } 645 } 646 647 /* PROGRAM CHANGE midi event: */ 648 void 649 oplsyn_programchange(midisyn *ms, uint_fast8_t chan, uint_fast8_t prog) 650 { 651 /* sanity checks */ 652 if (chan >= MIDI_MAX_CHANS) 653 return; 654 655 ms->pgms[chan] = prog; 656 } 657 658 void 659 oplsyn_loadpatch(midisyn *ms, struct sysex_info *sysex, 660 struct uio *uio) 661 { 662 #if 0 663 struct opl_softc *sc = ms->data; 664 struct sbi_instrument ins; 665 666 DPRINTFN(1, ("oplsyn_loadpatch: %p\n", sc)); 667 668 memcpy(&ins, sysex, sizeof *sysex); 669 if (uio->uio_resid >= sizeof ins - sizeof *sysex) 670 return EINVAL; 671 uiomove((char *)&ins + sizeof *sysex, sizeof ins - sizeof *sysex, uio); 672 /* XXX */ 673 #endif 674 } 675 676 static void 677 oplsyn_panhandler(midisyn *ms, uint_fast8_t chan) 678 { 679 struct opl_softc *sc = ms->data; 680 uint_fast16_t setting; 681 682 setting = midictl_read(&ms->ctl, chan, MIDI_CTRL_PAN_MSB, 8192); 683 setting >>= 7; /* we used to treat it as MSB only */ 684 sc->pan[chan] = 685 (setting <= OPL_MIDI_CENTER_MAX ? sc->panl : 0) | 686 (setting >= OPL_MIDI_CENTER_MIN ? sc->panr : 0); 687 } 688