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