Home | History | Annotate | Line # | Download | only in ic
      1 /*	$NetBSD: opl.c,v 1.44 2023/05/10 21:30:50 riastradh Exp $	*/
      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 (at) 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: opl.c,v 1.44 2023/05/10 21:30:50 riastradh 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/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/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(struct opl_softc *sc)
    142 {
    143 	int i;
    144 
    145 	KASSERT(sc->dev != NULL);
    146 	KASSERT(sc->lock != NULL);
    147 
    148 	mutex_enter(sc->lock);
    149 	i = opl_find(sc);
    150 	mutex_exit(sc->lock);
    151 	if (i == 0) {
    152 		aprint_error("\nopl: find failed\n");
    153 		return;
    154 	}
    155 
    156 	mutex_enter(sc->lock);
    157 	opl_reset(sc);
    158 	mutex_exit(sc->lock);
    159 
    160 	sc->syn.mets = &opl3_midi;
    161 	size_t len = strlen(sc->syn.name);
    162 	snprintf(sc->syn.name + len, sizeof(sc->syn.name) - len,
    163 	    "Yamaha OPL%d", 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_init(&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->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->dev);
    190 }
    191 
    192 int
    193 opl_detach(struct opl_softc *sc, int flags)
    194 {
    195 	int error;
    196 
    197 	error = config_detach_children(sc->dev, flags);
    198 	if (error)
    199 		return error;
    200 
    201 	return 0;
    202 }
    203 
    204 static void
    205 opl_command(struct opl_softc *sc, int offs, int addr, int data)
    206 {
    207 	DPRINTFN(4, ("opl_command: sc=%p, offs=%d addr=0x%02x data=0x%02x\n",
    208 		     sc, offs, addr, data));
    209 
    210 	KASSERT(!sc->lock || mutex_owned(sc->lock));
    211 
    212 	offs += sc->offs;
    213 	bus_space_write_1(sc->iot, sc->ioh, OPL_ADDR+offs, addr);
    214 	if (sc->model == OPL_2)
    215 		delay(10);
    216 	else
    217 		delay(6);
    218 	bus_space_write_1(sc->iot, sc->ioh, OPL_DATA+offs, data);
    219 	if (sc->model == OPL_2)
    220 		delay(30);
    221 	else
    222 		delay(6);
    223 }
    224 
    225 int
    226 opl_match(bus_space_tag_t iot, bus_space_handle_t ioh, int offs)
    227 {
    228 	struct opl_softc *sc;
    229 	int rv;
    230 
    231 	sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
    232 	sc->iot = iot;
    233 	sc->ioh = ioh;
    234 	sc->offs = offs;
    235 	rv = opl_find(sc);
    236 	kmem_free(sc, sizeof(*sc));
    237 	return rv;
    238 }
    239 
    240 int
    241 opl_find(struct opl_softc *sc)
    242 {
    243 	u_int8_t status1, status2;
    244 
    245 	DPRINTFN(2,("opl_find: ioh=0x%x\n", (int)sc->ioh));
    246 	sc->model = OPL_2;	/* worst case assumption */
    247 
    248 	/* Reset timers 1 and 2 */
    249 	opl_command(sc, OPL_L, OPL_TIMER_CONTROL,
    250 		    OPL_TIMER1_MASK | OPL_TIMER2_MASK);
    251 	/* Reset the IRQ of the FM chip */
    252 	opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
    253 
    254 	/* get status bits */
    255 	status1 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs);
    256 
    257 	opl_command(sc, OPL_L, OPL_TIMER1, -2); /* wait 2 ticks */
    258 	opl_command(sc, OPL_L, OPL_TIMER_CONTROL, /* start timer1 */
    259 		    OPL_TIMER1_START | OPL_TIMER2_MASK);
    260 	delay(1000);		/* wait for timer to expire */
    261 
    262 	/* get status bits again */
    263 	status2 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs);
    264 
    265 	opl_command(sc, OPL_L, OPL_TIMER_CONTROL,
    266 		    OPL_TIMER1_MASK | OPL_TIMER2_MASK);
    267 	opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
    268 
    269 	DPRINTFN(2,("opl_find: %02x %02x\n", status1, status2));
    270 
    271 	if ((status1 & OPL_STATUS_MASK) != 0 ||
    272 	    (status2 & OPL_STATUS_MASK) != (OPL_STATUS_IRQ | OPL_STATUS_FT1))
    273 		return (0);
    274 
    275 	switch(status1) {
    276 	case 0x00:
    277 	case 0x0f:
    278 		sc->model = OPL_3;
    279 		break;
    280 	case 0x06:
    281 		sc->model = OPL_2;
    282 		break;
    283 	default:
    284 		return (0);
    285 	}
    286 
    287 	DPRINTFN(2,("opl_find: OPL%d at 0x%x detected\n",
    288 		    sc->model, (int)sc->ioh));
    289 	return (1);
    290 }
    291 
    292 /*
    293  * idea: opl_command does a lot of busywaiting, and the driver typically sets
    294  *       a lot of registers each time a voice-attack happens. some kind of
    295  *       caching to remember what was last written to each register could save
    296  *       a lot of cpu. It would have to be smart enough not to interfere with
    297  *       any necessary sequences of register access expected by the hardware...
    298  */
    299 void
    300 opl_set_op_reg(struct opl_softc *sc, int base, int voice, int op, u_char value)
    301 {
    302 	struct opl_voice *v = &sc->voices[voice];
    303 
    304 	KASSERT(mutex_owned(sc->lock));
    305 
    306 	opl_command(sc, v->iooffs, base + v->op[op], value);
    307 }
    308 
    309 void
    310 opl_set_ch_reg(struct opl_softc *sc, int base, int voice, u_char value)
    311 {
    312 	struct opl_voice *v = &sc->voices[voice];
    313 
    314 	KASSERT(mutex_owned(sc->lock));
    315 
    316 	opl_command(sc, v->iooffs, base + v->voiceno, value);
    317 }
    318 
    319 
    320 void
    321 opl_load_patch(struct opl_softc *sc, int v)
    322 {
    323 	const struct opl_operators *p = sc->voices[v].patch;
    324 
    325 	KASSERT(mutex_owned(sc->lock));
    326 
    327 	opl_set_op_reg(sc, OPL_AM_VIB,          v, 0, p->ops[OO_CHARS+0]);
    328 	opl_set_op_reg(sc, OPL_AM_VIB,          v, 1, p->ops[OO_CHARS+1]);
    329 	opl_set_op_reg(sc, OPL_KSL_LEVEL,       v, 0, p->ops[OO_KSL_LEV+0]);
    330 	opl_set_op_reg(sc, OPL_KSL_LEVEL,       v, 1, p->ops[OO_KSL_LEV+1]);
    331 	opl_set_op_reg(sc, OPL_ATTACK_DECAY,    v, 0, p->ops[OO_ATT_DEC+0]);
    332 	opl_set_op_reg(sc, OPL_ATTACK_DECAY,    v, 1, p->ops[OO_ATT_DEC+1]);
    333 	opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 0, p->ops[OO_SUS_REL+0]);
    334 	opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 1, p->ops[OO_SUS_REL+1]);
    335 	opl_set_op_reg(sc, OPL_WAVE_SELECT,     v, 0, p->ops[OO_WAV_SEL+0]);
    336 	opl_set_op_reg(sc, OPL_WAVE_SELECT,     v, 1, p->ops[OO_WAV_SEL+1]);
    337 	opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, v, p->ops[OO_FB_CONN]);
    338 }
    339 
    340 uint32_t
    341 opl_get_block_fnum(midipitch_t mp)
    342 {
    343 	midihz18_t hz18;
    344 	uint32_t block;
    345 	uint32_t f_num;
    346 
    347 	/*
    348 	 * We can get to about note 30 before needing to switch from block 0.
    349 	 * Thereafter, switch block every octave; that will keep f_num in the
    350 	 * upper end of its range, making the most bits available for
    351 	 * resolution.
    352 	 */
    353 	block = ( mp - MIDIPITCH_FROM_KEY(19) ) / MIDIPITCH_OCTAVE;
    354 	if ( block > 7 )	/* subtract wrapped */
    355 		block = 0;
    356 	/*
    357 	 * Could subtract block*MIDIPITCH_OCTAVE here, or >>block later. Later.
    358 	 */
    359 
    360 	hz18 = MIDIPITCH_TO_HZ18(mp);
    361 	hz18 >>= block;
    362 
    363 	/*
    364 	 * The formula in the manual is f_num = ((hz<<19)/fs)>>(block-1) (though
    365 	 * block==0 implies >>-1 which is a C unspecified result). As we already
    366 	 * have hz<<18 and I omitted the -1 when shifting above, what's left to
    367 	 * do now is multiply by 4 and divide by fs, the sampling frequency of
    368 	 * the chip. fs is the master clock frequency fM / 288, fM is 14.32 MHz
    369 	 * so fs is a goofy number around 49.7kHz. The 5th convergent of the
    370 	 * continued fraction matches 4/fs to 9+ significant figures. Doing the
    371 	 * shift first (above) ensures there's room in hz18 to multiply by 9.
    372 	 */
    373 
    374 	f_num = (9 * hz18) / 111875;
    375 	return ((block << 10) | f_num);
    376 }
    377 
    378 
    379 void
    380 opl_reset(struct opl_softc *sc)
    381 {
    382 	int i;
    383 
    384 	KASSERT(mutex_owned(sc->lock));
    385 
    386 	for (i = 1; i <= OPL_MAXREG; i++)
    387 		opl_command(sc, OPL_L, OPL_KEYON_BLOCK + i, 0);
    388 
    389 	opl_command(sc, OPL_L, OPL_TEST, OPL_ENABLE_WAVE_SELECT);
    390 	opl_command(sc, OPL_L, OPL_PERCUSSION, 0);
    391 	if (sc->model == OPL_3) {
    392 		opl_command(sc, OPL_R, OPL_MODE, OPL3_ENABLE);
    393 		opl_command(sc, OPL_R,OPL_CONNECTION_SELECT,OPL_NOCONNECTION);
    394 	}
    395 
    396 	for (i = 0; i < MIDI_MAX_CHANS; i++)
    397 		sc->pan[i] = OPL_VOICE_TO_LEFT | OPL_VOICE_TO_RIGHT;
    398 }
    399 
    400 int
    401 oplsyn_open(midisyn *ms, int flags)
    402 {
    403 	struct opl_softc *sc = ms->data;
    404 
    405 	KASSERT(mutex_owned(sc->lock));
    406 
    407 	DPRINTFN(2, ("oplsyn_open: %d\n", flags));
    408 
    409 #ifndef AUDIO_NO_POWER_CTL
    410 	if (sc->powerctl)
    411 		sc->powerctl(sc->powerarg, 1);
    412 #endif
    413 	opl_reset(ms->data);
    414 	if (sc->spkrctl)
    415 		sc->spkrctl(sc->spkrarg, 1);
    416 	return (0);
    417 }
    418 
    419 void
    420 oplsyn_close(midisyn *ms)
    421 {
    422 	struct opl_softc *sc = ms->data;
    423 
    424 	DPRINTFN(2, ("oplsyn_close:\n"));
    425 
    426 	KASSERT(mutex_owned(sc->lock));
    427 
    428 	/*opl_reset(ms->data);*/
    429 	if (sc->spkrctl)
    430 		sc->spkrctl(sc->spkrarg, 0);
    431 #ifndef AUDIO_NO_POWER_CTL
    432 	if (sc->powerctl)
    433 		sc->powerctl(sc->powerarg, 0);
    434 #endif
    435 }
    436 
    437 #if 0
    438 void
    439 oplsyn_getinfo(void *addr, 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(void *addr)
    453 {
    454 	struct opl_softc *sc = addr;
    455 
    456 	KASSERT(mutex_owned(sc->lock));
    457 
    458 	DPRINTFN(3, ("oplsyn_reset:\n"));
    459 	opl_reset(sc);
    460 }
    461 
    462 int
    463 opl_calc_vol(int regbyte, int16_t level_cB)
    464 {
    465 	int level = regbyte & OPL_TOTAL_LEVEL_MASK;
    466 
    467 	/*
    468 	 * level is a six-bit attenuation, from 0 (full output)
    469 	 * to -48dB (but without the minus sign) in steps of .75 dB.
    470 	 * We'll just add level_cB, after scaling it because it's
    471 	 * in centibels instead and has the customary minus sign.
    472 	 */
    473 
    474 	level += ( -4 * level_cB ) / 30;
    475 
    476 	if (level > OPL_TOTAL_LEVEL_MASK)
    477 		level = OPL_TOTAL_LEVEL_MASK;
    478 	if (level < 0)
    479 		level = 0;
    480 
    481 	return level & OPL_TOTAL_LEVEL_MASK;
    482 }
    483 
    484 #define OPLACT_ARTICULATE 1
    485 #define OPLACT_PITCH      2
    486 #define OPLACT_LEVEL      4
    487 
    488 void
    489 oplsyn_attackv(midisyn *ms,
    490                uint_fast16_t voice, midipitch_t mp, int16_t level_cB)
    491 {
    492 	oplsyn_setv(ms, voice, mp, level_cB,
    493 		    OPLACT_ARTICULATE | OPLACT_PITCH | OPLACT_LEVEL);
    494 }
    495 
    496 static void
    497 oplsyn_repitchv(midisyn *ms, uint_fast16_t voice, midipitch_t mp)
    498 {
    499 	oplsyn_setv(ms, voice, mp, 0, OPLACT_PITCH);
    500 }
    501 
    502 static void
    503 oplsyn_relevelv(midisyn *ms, uint_fast16_t voice, int16_t level_cB)
    504 {
    505 	oplsyn_setv(ms, voice, 0, level_cB, OPLACT_LEVEL);
    506 }
    507 
    508 static void
    509 oplsyn_setv(midisyn *ms,
    510             uint_fast16_t voice, midipitch_t mp, int16_t level_cB, int act)
    511 {
    512 	struct opl_softc *sc = ms->data;
    513 	struct opl_voice *v;
    514 	const struct opl_operators *p;
    515 	u_int32_t block_fnum;
    516 	int mult;
    517 	int c_mult, m_mult;
    518 	u_int32_t chan;
    519 	u_int8_t chars0, chars1, ksl0, ksl1, fbc;
    520 	u_int8_t r20m, r20c, r40m, r40c, rA0, rB0;
    521 	u_int8_t vol0, vol1;
    522 
    523 	KASSERT(mutex_owned(sc->lock));
    524 
    525 	DPRINTFN(3, ("%s: %p %d %u %d\n", __func__, sc, voice,
    526 		     mp, level_cB));
    527 
    528 #ifdef DIAGNOSTIC
    529 	if (voice >= sc->syn.nvoice) {
    530 		printf("%s: bad voice %d\n", __func__, voice);
    531 		return;
    532 	}
    533 #endif
    534 	v = &sc->voices[voice];
    535 
    536 	if ( act & OPLACT_ARTICULATE ) {
    537 		/* Turn off old note */
    538 		opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 0, 0xff);
    539 		opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 1, 0xff);
    540 		opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice,    0);
    541 
    542 		chan = MS_GETCHAN(&ms->voices[voice]);
    543 		p = &opl2_instrs[ms->pgms[chan]];
    544 		v->patch = p;
    545 		opl_load_patch(sc, voice);
    546 
    547 		fbc = p->ops[OO_FB_CONN];
    548 		if (sc->model == OPL_3) {
    549 			fbc &= ~OPL_STEREO_BITS;
    550 			fbc |= sc->pan[chan];
    551 		}
    552 		opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, voice, fbc);
    553 	} else
    554 		p = v->patch;
    555 
    556 	if ( act & OPLACT_LEVEL ) {
    557 		/* 2 voice */
    558 		ksl0 = p->ops[OO_KSL_LEV+0];
    559 		ksl1 = p->ops[OO_KSL_LEV+1];
    560 		if (p->ops[OO_FB_CONN] & 0x01) {
    561 			vol0 = opl_calc_vol(ksl0, level_cB);
    562 			vol1 = opl_calc_vol(ksl1, level_cB);
    563 		} else {
    564 			vol0 = ksl0;
    565 			vol1 = opl_calc_vol(ksl1, level_cB);
    566 		}
    567 		r40m = (ksl0 & OPL_KSL_MASK) | vol0;
    568 		r40c = (ksl1 & OPL_KSL_MASK) | vol1;
    569 
    570 		opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 0, r40m);
    571 		opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 1, r40c);
    572 	}
    573 
    574 	if ( act & OPLACT_PITCH ) {
    575 		mult = 1;
    576 		if ( mp > MIDIPITCH_FROM_KEY(114) ) { /* out of mult 1 range */
    577 			mult = 4;	/* will cover remaining MIDI range */
    578 			mp -= 2*MIDIPITCH_OCTAVE;
    579 		}
    580 
    581 		block_fnum = opl_get_block_fnum(mp);
    582 
    583 		chars0 = p->ops[OO_CHARS+0];
    584 		chars1 = p->ops[OO_CHARS+1];
    585 		m_mult = (chars0 & OPL_MULTIPLE_MASK) * mult;
    586 		c_mult = (chars1 & OPL_MULTIPLE_MASK) * mult;
    587 
    588 		if ( 4 == mult ) {
    589 			if ( 0 == m_mult )  /* The OPL uses 0 to represent .5 */
    590 				m_mult = 2; /* but of course 0*mult above did */
    591 			if ( 0 == c_mult )  /* not DTRT */
    592 				c_mult = 2;
    593 		}
    594 
    595 		if ((m_mult > 15) || (c_mult > 15)) {
    596 			printf("%s: frequency out of range %u (mult %d)\n",
    597 			       __func__, mp, mult);
    598 			return;
    599 		}
    600 		r20m = (chars0 &~ OPL_MULTIPLE_MASK) | m_mult;
    601 		r20c = (chars1 &~ OPL_MULTIPLE_MASK) | c_mult;
    602 
    603 		rA0  = block_fnum & 0xFF;
    604 		rB0  = (block_fnum >> 8) | OPL_KEYON_BIT;
    605 
    606 		v->rB0 = rB0;
    607 
    608 		opl_set_op_reg(sc, OPL_AM_VIB,      voice, 0, r20m);
    609 		opl_set_op_reg(sc, OPL_AM_VIB,      voice, 1, r20c);
    610 
    611 		opl_set_ch_reg(sc, OPL_FNUM_LOW,    voice,    rA0);
    612 		opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice,    rB0);
    613 	}
    614 }
    615 
    616 void
    617 oplsyn_releasev(midisyn *ms, uint_fast16_t voice, uint_fast8_t vel)
    618 {
    619 	struct opl_softc *sc = ms->data;
    620 	struct opl_voice *v;
    621 
    622 	KASSERT(mutex_owned(sc->lock));
    623 
    624 	DPRINTFN(1, ("%s: %p %d\n", __func__, sc, voice));
    625 
    626 #ifdef DIAGNOSTIC
    627 	if (voice >= sc->syn.nvoice) {
    628 		printf("oplsyn_noteoff: bad voice %d\n", voice);
    629 		return;
    630 	}
    631 #endif
    632 	v = &sc->voices[voice];
    633 	opl_set_ch_reg(sc, 0xB0, voice, v->rB0 & ~OPL_KEYON_BIT);
    634 }
    635 
    636 int
    637 oplsyn_ctlnotice(midisyn *ms,
    638 		 midictl_evt evt, uint_fast8_t chan, uint_fast16_t key)
    639 {
    640 
    641 	DPRINTFN(1, ("%s: %p %d\n", __func__, ms->data, chan));
    642 
    643 	switch (evt) {
    644 	case MIDICTL_RESET:
    645 		oplsyn_panhandler(ms, chan);
    646 		return 1;
    647 
    648 	case MIDICTL_CTLR:
    649 		switch (key) {
    650 		case MIDI_CTRL_PAN_MSB:
    651 			oplsyn_panhandler(ms, chan);
    652 			return 1;
    653 		}
    654 		return 0;
    655 	default:
    656 		return 0;
    657 	}
    658 }
    659 
    660 /* PROGRAM CHANGE midi event: */
    661 void
    662 oplsyn_programchange(midisyn *ms, uint_fast8_t chan, uint_fast8_t prog)
    663 {
    664 	/* sanity checks */
    665 	if (chan >= MIDI_MAX_CHANS)
    666 		return;
    667 
    668 	ms->pgms[chan] = prog;
    669 }
    670 
    671 void
    672 oplsyn_loadpatch(midisyn *ms, struct sysex_info *sysex, 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 
    688 static void
    689 oplsyn_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