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@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
opl_attach(struct opl_softc * sc)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
opl_detach(struct opl_softc * sc,int flags)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
opl_command(struct opl_softc * sc,int offs,int addr,int data)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
opl_match(bus_space_tag_t iot,bus_space_handle_t ioh,int offs)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
opl_find(struct opl_softc * sc)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
opl_set_op_reg(struct opl_softc * sc,int base,int voice,int op,u_char value)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
opl_set_ch_reg(struct opl_softc * sc,int base,int voice,u_char value)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
opl_load_patch(struct opl_softc * sc,int v)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
opl_get_block_fnum(midipitch_t mp)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
opl_reset(struct opl_softc * sc)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
oplsyn_open(midisyn * ms,int flags)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
oplsyn_close(midisyn * ms)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
oplsyn_reset(void * addr)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
opl_calc_vol(int regbyte,int16_t level_cB)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
oplsyn_attackv(midisyn * ms,uint_fast16_t voice,midipitch_t mp,int16_t level_cB)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
oplsyn_repitchv(midisyn * ms,uint_fast16_t voice,midipitch_t mp)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
oplsyn_relevelv(midisyn * ms,uint_fast16_t voice,int16_t level_cB)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
oplsyn_setv(midisyn * ms,uint_fast16_t voice,midipitch_t mp,int16_t level_cB,int act)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
oplsyn_releasev(midisyn * ms,uint_fast16_t voice,uint_fast8_t vel)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
oplsyn_ctlnotice(midisyn * ms,midictl_evt evt,uint_fast8_t chan,uint_fast16_t key)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
oplsyn_programchange(midisyn * ms,uint_fast8_t chan,uint_fast8_t prog)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
oplsyn_loadpatch(midisyn * ms,struct sysex_info * sysex,struct uio * uio)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
oplsyn_panhandler(midisyn * ms,uint_fast8_t chan)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