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