xref: /netbsd-src/sys/dev/ic/opl.c (revision 8a8f936f250a330d54f8a24ed0e92aadf9743a7b)
1 /*	$NetBSD: opl.c,v 1.13 2001/09/29 13:56:04 augustss 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/param.h>
45 #include <sys/systm.h>
46 #include <sys/errno.h>
47 #include <sys/ioctl.h>
48 #include <sys/syslog.h>
49 #include <sys/device.h>
50 #include <sys/select.h>
51 
52 #include <machine/cpu.h>
53 #include <machine/bus.h>
54 
55 #include <sys/audioio.h>
56 #include <sys/midiio.h>
57 #include <dev/audio_if.h>
58 
59 #include <dev/midi_if.h>
60 #include <dev/midivar.h>
61 #include <dev/midisynvar.h>
62 
63 #include <dev/ic/oplreg.h>
64 #include <dev/ic/oplvar.h>
65 
66 #ifdef AUDIO_DEBUG
67 #define DPRINTF(x)	if (opldebug) printf x
68 #define DPRINTFN(n,x)	if (opldebug >= (n)) printf x
69 int	opldebug = 0;
70 #else
71 #define DPRINTF(x)
72 #define DPRINTFN(n,x)
73 #endif
74 
75 struct real_voice {
76 	u_int8_t voice_num;
77 	u_int8_t voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */
78 	u_int8_t iooffs; /* I/O port (left or right side) */
79 	u_int8_t op[4]; /* Operator offsets */
80 };
81 
82 const struct opl_voice voicetab[] = {
83 /*       No    I/O offs	OP1	OP2	OP3   OP4	*/
84 /*	---------------------------------------------	*/
85 	{ 0,   OPL_L,	{0x00,	0x03,	0x08, 0x0b}},
86 	{ 1,   OPL_L,	{0x01,	0x04,	0x09, 0x0c}},
87 	{ 2,   OPL_L,	{0x02,	0x05,	0x0a, 0x0d}},
88 
89 	{ 3,   OPL_L,	{0x08,	0x0b,	0x00, 0x00}},
90 	{ 4,   OPL_L,	{0x09,	0x0c,	0x00, 0x00}},
91 	{ 5,   OPL_L,	{0x0a,	0x0d,	0x00, 0x00}},
92 
93 	{ 6,   OPL_L,	{0x10,	0x13,	0x00, 0x00}},
94 	{ 7,   OPL_L,	{0x11,	0x14,	0x00, 0x00}},
95 	{ 8,   OPL_L,	{0x12,	0x15,	0x00, 0x00}},
96 
97 	{ 0,   OPL_R,	{0x00,	0x03,	0x08, 0x0b}},
98 	{ 1,   OPL_R,	{0x01,	0x04,	0x09, 0x0c}},
99 	{ 2,   OPL_R,	{0x02,	0x05,	0x0a, 0x0d}},
100 	{ 3,   OPL_R,	{0x08,	0x0b,	0x00, 0x00}},
101 	{ 4,   OPL_R,	{0x09,	0x0c,	0x00, 0x00}},
102 	{ 5,   OPL_R,	{0x0a,	0x0d,	0x00, 0x00}},
103 
104 	{ 6,   OPL_R,	{0x10,	0x13,	0x00, 0x00}},
105 	{ 7,   OPL_R,	{0x11,	0x14,	0x00, 0x00}},
106 	{ 8,   OPL_R,	{0x12,	0x15,	0x00, 0x00}}
107 };
108 
109 static void opl_command(struct opl_softc *, int, int, int);
110 void opl_reset(struct opl_softc *);
111 void opl_freq_to_fnum (int freq, int *block, int *fnum);
112 
113 int oplsyn_open __P((midisyn *ms, int));
114 void oplsyn_close __P((midisyn *));
115 void oplsyn_reset __P((void *));
116 void oplsyn_noteon __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
117 void oplsyn_noteoff __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
118 void oplsyn_keypressure __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
119 void oplsyn_ctlchange __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
120 void oplsyn_programchange __P((midisyn *, u_int32_t, u_int32_t));
121 void oplsyn_pitchbend __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
122 void oplsyn_loadpatch __P((midisyn *, struct sysex_info *, struct uio *));
123 
124 
125 void opl_set_op_reg __P((struct opl_softc *, int, int, int, u_char));
126 void opl_set_ch_reg __P((struct opl_softc *, int, int, u_char));
127 void opl_load_patch __P((struct opl_softc *, int));
128 u_int32_t opl_get_block_fnum __P((int freq));
129 int opl_calc_vol __P((int regbyte, int volume, int main_vol));
130 
131 struct midisyn_methods opl3_midi = {
132 	oplsyn_open,
133 	oplsyn_close,
134 	0,
135 	0,
136 	oplsyn_noteon,
137 	oplsyn_noteoff,
138 	oplsyn_keypressure,
139 	oplsyn_ctlchange,
140 	oplsyn_programchange,
141 	0,
142 	oplsyn_pitchbend,
143 	0
144 };
145 
146 void
147 opl_attach(sc)
148 	struct opl_softc *sc;
149 {
150 	int i;
151 
152 	if (!opl_find(sc)) {
153 		printf("\nopl: find failed\n");
154 		return;
155 	}
156 
157 	sc->syn.mets = &opl3_midi;
158 	sprintf(sc->syn.name, "%sYamaha OPL%d", sc->syn.name, sc->model);
159 	sc->syn.data = sc;
160 	sc->syn.nvoice = sc->model == OPL_2 ? OPL2_NVOICE : OPL3_NVOICE;
161 	sc->syn.flags =  MS_DOALLOC | MS_FREQXLATE;
162 	midisyn_attach(&sc->mididev, &sc->syn);
163 
164 	/* Set up voice table */
165 	for (i = 0; i < OPL3_NVOICE; i++)
166 		sc->voices[i] = voicetab[i];
167 
168 	opl_reset(sc);
169 
170 	printf(": model OPL%d\n", sc->model);
171 
172 	sc->sc_mididev =
173 	    midi_attach_mi(&midisyn_hw_if, &sc->syn, &sc->mididev.dev);
174 }
175 
176 int
177 opl_detach(sc, flags)
178 	struct opl_softc *sc;
179 	int flags;
180 {
181 	int rv = 0;
182 
183 	if (sc->sc_mididev != NULL)
184 		rv = config_detach(sc->sc_mididev, flags);
185 
186 	return(rv);
187 }
188 
189 static void
190 opl_command(sc, offs, addr, data)
191 	struct opl_softc *sc;
192 	int offs;
193 	int addr, 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_find(sc)
212 	struct opl_softc *sc;
213 {
214 	u_int8_t status1, status2;
215 
216 	DPRINTFN(2,("opl_find: ioh=0x%x\n", (int)sc->ioh));
217 	sc->model = OPL_2;	/* worst case assumtion */
218 
219 	/* Reset timers 1 and 2 */
220 	opl_command(sc, OPL_L, OPL_TIMER_CONTROL,
221 		    OPL_TIMER1_MASK | OPL_TIMER2_MASK);
222 	/* Reset the IRQ of the FM chip */
223 	opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
224 
225 	/* get status bits */
226 	status1 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs);
227 
228 	opl_command(sc, OPL_L, OPL_TIMER1, -2); /* wait 2 ticks */
229 	opl_command(sc, OPL_L, OPL_TIMER_CONTROL, /* start timer1 */
230 		    OPL_TIMER1_START | OPL_TIMER2_MASK);
231 	delay(1000);		/* wait for timer to expire */
232 
233 	/* get status bits again */
234 	status2 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs);
235 
236 	opl_command(sc, OPL_L, OPL_TIMER_CONTROL,
237 		    OPL_TIMER1_MASK | OPL_TIMER2_MASK);
238 	opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
239 
240 	DPRINTFN(2,("opl_find: %02x %02x\n", status1, status2));
241 
242 	if ((status1 & OPL_STATUS_MASK) != 0 ||
243 	    (status2 & OPL_STATUS_MASK) != (OPL_STATUS_IRQ | OPL_STATUS_FT1))
244 		return (0);
245 
246 	switch(status1) {
247 	case 0x00:
248 	case 0x0f:
249 		sc->model = OPL_3;
250 		break;
251 	case 0x06:
252 		sc->model = OPL_2;
253 		break;
254 	default:
255 		return (0);
256 	}
257 
258 	DPRINTFN(2,("opl_find: OPL%d at 0x%x detected\n",
259 		    sc->model, (int)sc->ioh));
260 	return (1);
261 }
262 
263 void
264 opl_set_op_reg(sc, base, voice, op, value)
265 	struct opl_softc *sc;
266 	int base;
267 	int voice;
268 	int op;
269 	u_char value;
270 {
271 	struct opl_voice *v = &sc->voices[voice];
272 	opl_command(sc, v->iooffs, base + v->op[op], value);
273 }
274 
275 void
276 opl_set_ch_reg(sc, base, voice, value)
277 	struct opl_softc *sc;
278 	int base;
279 	int voice;
280 	u_char value;
281 {
282 	struct opl_voice *v = &sc->voices[voice];
283 	opl_command(sc, v->iooffs, base + v->voiceno, value);
284 }
285 
286 
287 void
288 opl_load_patch(sc, v)
289 	struct opl_softc *sc;
290 	int v;
291 {
292 	const struct opl_operators *p = sc->voices[v].patch;
293 
294 	opl_set_op_reg(sc, OPL_AM_VIB,          v, 0, p->ops[OO_CHARS+0]);
295 	opl_set_op_reg(sc, OPL_AM_VIB,          v, 1, p->ops[OO_CHARS+1]);
296 	opl_set_op_reg(sc, OPL_KSL_LEVEL,       v, 0, p->ops[OO_KSL_LEV+0]);
297 	opl_set_op_reg(sc, OPL_KSL_LEVEL,       v, 1, p->ops[OO_KSL_LEV+1]);
298 	opl_set_op_reg(sc, OPL_ATTACK_DECAY,    v, 0, p->ops[OO_ATT_DEC+0]);
299 	opl_set_op_reg(sc, OPL_ATTACK_DECAY,    v, 1, p->ops[OO_ATT_DEC+1]);
300 	opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 0, p->ops[OO_SUS_REL+0]);
301 	opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 1, p->ops[OO_SUS_REL+1]);
302 	opl_set_op_reg(sc, OPL_WAVE_SELECT,     v, 0, p->ops[OO_WAV_SEL+0]);
303 	opl_set_op_reg(sc, OPL_WAVE_SELECT,     v, 1, p->ops[OO_WAV_SEL+1]);
304 	opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, v, p->ops[OO_FB_CONN]);
305 }
306 
307 #define OPL_FNUM_FAIL 0xffff
308 u_int32_t
309 opl_get_block_fnum(freq)
310 	int freq;
311 {
312 	u_int32_t f_num = freq / 3125;
313 	u_int32_t  block = 0;
314 
315 	while (f_num > 0x3ff && block < 8) {
316 		block++;
317 		f_num >>= 1;
318 	}
319 
320 	if (block > 7)
321 		return (OPL_FNUM_FAIL);
322 	else
323 		return ((block << 10) | f_num);
324   }
325 
326 
327 void
328 opl_reset(sc)
329 	struct opl_softc *sc;
330 {
331 	int i;
332 
333 	for (i = 1; i <= OPL_MAXREG; i++)
334 		opl_command(sc, OPL_L, OPL_KEYON_BLOCK + i, 0);
335 
336 	opl_command(sc, OPL_L, OPL_TEST, OPL_ENABLE_WAVE_SELECT);
337 	opl_command(sc, OPL_L, OPL_PERCUSSION, 0);
338 	if (sc->model == OPL_3) {
339 		opl_command(sc, OPL_R, OPL_MODE, OPL3_ENABLE);
340 		opl_command(sc, OPL_R,OPL_CONNECTION_SELECT,OPL_NOCONNECTION);
341 	}
342 
343 	sc->volume = 64;
344 }
345 
346 int
347 oplsyn_open(ms, flags)
348 	midisyn *ms;
349 	int flags;
350 {
351 	struct opl_softc *sc = ms->data;
352 
353 	DPRINTFN(2, ("oplsyn_open: %d\n", flags));
354 
355 #ifndef AUDIO_NO_POWER_CTL
356 	if (sc->powerctl)
357 		sc->powerctl(sc->powerarg, 1);
358 #endif
359 	opl_reset(ms->data);
360 	if (sc->spkrctl)
361 		sc->spkrctl(sc->spkrarg, 1);
362 	return (0);
363 }
364 
365 void
366 oplsyn_close(ms)
367 	midisyn *ms;
368 {
369 	struct opl_softc *sc = ms->data;
370 
371 	DPRINTFN(2, ("oplsyn_close:\n"));
372 
373 	/*opl_reset(ms->data);*/
374 	if (sc->spkrctl)
375 		sc->spkrctl(sc->spkrarg, 0);
376 #ifndef AUDIO_NO_POWER_CTL
377 	if (sc->powerctl)
378 		sc->powerctl(sc->powerarg, 0);
379 #endif
380 }
381 
382 #if 0
383 void
384 oplsyn_getinfo(addr, sd)
385 	void *addr;
386 	struct synth_dev *sd;
387 {
388 	struct opl_softc *sc = addr;
389 
390 	sd->name = sc->model == OPL_2 ? "Yamaha OPL2" : "Yamaha OPL3";
391 	sd->type = SYNTH_TYPE_FM;
392 	sd->subtype = sc->model == OPL_2 ? SYNTH_SUB_FM_TYPE_ADLIB
393 		: SYNTH_SUB_FM_TYPE_OPL3;
394 	sd->capabilities = 0;
395 }
396 #endif
397 
398 void
399 oplsyn_reset(addr)
400 	void *addr;
401 {
402 	struct opl_softc *sc = addr;
403 	DPRINTFN(3, ("oplsyn_reset:\n"));
404 	opl_reset(sc);
405 }
406 
407 const int8_t opl_volume_table[128] =
408     {-64, -48, -40, -35, -32, -29, -27, -26,
409      -24, -23, -21, -20, -19, -18, -18, -17,
410      -16, -15, -15, -14, -13, -13, -12, -12,
411      -11, -11, -10, -10, -10, -9, -9, -8,
412      -8, -8, -7, -7, -7, -6, -6, -6,
413      -5, -5, -5, -5, -4, -4, -4, -4,
414      -3, -3, -3, -3, -2, -2, -2, -2,
415      -2, -1, -1, -1, -1, 0, 0, 0,
416      0, 0, 0, 1, 1, 1, 1, 1,
417      1, 2, 2, 2, 2, 2, 2, 2,
418      3, 3, 3, 3, 3, 3, 3, 4,
419      4, 4, 4, 4, 4, 4, 4, 5,
420      5, 5, 5, 5, 5, 5, 5, 5,
421      6, 6, 6, 6, 6, 6, 6, 6,
422      6, 7, 7, 7, 7, 7, 7, 7,
423      7, 7, 7, 8, 8, 8, 8, 8};
424 
425 int
426 opl_calc_vol(regbyte, volume, mainvol)
427 	int regbyte;
428 	int volume;
429 	int mainvol;
430 {
431 	int level = ~regbyte & OPL_TOTAL_LEVEL_MASK;
432 
433 	if (mainvol > 127)
434 		mainvol = 127;
435 
436 	volume = (volume * mainvol) / 127;
437 
438 	if (level)
439 		level += opl_volume_table[volume];
440 
441 	if (level > OPL_TOTAL_LEVEL_MASK)
442 		level = OPL_TOTAL_LEVEL_MASK;
443 	if (level < 0)
444 		level = 0;
445 
446 	return (~level & OPL_TOTAL_LEVEL_MASK);
447 }
448 
449 void
450 oplsyn_noteon(ms, voice, freq, vel)
451 	midisyn *ms;
452 	u_int32_t voice, freq, vel;
453 {
454 	struct opl_softc *sc = ms->data;
455 	struct opl_voice *v;
456 	const struct opl_operators *p;
457 	u_int32_t block_fnum;
458 	int mult;
459 	int c_mult, m_mult;
460 	u_int8_t chars0, chars1, ksl0, ksl1, fbc;
461 	u_int8_t r20m, r20c, r40m, r40c, rA0, rB0;
462 	u_int8_t vol0, vol1;
463 
464 	DPRINTFN(3, ("oplsyn_noteon: %p %d %d\n", sc, voice,
465 		     MIDISYN_FREQ_TO_HZ(freq)));
466 
467 #ifdef DIAGNOSTIC
468 	if (voice < 0 || voice >= sc->syn.nvoice) {
469 		printf("oplsyn_noteon: bad voice %d\n", voice);
470 		return;
471 	}
472 #endif
473 	/* Turn off old note */
474 	opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 0, 0xff);
475 	opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 1, 0xff);
476 	opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice,    0);
477 
478 	v = &sc->voices[voice];
479 
480 	p = &opl2_instrs[MS_GETPGM(ms, voice)];
481 	v->patch = p;
482 	opl_load_patch(sc, voice);
483 
484 	mult = 1;
485 	for (;;) {
486 		block_fnum = opl_get_block_fnum(freq / mult);
487 		if (block_fnum != OPL_FNUM_FAIL)
488 			break;
489 		mult *= 2;
490 		if (mult == 16)
491 			mult = 15;
492 	}
493 
494 	chars0 = p->ops[OO_CHARS+0];
495 	chars1 = p->ops[OO_CHARS+1];
496 	m_mult = (chars0 & OPL_MULTIPLE_MASK) * mult;
497 	c_mult = (chars1 & OPL_MULTIPLE_MASK) * mult;
498 	if ((block_fnum == OPL_FNUM_FAIL) || (m_mult > 15) || (c_mult > 15)) {
499 		printf("oplsyn_noteon: frequency out of range %d\n",
500 		       MIDISYN_FREQ_TO_HZ(freq));
501 		return;
502 	}
503 	r20m = (chars0 &~ OPL_MULTIPLE_MASK) | m_mult;
504 	r20c = (chars1 &~ OPL_MULTIPLE_MASK) | c_mult;
505 
506 	/* 2 voice */
507 	ksl0 = p->ops[OO_KSL_LEV+0];
508 	ksl1 = p->ops[OO_KSL_LEV+1];
509 	if (p->ops[OO_FB_CONN] & 0x01) {
510 		vol0 = opl_calc_vol(ksl0, vel, sc->volume);
511 		vol1 = opl_calc_vol(ksl1, vel, sc->volume);
512 	} else {
513 		vol0 = ksl0;
514 		vol1 = opl_calc_vol(ksl1, vel, sc->volume);
515 	}
516 	r40m = (ksl0 & OPL_KSL_MASK) | vol0;
517 	r40c = (ksl1 & OPL_KSL_MASK) | vol1;
518 
519 	rA0  = block_fnum & 0xFF;
520 	rB0  = (block_fnum >> 8) | OPL_KEYON_BIT;
521 
522 	v->rB0 = rB0;
523 
524 	fbc = p->ops[OO_FB_CONN];
525 	if (sc->model == OPL_3) {
526 		fbc &= ~OPL_STEREO_BITS;
527 		/* XXX use pan */
528 		fbc |= OPL_VOICE_TO_LEFT | OPL_VOICE_TO_RIGHT;
529 	}
530 	opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, voice, fbc);
531 
532 	opl_set_op_reg(sc, OPL_AM_VIB,      voice, 0, r20m);
533 	opl_set_op_reg(sc, OPL_AM_VIB,      voice, 1, r20c);
534 	opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 0, r40m);
535 	opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 1, r40c);
536 	opl_set_ch_reg(sc, OPL_FNUM_LOW,    voice,    rA0);
537 	opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice,    rB0);
538 }
539 
540 void
541 oplsyn_noteoff(ms, voice, note, vel)
542 	midisyn *ms;
543 	u_int32_t voice, note, vel;
544 {
545 	struct opl_softc *sc = ms->data;
546 	struct opl_voice *v;
547 
548 	DPRINTFN(3, ("oplsyn_noteoff: %p %d %d\n", sc, voice,
549 		     MIDISYN_FREQ_TO_HZ(note)));
550 
551 #ifdef DIAGNOSTIC
552 	if (voice < 0 || voice >= sc->syn.nvoice) {
553 		printf("oplsyn_noteoff: bad voice %d\n", voice);
554 		return;
555 	}
556 #endif
557 	v = &sc->voices[voice];
558 	opl_set_ch_reg(sc, 0xB0, voice, v->rB0 & ~OPL_KEYON_BIT);
559 }
560 
561 void
562 oplsyn_keypressure(ms, voice, note, vel)
563 	midisyn *ms;
564 	u_int32_t voice, note, vel;
565 {
566 #ifdef AUDIO_DEBUG
567 	struct opl_softc *sc = ms->data;
568 	DPRINTFN(1, ("oplsyn_keypressure: %p %d\n", sc, note));
569 #endif
570 }
571 
572 void
573 oplsyn_ctlchange(ms, voice, parm, w14)
574 	midisyn *ms;
575 	u_int32_t voice, parm, w14;
576 {
577 #ifdef AUDIO_DEBUG
578 	struct opl_softc *sc = ms->data;
579 	DPRINTFN(1, ("oplsyn_ctlchange: %p %d\n", sc, voice));
580 #endif
581 }
582 
583 /* PROGRAM CHANGE midi event: */
584 void
585 oplsyn_programchange(ms, chan, prog)
586 	midisyn *ms;
587 	u_int32_t chan;
588 	u_int32_t prog;
589 {
590 	/* sanity checks */
591 	if (chan >= MIDI_MAX_CHANS || prog >= OPL_NINSTR)
592 		return;
593 
594 	ms->pgms[chan] = prog;
595 }
596 
597 void
598 oplsyn_pitchbend(ms, voice, parm, x)
599 	midisyn *ms;
600 	u_int32_t voice, parm, x;
601 {
602 #ifdef AUDIO_DEBUG
603 	struct opl_softc *sc = ms->data;
604 	DPRINTFN(1, ("oplsyn_pitchbend: %p %d\n", sc, voice));
605 #endif
606 }
607 
608 void
609 oplsyn_loadpatch(ms, sysex, uio)
610 	midisyn *ms;
611 	struct sysex_info *sysex;
612 	struct uio *uio;
613 {
614 #if 0
615 	struct opl_softc *sc = ms->data;
616 	struct sbi_instrument ins;
617 
618 	DPRINTFN(1, ("oplsyn_loadpatch: %p\n", sc));
619 
620 	memcpy(&ins, sysex, sizeof *sysex);
621 	if (uio->uio_resid >= sizeof ins - sizeof *sysex)
622 		return EINVAL;
623 	uiomove((char *)&ins + sizeof *sysex, sizeof ins - sizeof *sysex, uio);
624 	/* XXX */
625 #endif
626 }
627