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