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