Annotation of sys/dev/ic/opl.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: opl.c,v 1.8 2006/07/27 05:55:00 miod Exp $ */
! 2: /* $NetBSD: opl.c,v 1.7 1998/12/08 14:26:56 augustss Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Lennart Augustsson (augustss@netbsd.org).
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: /*
! 41: * The OPL3 (YMF262) manual can be found at
! 42: * ftp://ftp.yamahayst.com/pub/Fax_Back_Doc/Sound/YMF262.PDF
! 43: */
! 44:
! 45: #include <sys/param.h>
! 46: #include <sys/systm.h>
! 47: #include <sys/errno.h>
! 48: #include <sys/ioctl.h>
! 49: #include <sys/syslog.h>
! 50: #include <sys/device.h>
! 51: #include <sys/selinfo.h>
! 52:
! 53: #include <machine/cpu.h>
! 54: #include <machine/bus.h>
! 55:
! 56: #include <sys/audioio.h>
! 57: #include <sys/midiio.h>
! 58: #include <dev/audio_if.h>
! 59:
! 60: #include <dev/midi_if.h>
! 61: #include <dev/midivar.h>
! 62: #include <dev/midisynvar.h>
! 63:
! 64: #include <dev/ic/oplreg.h>
! 65: #include <dev/ic/oplvar.h>
! 66:
! 67: #ifdef AUDIO_DEBUG
! 68: #define DPRINTF(x) if (opldebug) printf x
! 69: #define DPRINTFN(n,x) if (opldebug >= (n)) printf x
! 70: int opldebug = 0;
! 71: #else
! 72: #define DPRINTF(x)
! 73: #define DPRINTFN(n,x)
! 74: #endif
! 75:
! 76: struct real_voice {
! 77: u_int8_t voice_num;
! 78: u_int8_t voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */
! 79: u_int8_t iooffs; /* I/O port (left or right side) */
! 80: u_int8_t op[4]; /* Operator offsets */
! 81: };
! 82:
! 83: const struct opl_voice voicetab[] = {
! 84: /* No I/O offs OP1 OP2 OP3 OP4 */
! 85: /* --------------------------------------------------- */
! 86: { 0, OPL_L, {0x00, 0x03, 0x08, 0x0b}},
! 87: { 1, OPL_L, {0x01, 0x04, 0x09, 0x0c}},
! 88: { 2, OPL_L, {0x02, 0x05, 0x0a, 0x0d}},
! 89:
! 90: { 3, OPL_L, {0x08, 0x0b, 0x00, 0x00}},
! 91: { 4, OPL_L, {0x09, 0x0c, 0x00, 0x00}},
! 92: { 5, OPL_L, {0x0a, 0x0d, 0x00, 0x00}},
! 93:
! 94: { 6, OPL_L, {0x10, 0x13, 0x00, 0x00}},
! 95: { 7, OPL_L, {0x11, 0x14, 0x00, 0x00}},
! 96: { 8, OPL_L, {0x12, 0x15, 0x00, 0x00}},
! 97:
! 98: { 0, OPL_R, {0x00, 0x03, 0x08, 0x0b}},
! 99: { 1, OPL_R, {0x01, 0x04, 0x09, 0x0c}},
! 100: { 2, OPL_R, {0x02, 0x05, 0x0a, 0x0d}},
! 101: { 3, OPL_R, {0x08, 0x0b, 0x00, 0x00}},
! 102: { 4, OPL_R, {0x09, 0x0c, 0x00, 0x00}},
! 103: { 5, OPL_R, {0x0a, 0x0d, 0x00, 0x00}},
! 104:
! 105: { 6, OPL_R, {0x10, 0x13, 0x00, 0x00}},
! 106: { 7, OPL_R, {0x11, 0x14, 0x00, 0x00}},
! 107: { 8, OPL_R, {0x12, 0x15, 0x00, 0x00}}
! 108: };
! 109:
! 110: static void opl_probe_command(struct opl_attach_arg *, int, int);
! 111: static void opl_command(struct opl_softc *, int, int, int);
! 112: void opl_reset(struct opl_softc *);
! 113: void opl_freq_to_fnum (int freq, int *block, int *fnum);
! 114:
! 115: int oplsyn_open(midisyn *ms, int);
! 116: void oplsyn_close(midisyn *);
! 117: void oplsyn_reset(void *);
! 118: void oplsyn_noteon(midisyn *, u_int32_t, u_int32_t, u_int32_t);
! 119: void oplsyn_noteoff(midisyn *, u_int32_t, u_int32_t, u_int32_t);
! 120: void oplsyn_keypressure(midisyn *, u_int32_t, u_int32_t, u_int32_t);
! 121: void oplsyn_ctlchange(midisyn *, u_int32_t, u_int32_t, u_int32_t);
! 122: void oplsyn_pitchbend(midisyn *, u_int32_t, u_int32_t, u_int32_t);
! 123: void oplsyn_loadpatch(midisyn *, struct sysex_info *, struct uio *);
! 124:
! 125:
! 126: void opl_set_op_reg(struct opl_softc *, int, int, int, u_char);
! 127: void opl_set_ch_reg(struct opl_softc *, int, int, u_char);
! 128: void opl_load_patch(struct opl_softc *, int);
! 129: u_int32_t opl_get_block_fnum(int freq);
! 130: int opl_calc_vol(int regbyte, int volume, int main_vol);
! 131:
! 132: struct cfdriver opl_cd = {
! 133: NULL, "opl", DV_DULL
! 134: };
! 135:
! 136: struct midisyn_methods opl3_midi = {
! 137: oplsyn_open,
! 138: oplsyn_close,
! 139: 0,
! 140: 0,
! 141: oplsyn_noteon,
! 142: oplsyn_noteoff,
! 143: oplsyn_keypressure,
! 144: oplsyn_ctlchange,
! 145: 0,
! 146: 0,
! 147: oplsyn_pitchbend,
! 148: 0
! 149: };
! 150:
! 151: void
! 152: opl_attach(sc)
! 153: struct opl_softc *sc;
! 154: {
! 155: int i;
! 156: struct opl_attach_arg oaa;
! 157:
! 158: oaa.iot = sc->iot;
! 159: oaa.ioh = sc->ioh;
! 160: oaa.offs = sc->offs;
! 161: oaa.done = 0;
! 162:
! 163: if ((sc->model = opl_find(&oaa)) == 0) {
! 164: printf("\nopl: find failed\n");
! 165: return;
! 166: }
! 167:
! 168: sc->syn.mets = &opl3_midi;
! 169: snprintf(sc->syn.name, sizeof sc->syn.name, "%sYamaha OPL%d",
! 170: sc->syn.name, sc->model);
! 171: sc->syn.data = sc;
! 172: sc->syn.nvoice = sc->model == OPL_2 ? OPL2_NVOICE : OPL3_NVOICE;
! 173: sc->syn.flags = MS_DOALLOC | MS_FREQXLATE;
! 174: midisyn_attach(&sc->mididev, &sc->syn);
! 175:
! 176: /* Set up voice table */
! 177: for (i = 0; i < OPL3_NVOICE; i++)
! 178: sc->voices[i] = voicetab[i];
! 179:
! 180: opl_reset(sc);
! 181:
! 182: printf(": model OPL%d\n", sc->model);
! 183:
! 184: midi_attach_mi(&midisyn_hw_if, &sc->syn, &sc->mididev.dev);
! 185: }
! 186:
! 187: static void
! 188: opl_probe_command(oaa, addr, data)
! 189: struct opl_attach_arg *oaa;
! 190: int addr, data;
! 191: {
! 192: DPRINTFN(4, ("opl_probe_command: addr=0x%02x data=0x%02x\n",
! 193: addr, data));
! 194: bus_space_write_1(oaa->iot, oaa->ioh, OPL_ADDR + OPL_L + oaa->offs,
! 195: addr);
! 196: delay(10);
! 197: bus_space_write_1(oaa->iot, oaa->ioh, OPL_DATA + OPL_L + oaa->offs,
! 198: data);
! 199: delay(30);
! 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_find(oaa)
! 225: struct opl_attach_arg *oaa;
! 226: {
! 227: u_int8_t status1, status2;
! 228: int model;
! 229:
! 230: DPRINTFN(2,("opl_find: ioh=0x%x\n", (int)oaa->ioh));
! 231: model = OPL_2; /* worst case assumption */
! 232:
! 233: /* Reset timers 1 and 2 */
! 234: opl_probe_command(oaa, OPL_TIMER_CONTROL,
! 235: OPL_TIMER1_MASK | OPL_TIMER2_MASK);
! 236: /* Reset the IRQ of the FM chip */
! 237: opl_probe_command(oaa, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
! 238:
! 239: /* get status bits */
! 240: status1 = bus_space_read_1(oaa->iot, oaa->ioh,
! 241: OPL_STATUS + OPL_L + oaa->offs);
! 242:
! 243: opl_probe_command(oaa, OPL_TIMER1, -2); /* wait 2 ticks */
! 244: opl_probe_command(oaa, 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(oaa->iot, oaa->ioh,
! 250: OPL_STATUS + OPL_L + oaa->offs);
! 251:
! 252: opl_probe_command(oaa, OPL_TIMER_CONTROL,
! 253: OPL_TIMER1_MASK | OPL_TIMER2_MASK);
! 254: opl_probe_command(oaa, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
! 255:
! 256: DPRINTFN(2,("opl_find: %02x %02x\n", status1, status2));
! 257:
! 258: if ((status1 & OPL_STATUS_MASK) != 0 ||
! 259: (status2 & OPL_STATUS_MASK) != (OPL_STATUS_IRQ | OPL_STATUS_FT1))
! 260: return (0);
! 261:
! 262: switch(status1) {
! 263: case 0x00:
! 264: case 0x0f:
! 265: model = OPL_3;
! 266: break;
! 267: case 0x06:
! 268: model = OPL_2;
! 269: break;
! 270: default:
! 271: return 0;
! 272: }
! 273:
! 274: DPRINTFN(2,("opl_find: OPL%d at 0x%x detected\n",
! 275: model, (int)oaa->ioh));
! 276: return (model);
! 277: }
! 278:
! 279: void
! 280: opl_set_op_reg(sc, base, voice, op, value)
! 281: struct opl_softc *sc;
! 282: int base;
! 283: int voice;
! 284: int op;
! 285: u_char value;
! 286: {
! 287: struct opl_voice *v = &sc->voices[voice];
! 288: opl_command(sc, v->iooffs, base + v->op[op], value);
! 289: }
! 290:
! 291: void
! 292: opl_set_ch_reg(sc, base, voice, value)
! 293: struct opl_softc *sc;
! 294: int base;
! 295: int voice;
! 296: u_char value;
! 297: {
! 298: struct opl_voice *v = &sc->voices[voice];
! 299: opl_command(sc, v->iooffs, base + v->voiceno, value);
! 300: }
! 301:
! 302:
! 303: void
! 304: opl_load_patch(sc, v)
! 305: struct opl_softc *sc;
! 306: int v;
! 307: {
! 308: const struct opl_operators *p = sc->voices[v].patch;
! 309:
! 310: opl_set_op_reg(sc, OPL_AM_VIB, v, 0, p->ops[OO_CHARS+0]);
! 311: opl_set_op_reg(sc, OPL_AM_VIB, v, 1, p->ops[OO_CHARS+1]);
! 312: opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 0, p->ops[OO_KSL_LEV+0]);
! 313: opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 1, p->ops[OO_KSL_LEV+1]);
! 314: opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 0, p->ops[OO_ATT_DEC+0]);
! 315: opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 1, p->ops[OO_ATT_DEC+1]);
! 316: opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 0, p->ops[OO_SUS_REL+0]);
! 317: opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 1, p->ops[OO_SUS_REL+1]);
! 318: opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 0, p->ops[OO_WAV_SEL+0]);
! 319: opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 1, p->ops[OO_WAV_SEL+1]);
! 320: opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, v, p->ops[OO_FB_CONN]);
! 321: }
! 322:
! 323: #define OPL_FNUM_FAIL 0xffff
! 324: u_int32_t
! 325: opl_get_block_fnum(freq)
! 326: int freq;
! 327: {
! 328: u_int32_t f_num = freq / 3125;
! 329: u_int32_t block = 0;
! 330:
! 331: while (f_num > 0x3FF && block < 8) {
! 332: block++;
! 333: f_num >>= 1;
! 334: }
! 335:
! 336: if (block > 7)
! 337: return (OPL_FNUM_FAIL);
! 338: else
! 339: return ((block << 10) | f_num);
! 340: }
! 341:
! 342:
! 343: void
! 344: opl_reset(sc)
! 345: struct opl_softc *sc;
! 346: {
! 347: int i;
! 348:
! 349: for (i = 1; i <= OPL_MAXREG; i++)
! 350: opl_command(sc, OPL_L, OPL_KEYON_BLOCK + i, 0);
! 351:
! 352: opl_command(sc, OPL_L, OPL_TEST, OPL_ENABLE_WAVE_SELECT);
! 353: opl_command(sc, OPL_L, OPL_PERCUSSION, 0);
! 354: if (sc->model == OPL_3) {
! 355: opl_command(sc, OPL_R, OPL_MODE, OPL3_ENABLE);
! 356: opl_command(sc, OPL_R,OPL_CONNECTION_SELECT,OPL_NOCONNECTION);
! 357: }
! 358:
! 359: sc->volume = 64;
! 360: }
! 361:
! 362: int
! 363: oplsyn_open(ms, flags)
! 364: midisyn *ms;
! 365: int flags;
! 366: {
! 367: struct opl_softc *sc = ms->data;
! 368:
! 369: DPRINTFN(2, ("oplsyn_open: %d\n", flags));
! 370:
! 371: opl_reset(ms->data);
! 372: if (sc->spkrctl)
! 373: sc->spkrctl(sc->spkrarg, 1);
! 374: return (0);
! 375: }
! 376:
! 377: void
! 378: oplsyn_close(ms)
! 379: midisyn *ms;
! 380: {
! 381: struct opl_softc *sc = ms->data;
! 382:
! 383: DPRINTFN(2, ("oplsyn_close:\n"));
! 384:
! 385: /*opl_reset(ms->data);*/
! 386: if (sc->spkrctl)
! 387: sc->spkrctl(sc->spkrarg, 0);
! 388: }
! 389:
! 390: #if 0
! 391: void
! 392: oplsyn_getinfo(addr, sd)
! 393: void *addr;
! 394: struct synth_dev *sd;
! 395: {
! 396: struct opl_softc *sc = addr;
! 397:
! 398: sd->name = sc->model == OPL_2 ? "Yamaha OPL2" : "Yamaha OPL3";
! 399: sd->type = SYNTH_TYPE_FM;
! 400: sd->subtype = sc->model == OPL_2 ? SYNTH_SUB_FM_TYPE_ADLIB
! 401: : SYNTH_SUB_FM_TYPE_OPL3;
! 402: sd->capabilities = 0;
! 403: }
! 404: #endif
! 405:
! 406: void
! 407: oplsyn_reset(addr)
! 408: void *addr;
! 409: {
! 410: struct opl_softc *sc = addr;
! 411: DPRINTFN(3, ("oplsyn_reset:\n"));
! 412: opl_reset(sc);
! 413: }
! 414:
! 415: int8_t opl_volume_table[128] =
! 416: {-64, -48, -40, -35, -32, -29, -27, -26,
! 417: -24, -23, -21, -20, -19, -18, -18, -17,
! 418: -16, -15, -15, -14, -13, -13, -12, -12,
! 419: -11, -11, -10, -10, -10, -9, -9, -8,
! 420: -8, -8, -7, -7, -7, -6, -6, -6,
! 421: -5, -5, -5, -5, -4, -4, -4, -4,
! 422: -3, -3, -3, -3, -2, -2, -2, -2,
! 423: -2, -1, -1, -1, -1, 0, 0, 0,
! 424: 0, 0, 0, 1, 1, 1, 1, 1,
! 425: 1, 2, 2, 2, 2, 2, 2, 2,
! 426: 3, 3, 3, 3, 3, 3, 3, 4,
! 427: 4, 4, 4, 4, 4, 4, 4, 5,
! 428: 5, 5, 5, 5, 5, 5, 5, 5,
! 429: 6, 6, 6, 6, 6, 6, 6, 6,
! 430: 6, 7, 7, 7, 7, 7, 7, 7,
! 431: 7, 7, 7, 8, 8, 8, 8, 8};
! 432:
! 433: int
! 434: opl_calc_vol(regbyte, volume, mainvol)
! 435: int regbyte;
! 436: int volume;
! 437: int mainvol;
! 438: {
! 439: int level = ~regbyte & OPL_TOTAL_LEVEL_MASK;
! 440:
! 441: if (mainvol > 127)
! 442: mainvol = 127;
! 443:
! 444: volume = (volume * mainvol) / 127;
! 445:
! 446: if (level)
! 447: level += opl_volume_table[volume];
! 448:
! 449: if (level > OPL_TOTAL_LEVEL_MASK)
! 450: level = OPL_TOTAL_LEVEL_MASK;
! 451: if (level < 0)
! 452: level = 0;
! 453:
! 454: return (~level & OPL_TOTAL_LEVEL_MASK);
! 455: }
! 456:
! 457: void
! 458: oplsyn_noteon(ms, voice, freq, vel)
! 459: midisyn *ms;
! 460: u_int32_t voice, freq, vel;
! 461: {
! 462: struct opl_softc *sc = ms->data;
! 463: struct opl_voice *v;
! 464: const struct opl_operators *p;
! 465: u_int32_t block_fnum;
! 466: int mult;
! 467: int c_mult, m_mult;
! 468: u_int8_t chars0, chars1, ksl0, ksl1, fbc;
! 469: u_int8_t r20m, r20c, r40m, r40c, rA0, rB0;
! 470: u_int8_t vol0, vol1;
! 471:
! 472: DPRINTFN(3, ("oplsyn_noteon: %p %d %d\n", sc, voice,
! 473: MIDISYN_FREQ_TO_HZ(freq)));
! 474:
! 475: #ifdef DIAGNOSTIC
! 476: if (voice < 0 || voice >= sc->syn.nvoice) {
! 477: printf("oplsyn_noteon: bad voice %d\n", voice);
! 478: return;
! 479: }
! 480: #endif
! 481: /* Turn off old note */
! 482: opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, 0xff);
! 483: opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, 0xff);
! 484: opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, 0);
! 485:
! 486: v = &sc->voices[voice];
! 487:
! 488: p = &opl2_instrs[MS_GETPGM(ms, voice)];
! 489: v->patch = p;
! 490: opl_load_patch(sc, voice);
! 491:
! 492: mult = 1;
! 493: for (;;) {
! 494: block_fnum = opl_get_block_fnum(freq / mult);
! 495: if (block_fnum != OPL_FNUM_FAIL)
! 496: break;
! 497: mult *= 2;
! 498: if (mult == 16)
! 499: mult = 15;
! 500: }
! 501:
! 502: chars0 = p->ops[OO_CHARS+0];
! 503: chars1 = p->ops[OO_CHARS+1];
! 504: m_mult = (chars0 & OPL_MULTIPLE_MASK) * mult;
! 505: c_mult = (chars1 & OPL_MULTIPLE_MASK) * mult;
! 506: if ((block_fnum == OPL_FNUM_FAIL) || (m_mult > 15) || (c_mult > 15)) {
! 507: printf("oplsyn_noteon: frequence out of range %d\n",
! 508: MIDISYN_FREQ_TO_HZ(freq));
! 509: return;
! 510: }
! 511: r20m = (chars0 &~ OPL_MULTIPLE_MASK) | m_mult;
! 512: r20c = (chars1 &~ OPL_MULTIPLE_MASK) | c_mult;
! 513:
! 514: /* 2 voice */
! 515: ksl0 = p->ops[OO_KSL_LEV+0];
! 516: ksl1 = p->ops[OO_KSL_LEV+1];
! 517: if (p->ops[OO_FB_CONN] & 0x01) {
! 518: vol0 = opl_calc_vol(ksl0, vel, sc->volume);
! 519: vol1 = opl_calc_vol(ksl1, vel, sc->volume);
! 520: } else {
! 521: vol0 = ksl0;
! 522: vol1 = opl_calc_vol(ksl1, vel, sc->volume);
! 523: }
! 524: r40m = (ksl0 & OPL_KSL_MASK) | vol0;
! 525: r40c = (ksl1 & OPL_KSL_MASK) | vol1;
! 526:
! 527: rA0 = block_fnum & 0xFF;
! 528: rB0 = (block_fnum >> 8) | OPL_KEYON_BIT;
! 529:
! 530: v->rB0 = rB0;
! 531:
! 532: fbc = p->ops[OO_FB_CONN];
! 533: if (sc->model == OPL_3) {
! 534: fbc &= ~OPL_STEREO_BITS;
! 535: /* XXX use pan */
! 536: fbc |= OPL_VOICE_TO_LEFT | OPL_VOICE_TO_RIGHT;
! 537: }
! 538: opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, voice, fbc);
! 539:
! 540: opl_set_op_reg(sc, OPL_AM_VIB, voice, 0, r20m);
! 541: opl_set_op_reg(sc, OPL_AM_VIB, voice, 1, r20c);
! 542: opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, r40m);
! 543: opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, r40c);
! 544: opl_set_ch_reg(sc, OPL_FNUM_LOW, voice, rA0);
! 545: opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, rB0);
! 546: }
! 547:
! 548: void
! 549: oplsyn_noteoff(ms, voice, note, vel)
! 550: midisyn *ms;
! 551: u_int32_t voice, note, vel;
! 552: {
! 553: struct opl_softc *sc = ms->data;
! 554: struct opl_voice *v;
! 555:
! 556: DPRINTFN(3, ("oplsyn_noteoff: %p %d %d\n", sc, voice,
! 557: MIDISYN_FREQ_TO_HZ(note)));
! 558:
! 559: #ifdef DIAGNOSTIC
! 560: if (voice < 0 || voice >= sc->syn.nvoice) {
! 561: printf("oplsyn_noteoff: bad voice %d\n", voice);
! 562: return;
! 563: }
! 564: #endif
! 565: v = &sc->voices[voice];
! 566: opl_set_ch_reg(sc, 0xB0, voice, v->rB0 & ~OPL_KEYON_BIT);
! 567: }
! 568:
! 569: void
! 570: oplsyn_keypressure(ms, voice, note, vel)
! 571: midisyn *ms;
! 572: u_int32_t voice, note, vel;
! 573: {
! 574: #ifdef AUDIO_DEBUG
! 575: struct opl_softc *sc = ms->data;
! 576: DPRINTFN(1, ("oplsyn_keypressure: %p %d\n", sc, note));
! 577: #endif
! 578: }
! 579:
! 580: void
! 581: oplsyn_ctlchange(ms, voice, parm, w14)
! 582: midisyn *ms;
! 583: u_int32_t voice, parm, w14;
! 584: {
! 585: #ifdef AUDIO_DEBUG
! 586: struct opl_softc *sc = ms->data;
! 587: DPRINTFN(1, ("oplsyn_ctlchange: %p %d\n", sc, voice));
! 588: #endif
! 589: }
! 590:
! 591: void
! 592: oplsyn_pitchbend(ms, voice, parm, x)
! 593: midisyn *ms;
! 594: u_int32_t voice, parm, x;
! 595: {
! 596: #ifdef AUDIO_DEBUG
! 597: struct opl_softc *sc = ms->data;
! 598: DPRINTFN(1, ("oplsyn_pitchbend: %p %d\n", sc, voice));
! 599: #endif
! 600: }
! 601:
! 602: void
! 603: oplsyn_loadpatch(ms, sysex, uio)
! 604: midisyn *ms;
! 605: struct sysex_info *sysex;
! 606: struct uio *uio;
! 607: {
! 608: #if 0
! 609: struct opl_softc *sc = ms->data;
! 610: struct sbi_instrument ins;
! 611:
! 612: DPRINTFN(1, ("oplsyn_loadpatch: %p\n", sc));
! 613:
! 614: memcpy(&ins, sysex, sizeof *sysex);
! 615: if (uio->uio_resid >= sizeof ins - sizeof *sysex)
! 616: return EINVAL;
! 617: uiomove((char *)&ins + sizeof *sysex, sizeof ins - sizeof *sysex, uio);
! 618: /* XXX */
! 619: #endif
! 620: }
CVSweb