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