1/* $NetBSD$ */ 2 3/* 4 * Copyright (c) 1998, 2008 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), and by Andrew Doran. 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$"); 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/kmem.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 66int opldebug = 0; 67#else 68#define DPRINTF(x) 69#define DPRINTFN(n,x) 70#endif 71 72struct 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 79const 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 106static void opl_command(struct opl_softc *, int, int, int); 107void opl_reset(struct opl_softc *); 108void opl_freq_to_fnum (int freq, int *block, int *fnum); 109 110int oplsyn_open(midisyn *ms, int); 111void oplsyn_close(midisyn *); 112void oplsyn_reset(void *); 113void oplsyn_attackv(midisyn *, uint_fast16_t, midipitch_t, int16_t); 114static void oplsyn_repitchv(midisyn *, uint_fast16_t, midipitch_t); 115static void oplsyn_relevelv(midisyn *, uint_fast16_t, int16_t); 116static void oplsyn_setv(midisyn *, uint_fast16_t, midipitch_t, int16_t, int); 117void oplsyn_releasev(midisyn *, uint_fast16_t, uint_fast8_t); 118int oplsyn_ctlnotice(midisyn *, midictl_evt, uint_fast8_t, uint_fast16_t); 119void oplsyn_programchange(midisyn *, uint_fast8_t, uint_fast8_t); 120void oplsyn_loadpatch(midisyn *, struct sysex_info *, struct uio *); 121static void oplsyn_panhandler(midisyn *, uint_fast8_t); 122 123void opl_set_op_reg(struct opl_softc *, int, int, int, u_char); 124void opl_set_ch_reg(struct opl_softc *, int, int, u_char); 125void opl_load_patch(struct opl_softc *, int); 126u_int32_t opl_get_block_fnum(midipitch_t mp); 127int opl_calc_vol(int regbyte, int16_t level_cB); 128 129struct 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 140void 141opl_attach(struct opl_softc *sc) 142{ 143 int i; 144 145 if (sc->lock == NULL) { 146 panic("opl_attach: no lock"); 147 } 148 149 mutex_enter(sc->lock); 150 i = opl_find(sc); 151 mutex_exit(sc->lock); 152 if (i == 0) { 153 printf("\nopl: find failed\n"); 154 return; 155 } 156 157 mutex_enter(sc->lock); 158 opl_reset(sc); 159 mutex_exit(sc->lock); 160 161 sc->syn.mets = &opl3_midi; 162 snprintf(sc->syn.name, sizeof(sc->syn.name), "%sYamaha OPL%d", 163 sc->syn.name, sc->model); 164 sc->syn.data = sc; 165 sc->syn.nvoice = sc->model == OPL_2 ? OPL2_NVOICE : OPL3_NVOICE; 166 sc->syn.lock = sc->lock; 167 midisyn_attach(&sc->mididev, &sc->syn); 168 169 /* Set up voice table */ 170 for (i = 0; i < OPL3_NVOICE; i++) 171 sc->voices[i] = voicetab[i]; 172 173 aprint_normal(": 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 device_cfdata(sc->mididev.dev)->cf_flags & OPL_FLAGS_SWAP_LR) { 180 sc->panl = OPL_VOICE_TO_RIGHT; 181 sc->panr = OPL_VOICE_TO_LEFT; 182 aprint_normal(": LR swapped"); 183 } 184 185 aprint_normal("\n"); 186 aprint_naive("\n"); 187 188 sc->sc_mididev = 189 midi_attach_mi(&midisyn_hw_if, &sc->syn, sc->mididev.dev); 190} 191 192int 193opl_detach(struct opl_softc *sc, int flags) 194{ 195 int rv = 0; 196 197 if (sc->sc_mididev != NULL) 198 rv = config_detach(sc->sc_mididev, flags); 199 200 return(rv); 201} 202 203static void 204opl_command(struct opl_softc *sc, int offs, int addr, int data) 205{ 206 DPRINTFN(4, ("opl_command: sc=%p, offs=%d addr=0x%02x data=0x%02x\n", 207 sc, offs, addr, data)); 208 209 KASSERT(!sc->lock || mutex_owned(sc->lock)); 210 211 offs += sc->offs; 212 bus_space_write_1(sc->iot, sc->ioh, OPL_ADDR+offs, addr); 213 if (sc->model == OPL_2) 214 delay(10); 215 else 216 delay(6); 217 bus_space_write_1(sc->iot, sc->ioh, OPL_DATA+offs, data); 218 if (sc->model == OPL_2) 219 delay(30); 220 else 221 delay(6); 222} 223 224int 225opl_match(bus_space_tag_t iot, bus_space_handle_t ioh, int offs) 226{ 227 struct opl_softc *sc; 228 int rv; 229 230 sc = kmem_zalloc(sizeof(*sc), KM_SLEEP); 231 sc->iot = iot; 232 sc->ioh = ioh; 233 sc->offs = offs; 234 rv = opl_find(sc); 235 kmem_free(sc, sizeof(*sc)); 236 return rv; 237} 238 239int 240opl_find(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 */ 298void 299opl_set_op_reg(struct opl_softc *sc, int base, int voice, int op, u_char value) 300{ 301 struct opl_voice *v = &sc->voices[voice]; 302 303 KASSERT(mutex_owned(sc->lock)); 304 305 opl_command(sc, v->iooffs, base + v->op[op], value); 306} 307 308void 309opl_set_ch_reg(struct opl_softc *sc, int base, int voice, u_char value) 310{ 311 struct opl_voice *v = &sc->voices[voice]; 312 313 KASSERT(mutex_owned(sc->lock)); 314 315 opl_command(sc, v->iooffs, base + v->voiceno, value); 316} 317 318 319void 320opl_load_patch(struct opl_softc *sc, int v) 321{ 322 const struct opl_operators *p = sc->voices[v].patch; 323 324 KASSERT(mutex_owned(sc->lock)); 325 326 opl_set_op_reg(sc, OPL_AM_VIB, v, 0, p->ops[OO_CHARS+0]); 327 opl_set_op_reg(sc, OPL_AM_VIB, v, 1, p->ops[OO_CHARS+1]); 328 opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 0, p->ops[OO_KSL_LEV+0]); 329 opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 1, p->ops[OO_KSL_LEV+1]); 330 opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 0, p->ops[OO_ATT_DEC+0]); 331 opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 1, p->ops[OO_ATT_DEC+1]); 332 opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 0, p->ops[OO_SUS_REL+0]); 333 opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 1, p->ops[OO_SUS_REL+1]); 334 opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 0, p->ops[OO_WAV_SEL+0]); 335 opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 1, p->ops[OO_WAV_SEL+1]); 336 opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, v, p->ops[OO_FB_CONN]); 337} 338 339uint32_t 340opl_get_block_fnum(midipitch_t mp) 341{ 342 midihz18_t hz18; 343 uint32_t block; 344 uint32_t f_num; 345 346 /* 347 * We can get to about note 30 before needing to switch from block 0. 348 * Thereafter, switch block every octave; that will keep f_num in the 349 * upper end of its range, making the most bits available for 350 * resolution. 351 */ 352 block = ( mp - MIDIPITCH_FROM_KEY(19) ) / MIDIPITCH_OCTAVE; 353 if ( block > 7 ) /* subtract wrapped */ 354 block = 0; 355 /* 356 * Could subtract block*MIDIPITCH_OCTAVE here, or >>block later. Later. 357 */ 358 359 hz18 = MIDIPITCH_TO_HZ18(mp); 360 hz18 >>= block; 361 362 /* 363 * The formula in the manual is f_num = ((hz<<19)/fs)>>(block-1) (though 364 * block==0 implies >>-1 which is a C unspecified result). As we already 365 * have hz<<18 and I omitted the -1 when shifting above, what's left to 366 * do now is multiply by 4 and divide by fs, the sampling frequency of 367 * the chip. fs is the master clock frequency fM / 288, fM is 14.32 MHz 368 * so fs is a goofy number around 49.7kHz. The 5th convergent of the 369 * continued fraction matches 4/fs to 9+ significant figures. Doing the 370 * shift first (above) ensures there's room in hz18 to multiply by 9. 371 */ 372 373 f_num = (9 * hz18) / 111875; 374 return ((block << 10) | f_num); 375} 376 377 378void 379opl_reset(struct opl_softc *sc) 380{ 381 int i; 382 383 KASSERT(mutex_owned(sc->lock)); 384 385 for (i = 1; i <= OPL_MAXREG; i++) 386 opl_command(sc, OPL_L, OPL_KEYON_BLOCK + i, 0); 387 388 opl_command(sc, OPL_L, OPL_TEST, OPL_ENABLE_WAVE_SELECT); 389 opl_command(sc, OPL_L, OPL_PERCUSSION, 0); 390 if (sc->model == OPL_3) { 391 opl_command(sc, OPL_R, OPL_MODE, OPL3_ENABLE); 392 opl_command(sc, OPL_R,OPL_CONNECTION_SELECT,OPL_NOCONNECTION); 393 } 394 395 for (i = 0; i < MIDI_MAX_CHANS; i++) 396 sc->pan[i] = OPL_VOICE_TO_LEFT | OPL_VOICE_TO_RIGHT; 397} 398 399int 400oplsyn_open(midisyn *ms, int flags) 401{ 402 struct opl_softc *sc = ms->data; 403 404 KASSERT(mutex_owned(sc->lock)); 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 418void 419oplsyn_close(midisyn *ms) 420{ 421 struct opl_softc *sc = ms->data; 422 423 DPRINTFN(2, ("oplsyn_close:\n")); 424 425 KASSERT(mutex_owned(sc->lock)); 426 427 /*opl_reset(ms->data);*/ 428 if (sc->spkrctl) 429 sc->spkrctl(sc->spkrarg, 0); 430#ifndef AUDIO_NO_POWER_CTL 431 if (sc->powerctl) 432 sc->powerctl(sc->powerarg, 0); 433#endif 434} 435 436#if 0 437void 438oplsyn_getinfo(void *addr, struct synth_dev *sd) 439{ 440 struct opl_softc *sc = addr; 441 442 sd->name = sc->model == OPL_2 ? "Yamaha OPL2" : "Yamaha OPL3"; 443 sd->type = SYNTH_TYPE_FM; 444 sd->subtype = sc->model == OPL_2 ? SYNTH_SUB_FM_TYPE_ADLIB 445 : SYNTH_SUB_FM_TYPE_OPL3; 446 sd->capabilities = 0; 447} 448#endif 449 450void 451oplsyn_reset(void *addr) 452{ 453 struct opl_softc *sc = addr; 454 455 KASSERT(mutex_owned(sc->lock)); 456 457 DPRINTFN(3, ("oplsyn_reset:\n")); 458 opl_reset(sc); 459} 460 461int 462opl_calc_vol(int regbyte, int16_t level_cB) 463{ 464 int level = regbyte & OPL_TOTAL_LEVEL_MASK; 465 466 /* 467 * level is a six-bit attenuation, from 0 (full output) 468 * to -48dB (but without the minus sign) in steps of .75 dB. 469 * We'll just add level_cB, after scaling it because it's 470 * in centibels instead and has the customary minus sign. 471 */ 472 473 level += ( -4 * level_cB ) / 30; 474 475 if (level > OPL_TOTAL_LEVEL_MASK) 476 level = OPL_TOTAL_LEVEL_MASK; 477 if (level < 0) 478 level = 0; 479 480 return level & OPL_TOTAL_LEVEL_MASK; 481} 482 483#define OPLACT_ARTICULATE 1 484#define OPLACT_PITCH 2 485#define OPLACT_LEVEL 4 486 487void 488oplsyn_attackv(midisyn *ms, 489 uint_fast16_t voice, midipitch_t mp, int16_t level_cB) 490{ 491 oplsyn_setv(ms, voice, mp, level_cB, 492 OPLACT_ARTICULATE | OPLACT_PITCH | OPLACT_LEVEL); 493} 494 495static void 496oplsyn_repitchv(midisyn *ms, uint_fast16_t voice, midipitch_t mp) 497{ 498 oplsyn_setv(ms, voice, mp, 0, OPLACT_PITCH); 499} 500 501static void 502oplsyn_relevelv(midisyn *ms, uint_fast16_t voice, int16_t level_cB) 503{ 504 oplsyn_setv(ms, voice, 0, level_cB, OPLACT_LEVEL); 505} 506 507static void 508oplsyn_setv(midisyn *ms, 509 uint_fast16_t voice, midipitch_t mp, int16_t level_cB, int act) 510{ 511 struct opl_softc *sc = ms->data; 512 struct opl_voice *v; 513 const struct opl_operators *p; 514 u_int32_t block_fnum; 515 int mult; 516 int c_mult, m_mult; 517 u_int32_t chan; 518 u_int8_t chars0, chars1, ksl0, ksl1, fbc; 519 u_int8_t r20m, r20c, r40m, r40c, rA0, rB0; 520 u_int8_t vol0, vol1; 521 522 KASSERT(mutex_owned(sc->lock)); 523 524 DPRINTFN(3, ("%s: %p %d %u %d\n", __func__, sc, voice, 525 mp, level_cB)); 526 527#ifdef DIAGNOSTIC 528 if (voice >= sc->syn.nvoice) { 529 printf("%s: bad voice %d\n", __func__, voice); 530 return; 531 } 532#endif 533 v = &sc->voices[voice]; 534 535 if ( act & OPLACT_ARTICULATE ) { 536 /* Turn off old note */ 537 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, 0xff); 538 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, 0xff); 539 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, 0); 540 541 chan = MS_GETCHAN(&ms->voices[voice]); 542 p = &opl2_instrs[ms->pgms[chan]]; 543 v->patch = p; 544 opl_load_patch(sc, voice); 545 546 fbc = p->ops[OO_FB_CONN]; 547 if (sc->model == OPL_3) { 548 fbc &= ~OPL_STEREO_BITS; 549 fbc |= sc->pan[chan]; 550 } 551 opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, voice, fbc); 552 } else 553 p = v->patch; 554 555 if ( act & OPLACT_LEVEL ) { 556 /* 2 voice */ 557 ksl0 = p->ops[OO_KSL_LEV+0]; 558 ksl1 = p->ops[OO_KSL_LEV+1]; 559 if (p->ops[OO_FB_CONN] & 0x01) { 560 vol0 = opl_calc_vol(ksl0, level_cB); 561 vol1 = opl_calc_vol(ksl1, level_cB); 562 } else { 563 vol0 = ksl0; 564 vol1 = opl_calc_vol(ksl1, level_cB); 565 } 566 r40m = (ksl0 & OPL_KSL_MASK) | vol0; 567 r40c = (ksl1 & OPL_KSL_MASK) | vol1; 568 569 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, r40m); 570 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, r40c); 571 } 572 573 if ( act & OPLACT_PITCH ) { 574 mult = 1; 575 if ( mp > MIDIPITCH_FROM_KEY(114) ) { /* out of mult 1 range */ 576 mult = 4; /* will cover remaining MIDI range */ 577 mp -= 2*MIDIPITCH_OCTAVE; 578 } 579 580 block_fnum = opl_get_block_fnum(mp); 581 582 chars0 = p->ops[OO_CHARS+0]; 583 chars1 = p->ops[OO_CHARS+1]; 584 m_mult = (chars0 & OPL_MULTIPLE_MASK) * mult; 585 c_mult = (chars1 & OPL_MULTIPLE_MASK) * mult; 586 587 if ( 4 == mult ) { 588 if ( 0 == m_mult ) /* The OPL uses 0 to represent .5 */ 589 m_mult = 2; /* but of course 0*mult above did */ 590 if ( 0 == c_mult ) /* not DTRT */ 591 c_mult = 2; 592 } 593 594 if ((m_mult > 15) || (c_mult > 15)) { 595 printf("%s: frequency out of range %u (mult %d)\n", 596 __func__, mp, mult); 597 return; 598 } 599 r20m = (chars0 &~ OPL_MULTIPLE_MASK) | m_mult; 600 r20c = (chars1 &~ OPL_MULTIPLE_MASK) | c_mult; 601 602 rA0 = block_fnum & 0xFF; 603 rB0 = (block_fnum >> 8) | OPL_KEYON_BIT; 604 605 v->rB0 = rB0; 606 607 opl_set_op_reg(sc, OPL_AM_VIB, voice, 0, r20m); 608 opl_set_op_reg(sc, OPL_AM_VIB, voice, 1, r20c); 609 610 opl_set_ch_reg(sc, OPL_FNUM_LOW, voice, rA0); 611 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, rB0); 612 } 613} 614 615void 616oplsyn_releasev(midisyn *ms, uint_fast16_t voice, uint_fast8_t vel) 617{ 618 struct opl_softc *sc = ms->data; 619 struct opl_voice *v; 620 621 KASSERT(mutex_owned(sc->lock)); 622 623 DPRINTFN(1, ("%s: %p %d\n", __func__, sc, voice)); 624 625#ifdef DIAGNOSTIC 626 if (voice >= sc->syn.nvoice) { 627 printf("oplsyn_noteoff: bad voice %d\n", voice); 628 return; 629 } 630#endif 631 v = &sc->voices[voice]; 632 opl_set_ch_reg(sc, 0xB0, voice, v->rB0 & ~OPL_KEYON_BIT); 633} 634 635int 636oplsyn_ctlnotice(midisyn *ms, 637 midictl_evt evt, uint_fast8_t chan, uint_fast16_t key) 638{ 639 640 DPRINTFN(1, ("%s: %p %d\n", __func__, ms->data, chan)); 641 642 switch (evt) { 643 case MIDICTL_RESET: 644 oplsyn_panhandler(ms, chan); 645 return 1; 646 647 case MIDICTL_CTLR: 648 switch (key) { 649 case MIDI_CTRL_PAN_MSB: 650 oplsyn_panhandler(ms, chan); 651 return 1; 652 } 653 return 0; 654 default: 655 return 0; 656 } 657} 658 659/* PROGRAM CHANGE midi event: */ 660void 661oplsyn_programchange(midisyn *ms, uint_fast8_t chan, uint_fast8_t prog) 662{ 663 /* sanity checks */ 664 if (chan >= MIDI_MAX_CHANS) 665 return; 666 667 ms->pgms[chan] = prog; 668} 669 670void 671oplsyn_loadpatch(midisyn *ms, struct sysex_info *sysex, 672 struct uio *uio) 673{ 674#if 0 675 struct opl_softc *sc = ms->data; 676 struct sbi_instrument ins; 677 678 DPRINTFN(1, ("oplsyn_loadpatch: %p\n", sc)); 679 680 memcpy(&ins, sysex, sizeof *sysex); 681 if (uio->uio_resid >= sizeof ins - sizeof *sysex) 682 return EINVAL; 683 uiomove((char *)&ins + sizeof *sysex, sizeof ins - sizeof *sysex, uio); 684 /* XXX */ 685#endif 686} 687 688static void 689oplsyn_panhandler(midisyn *ms, uint_fast8_t chan) 690{ 691 struct opl_softc *sc = ms->data; 692 uint_fast16_t setting; 693 694 setting = midictl_read(&ms->ctl, chan, MIDI_CTRL_PAN_MSB, 8192); 695 setting >>= 7; /* we used to treat it as MSB only */ 696 sc->pan[chan] = 697 (setting <= OPL_MIDI_CENTER_MAX ? sc->panl : 0) | 698 (setting >= OPL_MIDI_CENTER_MIN ? sc->panr : 0); 699} 700