1 /* $OpenBSD: opl.c,v 1.6 2003/10/21 18:58:49 jmc Exp $ */
2 /* $NetBSD: opl.c,v 1.7 1998/12/08 14:26:56 augustss Exp $ */
3
4 /*
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Lennart Augustsson (augustss@netbsd.org).
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * The OPL3 (YMF262) manual can be found at
42 * ftp://ftp.yamahayst.com/pub/Fax_Back_Doc/Sound/YMF262.PDF
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/select.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; /* 0=unavailable, 2=2 OP, 4=4 OP */
79 u_int8_t iooffs; /* I/O port (left or right side) */
80 u_int8_t op[4]; /* Operator offsets */
81 };
82
83 const struct opl_voice voicetab[] = {
84 /* No I/O offs OP1 OP2 OP3 OP4 */
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_command(struct opl_softc *, int, int, int);
111 void opl_reset(struct opl_softc *);
112 void opl_freq_to_fnum (int freq, int *block, int *fnum);
113
114 int oplsyn_open(midisyn *ms, int);
115 void oplsyn_close(midisyn *);
116 void oplsyn_reset(void *);
117 void oplsyn_noteon(midisyn *, u_int32_t, u_int32_t, u_int32_t);
118 void oplsyn_noteoff(midisyn *, u_int32_t, u_int32_t, u_int32_t);
119 void oplsyn_keypressure(midisyn *, u_int32_t, u_int32_t, u_int32_t);
120 void oplsyn_ctlchange(midisyn *, u_int32_t, u_int32_t, u_int32_t);
121 void oplsyn_pitchbend(midisyn *, u_int32_t, u_int32_t, u_int32_t);
122 void oplsyn_loadpatch(midisyn *, struct sysex_info *, struct uio *);
123
124
125 void opl_set_op_reg(struct opl_softc *, int, int, int, u_char);
126 void opl_set_ch_reg(struct opl_softc *, int, int, u_char);
127 void opl_load_patch(struct opl_softc *, int);
128 u_int32_t opl_get_block_fnum(int freq);
129 int opl_calc_vol(int regbyte, int volume, int main_vol);
130
131 struct cfdriver opl_cd = {
132 NULL, "opl", DV_DULL
133 };
134
135 struct midisyn_methods opl3_midi = {
136 oplsyn_open,
137 oplsyn_close,
138 0,
139 0,
140 oplsyn_noteon,
141 oplsyn_noteoff,
142 oplsyn_keypressure,
143 oplsyn_ctlchange,
144 0,
145 0,
146 oplsyn_pitchbend,
147 0
148 };
149
150 void
opl_attach(sc)151 opl_attach(sc)
152 struct opl_softc *sc;
153 {
154 int i;
155
156 if (!opl_find(sc)) {
157 printf("\nopl: find failed\n");
158 return;
159 }
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.flags = MS_DOALLOC | MS_FREQXLATE;
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 opl_reset(sc);
174
175 printf(": model OPL%d\n", sc->model);
176
177 midi_attach_mi(&midisyn_hw_if, &sc->syn, &sc->mididev.dev);
178 }
179
180 static void
opl_command(sc,offs,addr,data)181 opl_command(sc, offs, addr, data)
182 struct opl_softc *sc;
183 int offs;
184 int addr, data;
185 {
186 DPRINTFN(4, ("opl_command: sc=%p, offs=%d addr=0x%02x data=0x%02x\n",
187 sc, offs, addr, data));
188 offs += sc->offs;
189 bus_space_write_1(sc->iot, sc->ioh, OPL_ADDR+offs, addr);
190 if (sc->model == OPL_2)
191 delay(10);
192 else
193 delay(6);
194 bus_space_write_1(sc->iot, sc->ioh, OPL_DATA+offs, data);
195 if (sc->model == OPL_2)
196 delay(30);
197 else
198 delay(6);
199 }
200
201 int
opl_find(sc)202 opl_find(sc)
203 struct opl_softc *sc;
204 {
205 u_int8_t status1, status2;
206
207 DPRINTFN(2,("opl_find: ioh=0x%x\n", (int)sc->ioh));
208 sc->model = OPL_2; /* worst case assumption */
209
210 /* Reset timers 1 and 2 */
211 opl_command(sc, OPL_L, OPL_TIMER_CONTROL,
212 OPL_TIMER1_MASK | OPL_TIMER2_MASK);
213 /* Reset the IRQ of the FM chip */
214 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
215
216 /* get status bits */
217 status1 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs);
218
219 opl_command(sc, OPL_L, OPL_TIMER1, -2); /* wait 2 ticks */
220 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, /* start timer1 */
221 OPL_TIMER1_START | OPL_TIMER2_MASK);
222 delay(1000); /* wait for timer to expire */
223
224 /* get status bits again */
225 status2 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs);
226
227 opl_command(sc, OPL_L, OPL_TIMER_CONTROL,
228 OPL_TIMER1_MASK | OPL_TIMER2_MASK);
229 opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
230
231 DPRINTFN(2,("opl_find: %02x %02x\n", status1, status2));
232
233 if ((status1 & OPL_STATUS_MASK) != 0 ||
234 (status2 & OPL_STATUS_MASK) != (OPL_STATUS_IRQ | OPL_STATUS_FT1))
235 return (0);
236
237 switch(status1) {
238 case 0x00:
239 case 0x0f:
240 sc->model = OPL_3;
241 break;
242 case 0x06:
243 sc->model = OPL_2;
244 break;
245 default:
246 return 0;
247 }
248
249 DPRINTFN(2,("opl_find: OPL%d at 0x%x detected\n",
250 sc->model, (int)sc->ioh));
251 return (1);
252 }
253
254 void
opl_set_op_reg(sc,base,voice,op,value)255 opl_set_op_reg(sc, base, voice, op, value)
256 struct opl_softc *sc;
257 int base;
258 int voice;
259 int op;
260 u_char value;
261 {
262 struct opl_voice *v = &sc->voices[voice];
263 opl_command(sc, v->iooffs, base + v->op[op], value);
264 }
265
266 void
opl_set_ch_reg(sc,base,voice,value)267 opl_set_ch_reg(sc, base, voice, value)
268 struct opl_softc *sc;
269 int base;
270 int voice;
271 u_char value;
272 {
273 struct opl_voice *v = &sc->voices[voice];
274 opl_command(sc, v->iooffs, base + v->voiceno, value);
275 }
276
277
278 void
opl_load_patch(sc,v)279 opl_load_patch(sc, v)
280 struct opl_softc *sc;
281 int v;
282 {
283 const struct opl_operators *p = sc->voices[v].patch;
284
285 opl_set_op_reg(sc, OPL_AM_VIB, v, 0, p->ops[OO_CHARS+0]);
286 opl_set_op_reg(sc, OPL_AM_VIB, v, 1, p->ops[OO_CHARS+1]);
287 opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 0, p->ops[OO_KSL_LEV+0]);
288 opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 1, p->ops[OO_KSL_LEV+1]);
289 opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 0, p->ops[OO_ATT_DEC+0]);
290 opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 1, p->ops[OO_ATT_DEC+1]);
291 opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 0, p->ops[OO_SUS_REL+0]);
292 opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 1, p->ops[OO_SUS_REL+1]);
293 opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 0, p->ops[OO_WAV_SEL+0]);
294 opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 1, p->ops[OO_WAV_SEL+1]);
295 opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, v, p->ops[OO_FB_CONN]);
296 }
297
298 #define OPL_FNUM_FAIL 0xffff
299 u_int32_t
opl_get_block_fnum(freq)300 opl_get_block_fnum(freq)
301 int freq;
302 {
303 u_int32_t f_num = freq / 3125;
304 u_int32_t block = 0;
305
306 while (f_num > 0x3FF && block < 8) {
307 block++;
308 f_num >>= 1;
309 }
310
311 if (block > 7)
312 return (OPL_FNUM_FAIL);
313 else
314 return ((block << 10) | f_num);
315 }
316
317
318 void
opl_reset(sc)319 opl_reset(sc)
320 struct opl_softc *sc;
321 {
322 int i;
323
324 for (i = 1; i <= OPL_MAXREG; i++)
325 opl_command(sc, OPL_L, OPL_KEYON_BLOCK + i, 0);
326
327 opl_command(sc, OPL_L, OPL_TEST, OPL_ENABLE_WAVE_SELECT);
328 opl_command(sc, OPL_L, OPL_PERCUSSION, 0);
329 if (sc->model == OPL_3) {
330 opl_command(sc, OPL_R, OPL_MODE, OPL3_ENABLE);
331 opl_command(sc, OPL_R,OPL_CONNECTION_SELECT,OPL_NOCONNECTION);
332 }
333
334 sc->volume = 64;
335 }
336
337 int
oplsyn_open(ms,flags)338 oplsyn_open(ms, flags)
339 midisyn *ms;
340 int flags;
341 {
342 struct opl_softc *sc = ms->data;
343
344 DPRINTFN(2, ("oplsyn_open: %d\n", flags));
345
346 opl_reset(ms->data);
347 if (sc->spkrctl)
348 sc->spkrctl(sc->spkrarg, 1);
349 return (0);
350 }
351
352 void
oplsyn_close(ms)353 oplsyn_close(ms)
354 midisyn *ms;
355 {
356 struct opl_softc *sc = ms->data;
357
358 DPRINTFN(2, ("oplsyn_close:\n"));
359
360 /*opl_reset(ms->data);*/
361 if (sc->spkrctl)
362 sc->spkrctl(sc->spkrarg, 0);
363 }
364
365 #if 0
366 void
367 oplsyn_getinfo(addr, sd)
368 void *addr;
369 struct synth_dev *sd;
370 {
371 struct opl_softc *sc = addr;
372
373 sd->name = sc->model == OPL_2 ? "Yamaha OPL2" : "Yamaha OPL3";
374 sd->type = SYNTH_TYPE_FM;
375 sd->subtype = sc->model == OPL_2 ? SYNTH_SUB_FM_TYPE_ADLIB
376 : SYNTH_SUB_FM_TYPE_OPL3;
377 sd->capabilities = 0;
378 }
379 #endif
380
381 void
oplsyn_reset(addr)382 oplsyn_reset(addr)
383 void *addr;
384 {
385 struct opl_softc *sc = addr;
386 DPRINTFN(3, ("oplsyn_reset:\n"));
387 opl_reset(sc);
388 }
389
390 int8_t opl_volume_table[128] =
391 {-64, -48, -40, -35, -32, -29, -27, -26,
392 -24, -23, -21, -20, -19, -18, -18, -17,
393 -16, -15, -15, -14, -13, -13, -12, -12,
394 -11, -11, -10, -10, -10, -9, -9, -8,
395 -8, -8, -7, -7, -7, -6, -6, -6,
396 -5, -5, -5, -5, -4, -4, -4, -4,
397 -3, -3, -3, -3, -2, -2, -2, -2,
398 -2, -1, -1, -1, -1, 0, 0, 0,
399 0, 0, 0, 1, 1, 1, 1, 1,
400 1, 2, 2, 2, 2, 2, 2, 2,
401 3, 3, 3, 3, 3, 3, 3, 4,
402 4, 4, 4, 4, 4, 4, 4, 5,
403 5, 5, 5, 5, 5, 5, 5, 5,
404 6, 6, 6, 6, 6, 6, 6, 6,
405 6, 7, 7, 7, 7, 7, 7, 7,
406 7, 7, 7, 8, 8, 8, 8, 8};
407
408 int
opl_calc_vol(regbyte,volume,mainvol)409 opl_calc_vol(regbyte, volume, mainvol)
410 int regbyte;
411 int volume;
412 int mainvol;
413 {
414 int level = ~regbyte & OPL_TOTAL_LEVEL_MASK;
415
416 if (mainvol > 127)
417 mainvol = 127;
418
419 volume = (volume * mainvol) / 127;
420
421 if (level)
422 level += opl_volume_table[volume];
423
424 if (level > OPL_TOTAL_LEVEL_MASK)
425 level = OPL_TOTAL_LEVEL_MASK;
426 if (level < 0)
427 level = 0;
428
429 return (~level & OPL_TOTAL_LEVEL_MASK);
430 }
431
432 void
oplsyn_noteon(ms,voice,freq,vel)433 oplsyn_noteon(ms, voice, freq, vel)
434 midisyn *ms;
435 u_int32_t voice, freq, vel;
436 {
437 struct opl_softc *sc = ms->data;
438 struct opl_voice *v;
439 const struct opl_operators *p;
440 u_int32_t block_fnum;
441 int mult;
442 int c_mult, m_mult;
443 u_int8_t chars0, chars1, ksl0, ksl1, fbc;
444 u_int8_t r20m, r20c, r40m, r40c, rA0, rB0;
445 u_int8_t vol0, vol1;
446
447 DPRINTFN(3, ("oplsyn_noteon: %p %d %d\n", sc, voice,
448 MIDISYN_FREQ_TO_HZ(freq)));
449
450 #ifdef DIAGNOSTIC
451 if (voice < 0 || voice >= sc->syn.nvoice) {
452 printf("oplsyn_noteon: bad voice %d\n", voice);
453 return;
454 }
455 #endif
456 /* Turn off old note */
457 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, 0xff);
458 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, 0xff);
459 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, 0);
460
461 v = &sc->voices[voice];
462
463 p = &opl2_instrs[MS_GETPGM(ms, voice)];
464 v->patch = p;
465 opl_load_patch(sc, voice);
466
467 mult = 1;
468 for (;;) {
469 block_fnum = opl_get_block_fnum(freq / mult);
470 if (block_fnum != OPL_FNUM_FAIL)
471 break;
472 mult *= 2;
473 if (mult == 16)
474 mult = 15;
475 }
476
477 chars0 = p->ops[OO_CHARS+0];
478 chars1 = p->ops[OO_CHARS+1];
479 m_mult = (chars0 & OPL_MULTIPLE_MASK) * mult;
480 c_mult = (chars1 & OPL_MULTIPLE_MASK) * mult;
481 if ((block_fnum == OPL_FNUM_FAIL) || (m_mult > 15) || (c_mult > 15)) {
482 printf("oplsyn_noteon: frequence out of range %d\n",
483 MIDISYN_FREQ_TO_HZ(freq));
484 return;
485 }
486 r20m = (chars0 &~ OPL_MULTIPLE_MASK) | m_mult;
487 r20c = (chars1 &~ OPL_MULTIPLE_MASK) | c_mult;
488
489 /* 2 voice */
490 ksl0 = p->ops[OO_KSL_LEV+0];
491 ksl1 = p->ops[OO_KSL_LEV+1];
492 if (p->ops[OO_FB_CONN] & 0x01) {
493 vol0 = opl_calc_vol(ksl0, vel, sc->volume);
494 vol1 = opl_calc_vol(ksl1, vel, sc->volume);
495 } else {
496 vol0 = ksl0;
497 vol1 = opl_calc_vol(ksl1, vel, sc->volume);
498 }
499 r40m = (ksl0 & OPL_KSL_MASK) | vol0;
500 r40c = (ksl1 & OPL_KSL_MASK) | vol1;
501
502 rA0 = block_fnum & 0xFF;
503 rB0 = (block_fnum >> 8) | OPL_KEYON_BIT;
504
505 v->rB0 = rB0;
506
507 fbc = p->ops[OO_FB_CONN];
508 if (sc->model == OPL_3) {
509 fbc &= ~OPL_STEREO_BITS;
510 /* XXX use pan */
511 fbc |= OPL_VOICE_TO_LEFT | OPL_VOICE_TO_RIGHT;
512 }
513 opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, voice, fbc);
514
515 opl_set_op_reg(sc, OPL_AM_VIB, voice, 0, r20m);
516 opl_set_op_reg(sc, OPL_AM_VIB, voice, 1, r20c);
517 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, r40m);
518 opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, r40c);
519 opl_set_ch_reg(sc, OPL_FNUM_LOW, voice, rA0);
520 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, rB0);
521 }
522
523 void
oplsyn_noteoff(ms,voice,note,vel)524 oplsyn_noteoff(ms, voice, note, vel)
525 midisyn *ms;
526 u_int32_t voice, note, vel;
527 {
528 struct opl_softc *sc = ms->data;
529 struct opl_voice *v;
530
531 DPRINTFN(3, ("oplsyn_noteoff: %p %d %d\n", sc, voice,
532 MIDISYN_FREQ_TO_HZ(note)));
533
534 #ifdef DIAGNOSTIC
535 if (voice < 0 || voice >= sc->syn.nvoice) {
536 printf("oplsyn_noteoff: bad voice %d\n", voice);
537 return;
538 }
539 #endif
540 v = &sc->voices[voice];
541 opl_set_ch_reg(sc, 0xB0, voice, v->rB0 & ~OPL_KEYON_BIT);
542 }
543
544 void
oplsyn_keypressure(ms,voice,note,vel)545 oplsyn_keypressure(ms, voice, note, vel)
546 midisyn *ms;
547 u_int32_t voice, note, vel;
548 {
549 #ifdef AUDIO_DEBUG
550 struct opl_softc *sc = ms->data;
551 DPRINTFN(1, ("oplsyn_keypressure: %p %d\n", sc, note));
552 #endif
553 }
554
555 void
oplsyn_ctlchange(ms,voice,parm,w14)556 oplsyn_ctlchange(ms, voice, parm, w14)
557 midisyn *ms;
558 u_int32_t voice, parm, w14;
559 {
560 #ifdef AUDIO_DEBUG
561 struct opl_softc *sc = ms->data;
562 DPRINTFN(1, ("oplsyn_ctlchange: %p %d\n", sc, voice));
563 #endif
564 }
565
566 void
oplsyn_pitchbend(ms,voice,parm,x)567 oplsyn_pitchbend(ms, voice, parm, x)
568 midisyn *ms;
569 u_int32_t voice, parm, x;
570 {
571 #ifdef AUDIO_DEBUG
572 struct opl_softc *sc = ms->data;
573 DPRINTFN(1, ("oplsyn_pitchbend: %p %d\n", sc, voice));
574 #endif
575 }
576
577 void
oplsyn_loadpatch(ms,sysex,uio)578 oplsyn_loadpatch(ms, sysex, uio)
579 midisyn *ms;
580 struct sysex_info *sysex;
581 struct uio *uio;
582 {
583 #if 0
584 struct opl_softc *sc = ms->data;
585 struct sbi_instrument ins;
586
587 DPRINTFN(1, ("oplsyn_loadpatch: %p\n", sc));
588
589 memcpy(&ins, sysex, sizeof *sysex);
590 if (uio->uio_resid >= sizeof ins - sizeof *sysex)
591 return EINVAL;
592 uiomove((char *)&ins + sizeof *sysex, sizeof ins - sizeof *sysex, uio);
593 /* XXX */
594 #endif
595 }
596