1 /* 2 * Copyright (c) by Uros Bizjak <uros@kss-loka.si> 3 * 4 * Routines for OPL2/OPL3/OPL4 control 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <linux/slab.h> 23 #include <sound/opl3.h> 24 #include <sound/asound_fm.h> 25 26 #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) 27 #define OPL3_SUPPORT_SYNTH 28 #endif 29 30 /* 31 * There is 18 possible 2 OP voices 32 * (9 in the left and 9 in the right). 33 * The first OP is the modulator and 2nd is the carrier. 34 * 35 * The first three voices in the both sides may be connected 36 * with another voice to a 4 OP voice. For example voice 0 37 * can be connected with voice 3. The operators of voice 3 are 38 * used as operators 3 and 4 of the new 4 OP voice. 39 * In this case the 2 OP voice number 0 is the 'first half' and 40 * voice 3 is the second. 41 */ 42 43 44 /* 45 * Register offset table for OPL2/3 voices, 46 * OPL2 / one OPL3 register array side only 47 */ 48 49 char snd_opl3_regmap[MAX_OPL2_VOICES][4] = 50 { 51 /* OP1 OP2 OP3 OP4 */ 52 /* ------------------------ */ 53 { 0x00, 0x03, 0x08, 0x0b }, 54 { 0x01, 0x04, 0x09, 0x0c }, 55 { 0x02, 0x05, 0x0a, 0x0d }, 56 57 { 0x08, 0x0b, 0x00, 0x00 }, 58 { 0x09, 0x0c, 0x00, 0x00 }, 59 { 0x0a, 0x0d, 0x00, 0x00 }, 60 61 { 0x10, 0x13, 0x00, 0x00 }, /* used by percussive voices */ 62 { 0x11, 0x14, 0x00, 0x00 }, /* if the percussive mode */ 63 { 0x12, 0x15, 0x00, 0x00 } /* is selected (only left reg block) */ 64 }; 65 66 EXPORT_SYMBOL(snd_opl3_regmap); 67 68 /* 69 * prototypes 70 */ 71 static int snd_opl3_play_note(struct snd_opl3 * opl3, struct snd_dm_fm_note * note); 72 static int snd_opl3_set_voice(struct snd_opl3 * opl3, struct snd_dm_fm_voice * voice); 73 static int snd_opl3_set_params(struct snd_opl3 * opl3, struct snd_dm_fm_params * params); 74 static int snd_opl3_set_mode(struct snd_opl3 * opl3, int mode); 75 static int snd_opl3_set_connection(struct snd_opl3 * opl3, int connection); 76 77 /* ------------------------------ */ 78 79 /* 80 * open the device exclusively 81 */ 82 int snd_opl3_open(struct snd_hwdep * hw, struct file *file) 83 { 84 return 0; 85 } 86 87 /* 88 * ioctl for hwdep device: 89 */ 90 int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file, 91 unsigned int cmd, unsigned long arg) 92 { 93 struct snd_opl3 *opl3 = hw->private_data; 94 void __user *argp = (void __user *)arg; 95 96 if (snd_BUG_ON(!opl3)) 97 return -EINVAL; 98 99 switch (cmd) { 100 /* get information */ 101 case SNDRV_DM_FM_IOCTL_INFO: 102 { 103 struct snd_dm_fm_info info; 104 105 info.fm_mode = opl3->fm_mode; 106 info.rhythm = opl3->rhythm; 107 if (copy_to_user(argp, &info, sizeof(struct snd_dm_fm_info))) 108 return -EFAULT; 109 return 0; 110 } 111 112 case SNDRV_DM_FM_IOCTL_RESET: 113 #ifdef CONFIG_SND_OSSEMUL 114 case SNDRV_DM_FM_OSS_IOCTL_RESET: 115 #endif 116 snd_opl3_reset(opl3); 117 return 0; 118 119 case SNDRV_DM_FM_IOCTL_PLAY_NOTE: 120 #ifdef CONFIG_SND_OSSEMUL 121 case SNDRV_DM_FM_OSS_IOCTL_PLAY_NOTE: 122 #endif 123 { 124 struct snd_dm_fm_note note; 125 if (copy_from_user(¬e, argp, sizeof(struct snd_dm_fm_note))) 126 return -EFAULT; 127 return snd_opl3_play_note(opl3, ¬e); 128 } 129 130 case SNDRV_DM_FM_IOCTL_SET_VOICE: 131 #ifdef CONFIG_SND_OSSEMUL 132 case SNDRV_DM_FM_OSS_IOCTL_SET_VOICE: 133 #endif 134 { 135 struct snd_dm_fm_voice voice; 136 if (copy_from_user(&voice, argp, sizeof(struct snd_dm_fm_voice))) 137 return -EFAULT; 138 return snd_opl3_set_voice(opl3, &voice); 139 } 140 141 case SNDRV_DM_FM_IOCTL_SET_PARAMS: 142 #ifdef CONFIG_SND_OSSEMUL 143 case SNDRV_DM_FM_OSS_IOCTL_SET_PARAMS: 144 #endif 145 { 146 struct snd_dm_fm_params params; 147 if (copy_from_user(¶ms, argp, sizeof(struct snd_dm_fm_params))) 148 return -EFAULT; 149 return snd_opl3_set_params(opl3, ¶ms); 150 } 151 152 case SNDRV_DM_FM_IOCTL_SET_MODE: 153 #ifdef CONFIG_SND_OSSEMUL 154 case SNDRV_DM_FM_OSS_IOCTL_SET_MODE: 155 #endif 156 return snd_opl3_set_mode(opl3, (int) arg); 157 158 case SNDRV_DM_FM_IOCTL_SET_CONNECTION: 159 #ifdef CONFIG_SND_OSSEMUL 160 case SNDRV_DM_FM_OSS_IOCTL_SET_OPL: 161 #endif 162 return snd_opl3_set_connection(opl3, (int) arg); 163 164 #ifdef OPL3_SUPPORT_SYNTH 165 case SNDRV_DM_FM_IOCTL_CLEAR_PATCHES: 166 snd_opl3_clear_patches(opl3); 167 return 0; 168 #endif 169 170 #ifdef CONFIG_SND_DEBUG 171 default: 172 snd_printk(KERN_WARNING "unknown IOCTL: 0x%x\n", cmd); 173 #endif 174 } 175 return -ENOTTY; 176 } 177 178 /* 179 * close the device 180 */ 181 int snd_opl3_release(struct snd_hwdep * hw, struct file *file) 182 { 183 struct snd_opl3 *opl3 = hw->private_data; 184 185 snd_opl3_reset(opl3); 186 return 0; 187 } 188 189 #ifdef OPL3_SUPPORT_SYNTH 190 /* 191 * write the device - load patches 192 */ 193 long snd_opl3_write(struct snd_hwdep *hw, const char __user *buf, long count, 194 loff_t *offset) 195 { 196 struct snd_opl3 *opl3 = hw->private_data; 197 long result = 0; 198 int err = 0; 199 struct sbi_patch inst; 200 201 while (count >= sizeof(inst)) { 202 unsigned char type; 203 if (copy_from_user(&inst, buf, sizeof(inst))) 204 return -EFAULT; 205 if (!memcmp(inst.key, FM_KEY_SBI, 4) || 206 !memcmp(inst.key, FM_KEY_2OP, 4)) 207 type = FM_PATCH_OPL2; 208 else if (!memcmp(inst.key, FM_KEY_4OP, 4)) 209 type = FM_PATCH_OPL3; 210 else /* invalid type */ 211 break; 212 err = snd_opl3_load_patch(opl3, inst.prog, inst.bank, type, 213 inst.name, inst.extension, 214 inst.data); 215 if (err < 0) 216 break; 217 result += sizeof(inst); 218 count -= sizeof(inst); 219 } 220 return result > 0 ? result : err; 221 } 222 223 224 /* 225 * Patch management 226 */ 227 228 /* offsets for SBI params */ 229 #define AM_VIB 0 230 #define KSL_LEVEL 2 231 #define ATTACK_DECAY 4 232 #define SUSTAIN_RELEASE 6 233 #define WAVE_SELECT 8 234 235 /* offset for SBI instrument */ 236 #define CONNECTION 10 237 #define OFFSET_4OP 11 238 239 /* 240 * load a patch, obviously. 241 * 242 * loaded on the given program and bank numbers with the given type 243 * (FM_PATCH_OPLx). 244 * data is the pointer of SBI record _without_ header (key and name). 245 * name is the name string of the patch. 246 * ext is the extension data of 7 bytes long (stored in name of SBI 247 * data up to offset 25), or NULL to skip. 248 * return 0 if successful or a negative error code. 249 */ 250 int snd_opl3_load_patch(struct snd_opl3 *opl3, 251 int prog, int bank, int type, 252 const char *name, 253 const unsigned char *ext, 254 const unsigned char *data) 255 { 256 struct fm_patch *patch; 257 int i; 258 259 patch = snd_opl3_find_patch(opl3, prog, bank, 1); 260 if (!patch) 261 return -ENOMEM; 262 263 patch->type = type; 264 265 for (i = 0; i < 2; i++) { 266 patch->inst.op[i].am_vib = data[AM_VIB + i]; 267 patch->inst.op[i].ksl_level = data[KSL_LEVEL + i]; 268 patch->inst.op[i].attack_decay = data[ATTACK_DECAY + i]; 269 patch->inst.op[i].sustain_release = data[SUSTAIN_RELEASE + i]; 270 patch->inst.op[i].wave_select = data[WAVE_SELECT + i]; 271 } 272 patch->inst.feedback_connection[0] = data[CONNECTION]; 273 274 if (type == FM_PATCH_OPL3) { 275 for (i = 0; i < 2; i++) { 276 patch->inst.op[i+2].am_vib = 277 data[OFFSET_4OP + AM_VIB + i]; 278 patch->inst.op[i+2].ksl_level = 279 data[OFFSET_4OP + KSL_LEVEL + i]; 280 patch->inst.op[i+2].attack_decay = 281 data[OFFSET_4OP + ATTACK_DECAY + i]; 282 patch->inst.op[i+2].sustain_release = 283 data[OFFSET_4OP + SUSTAIN_RELEASE + i]; 284 patch->inst.op[i+2].wave_select = 285 data[OFFSET_4OP + WAVE_SELECT + i]; 286 } 287 patch->inst.feedback_connection[1] = 288 data[OFFSET_4OP + CONNECTION]; 289 } 290 291 if (ext) { 292 patch->inst.echo_delay = ext[0]; 293 patch->inst.echo_atten = ext[1]; 294 patch->inst.chorus_spread = ext[2]; 295 patch->inst.trnsps = ext[3]; 296 patch->inst.fix_dur = ext[4]; 297 patch->inst.modes = ext[5]; 298 patch->inst.fix_key = ext[6]; 299 } 300 301 if (name) 302 strlcpy(patch->name, name, sizeof(patch->name)); 303 304 return 0; 305 } 306 EXPORT_SYMBOL(snd_opl3_load_patch); 307 308 /* 309 * find a patch with the given program and bank numbers, returns its pointer 310 * if no matching patch is found and create_patch is set, it creates a 311 * new patch object. 312 */ 313 struct fm_patch *snd_opl3_find_patch(struct snd_opl3 *opl3, int prog, int bank, 314 int create_patch) 315 { 316 /* pretty dumb hash key */ 317 unsigned int key = (prog + bank) % OPL3_PATCH_HASH_SIZE; 318 struct fm_patch *patch; 319 320 for (patch = opl3->patch_table[key]; patch; patch = patch->next) { 321 if (patch->prog == prog && patch->bank == bank) 322 return patch; 323 } 324 if (!create_patch) 325 return NULL; 326 327 patch = kzalloc(sizeof(*patch), GFP_KERNEL); 328 if (!patch) 329 return NULL; 330 patch->prog = prog; 331 patch->bank = bank; 332 patch->next = opl3->patch_table[key]; 333 opl3->patch_table[key] = patch; 334 return patch; 335 } 336 EXPORT_SYMBOL(snd_opl3_find_patch); 337 338 /* 339 * Clear all patches of the given OPL3 instance 340 */ 341 void snd_opl3_clear_patches(struct snd_opl3 *opl3) 342 { 343 int i; 344 for (i = 0; i < OPL3_PATCH_HASH_SIZE; i++) { 345 struct fm_patch *patch, *next; 346 for (patch = opl3->patch_table[i]; patch; patch = next) { 347 next = patch->next; 348 kfree(patch); 349 } 350 } 351 memset(opl3->patch_table, 0, sizeof(opl3->patch_table)); 352 } 353 #endif /* OPL3_SUPPORT_SYNTH */ 354 355 /* ------------------------------ */ 356 357 void snd_opl3_reset(struct snd_opl3 * opl3) 358 { 359 unsigned short opl3_reg; 360 361 unsigned short reg_side; 362 unsigned char voice_offset; 363 364 int max_voices, i; 365 366 max_voices = (opl3->hardware < OPL3_HW_OPL3) ? 367 MAX_OPL2_VOICES : MAX_OPL3_VOICES; 368 369 for (i = 0; i < max_voices; i++) { 370 /* Get register array side and offset of voice */ 371 if (i < MAX_OPL2_VOICES) { 372 /* Left register block for voices 0 .. 8 */ 373 reg_side = OPL3_LEFT; 374 voice_offset = i; 375 } else { 376 /* Right register block for voices 9 .. 17 */ 377 reg_side = OPL3_RIGHT; 378 voice_offset = i - MAX_OPL2_VOICES; 379 } 380 opl3_reg = reg_side | (OPL3_REG_KSL_LEVEL + snd_opl3_regmap[voice_offset][0]); 381 opl3->command(opl3, opl3_reg, OPL3_TOTAL_LEVEL_MASK); /* Operator 1 volume */ 382 opl3_reg = reg_side | (OPL3_REG_KSL_LEVEL + snd_opl3_regmap[voice_offset][1]); 383 opl3->command(opl3, opl3_reg, OPL3_TOTAL_LEVEL_MASK); /* Operator 2 volume */ 384 385 opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset); 386 opl3->command(opl3, opl3_reg, 0x00); /* Note off */ 387 } 388 389 opl3->max_voices = MAX_OPL2_VOICES; 390 opl3->fm_mode = SNDRV_DM_FM_MODE_OPL2; 391 392 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TEST, OPL3_ENABLE_WAVE_SELECT); 393 opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, 0x00); /* Melodic mode */ 394 opl3->rhythm = 0; 395 } 396 397 EXPORT_SYMBOL(snd_opl3_reset); 398 399 static int snd_opl3_play_note(struct snd_opl3 * opl3, struct snd_dm_fm_note * note) 400 { 401 unsigned short reg_side; 402 unsigned char voice_offset; 403 404 unsigned short opl3_reg; 405 unsigned char reg_val; 406 407 /* Voices 0 - 8 in OPL2 mode */ 408 /* Voices 0 - 17 in OPL3 mode */ 409 if (note->voice >= ((opl3->fm_mode == SNDRV_DM_FM_MODE_OPL3) ? 410 MAX_OPL3_VOICES : MAX_OPL2_VOICES)) 411 return -EINVAL; 412 413 /* Get register array side and offset of voice */ 414 if (note->voice < MAX_OPL2_VOICES) { 415 /* Left register block for voices 0 .. 8 */ 416 reg_side = OPL3_LEFT; 417 voice_offset = note->voice; 418 } else { 419 /* Right register block for voices 9 .. 17 */ 420 reg_side = OPL3_RIGHT; 421 voice_offset = note->voice - MAX_OPL2_VOICES; 422 } 423 424 /* Set lower 8 bits of note frequency */ 425 reg_val = (unsigned char) note->fnum; 426 opl3_reg = reg_side | (OPL3_REG_FNUM_LOW + voice_offset); 427 opl3->command(opl3, opl3_reg, reg_val); 428 429 reg_val = 0x00; 430 /* Set output sound flag */ 431 if (note->key_on) 432 reg_val |= OPL3_KEYON_BIT; 433 /* Set octave */ 434 reg_val |= (note->octave << 2) & OPL3_BLOCKNUM_MASK; 435 /* Set higher 2 bits of note frequency */ 436 reg_val |= (unsigned char) (note->fnum >> 8) & OPL3_FNUM_HIGH_MASK; 437 438 /* Set OPL3 KEYON_BLOCK register of requested voice */ 439 opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset); 440 opl3->command(opl3, opl3_reg, reg_val); 441 442 return 0; 443 } 444 445 446 static int snd_opl3_set_voice(struct snd_opl3 * opl3, struct snd_dm_fm_voice * voice) 447 { 448 unsigned short reg_side; 449 unsigned char op_offset; 450 unsigned char voice_offset; 451 452 unsigned short opl3_reg; 453 unsigned char reg_val; 454 455 /* Only operators 1 and 2 */ 456 if (voice->op > 1) 457 return -EINVAL; 458 /* Voices 0 - 8 in OPL2 mode */ 459 /* Voices 0 - 17 in OPL3 mode */ 460 if (voice->voice >= ((opl3->fm_mode == SNDRV_DM_FM_MODE_OPL3) ? 461 MAX_OPL3_VOICES : MAX_OPL2_VOICES)) 462 return -EINVAL; 463 464 /* Get register array side and offset of voice */ 465 if (voice->voice < MAX_OPL2_VOICES) { 466 /* Left register block for voices 0 .. 8 */ 467 reg_side = OPL3_LEFT; 468 voice_offset = voice->voice; 469 } else { 470 /* Right register block for voices 9 .. 17 */ 471 reg_side = OPL3_RIGHT; 472 voice_offset = voice->voice - MAX_OPL2_VOICES; 473 } 474 /* Get register offset of operator */ 475 op_offset = snd_opl3_regmap[voice_offset][voice->op]; 476 477 reg_val = 0x00; 478 /* Set amplitude modulation (tremolo) effect */ 479 if (voice->am) 480 reg_val |= OPL3_TREMOLO_ON; 481 /* Set vibrato effect */ 482 if (voice->vibrato) 483 reg_val |= OPL3_VIBRATO_ON; 484 /* Set sustaining sound phase */ 485 if (voice->do_sustain) 486 reg_val |= OPL3_SUSTAIN_ON; 487 /* Set keyboard scaling bit */ 488 if (voice->kbd_scale) 489 reg_val |= OPL3_KSR; 490 /* Set harmonic or frequency multiplier */ 491 reg_val |= voice->harmonic & OPL3_MULTIPLE_MASK; 492 493 /* Set OPL3 AM_VIB register of requested voice/operator */ 494 opl3_reg = reg_side | (OPL3_REG_AM_VIB + op_offset); 495 opl3->command(opl3, opl3_reg, reg_val); 496 497 /* Set decreasing volume of higher notes */ 498 reg_val = (voice->scale_level << 6) & OPL3_KSL_MASK; 499 /* Set output volume */ 500 reg_val |= ~voice->volume & OPL3_TOTAL_LEVEL_MASK; 501 502 /* Set OPL3 KSL_LEVEL register of requested voice/operator */ 503 opl3_reg = reg_side | (OPL3_REG_KSL_LEVEL + op_offset); 504 opl3->command(opl3, opl3_reg, reg_val); 505 506 /* Set attack phase level */ 507 reg_val = (voice->attack << 4) & OPL3_ATTACK_MASK; 508 /* Set decay phase level */ 509 reg_val |= voice->decay & OPL3_DECAY_MASK; 510 511 /* Set OPL3 ATTACK_DECAY register of requested voice/operator */ 512 opl3_reg = reg_side | (OPL3_REG_ATTACK_DECAY + op_offset); 513 opl3->command(opl3, opl3_reg, reg_val); 514 515 /* Set sustain phase level */ 516 reg_val = (voice->sustain << 4) & OPL3_SUSTAIN_MASK; 517 /* Set release phase level */ 518 reg_val |= voice->release & OPL3_RELEASE_MASK; 519 520 /* Set OPL3 SUSTAIN_RELEASE register of requested voice/operator */ 521 opl3_reg = reg_side | (OPL3_REG_SUSTAIN_RELEASE + op_offset); 522 opl3->command(opl3, opl3_reg, reg_val); 523 524 /* Set inter-operator feedback */ 525 reg_val = (voice->feedback << 1) & OPL3_FEEDBACK_MASK; 526 /* Set inter-operator connection */ 527 if (voice->connection) 528 reg_val |= OPL3_CONNECTION_BIT; 529 /* OPL-3 only */ 530 if (opl3->fm_mode == SNDRV_DM_FM_MODE_OPL3) { 531 if (voice->left) 532 reg_val |= OPL3_VOICE_TO_LEFT; 533 if (voice->right) 534 reg_val |= OPL3_VOICE_TO_RIGHT; 535 } 536 /* Feedback/connection bits are applicable to voice */ 537 opl3_reg = reg_side | (OPL3_REG_FEEDBACK_CONNECTION + voice_offset); 538 opl3->command(opl3, opl3_reg, reg_val); 539 540 /* Select waveform */ 541 reg_val = voice->waveform & OPL3_WAVE_SELECT_MASK; 542 opl3_reg = reg_side | (OPL3_REG_WAVE_SELECT + op_offset); 543 opl3->command(opl3, opl3_reg, reg_val); 544 545 return 0; 546 } 547 548 static int snd_opl3_set_params(struct snd_opl3 * opl3, struct snd_dm_fm_params * params) 549 { 550 unsigned char reg_val; 551 552 reg_val = 0x00; 553 /* Set keyboard split method */ 554 if (params->kbd_split) 555 reg_val |= OPL3_KEYBOARD_SPLIT; 556 opl3->command(opl3, OPL3_LEFT | OPL3_REG_KBD_SPLIT, reg_val); 557 558 reg_val = 0x00; 559 /* Set amplitude modulation (tremolo) depth */ 560 if (params->am_depth) 561 reg_val |= OPL3_TREMOLO_DEPTH; 562 /* Set vibrato depth */ 563 if (params->vib_depth) 564 reg_val |= OPL3_VIBRATO_DEPTH; 565 /* Set percussion mode */ 566 if (params->rhythm) { 567 reg_val |= OPL3_PERCUSSION_ENABLE; 568 opl3->rhythm = 1; 569 } else { 570 opl3->rhythm = 0; 571 } 572 /* Play percussion instruments */ 573 if (params->bass) 574 reg_val |= OPL3_BASSDRUM_ON; 575 if (params->snare) 576 reg_val |= OPL3_SNAREDRUM_ON; 577 if (params->tomtom) 578 reg_val |= OPL3_TOMTOM_ON; 579 if (params->cymbal) 580 reg_val |= OPL3_CYMBAL_ON; 581 if (params->hihat) 582 reg_val |= OPL3_HIHAT_ON; 583 584 opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, reg_val); 585 return 0; 586 } 587 588 static int snd_opl3_set_mode(struct snd_opl3 * opl3, int mode) 589 { 590 if ((mode == SNDRV_DM_FM_MODE_OPL3) && (opl3->hardware < OPL3_HW_OPL3)) 591 return -EINVAL; 592 593 opl3->fm_mode = mode; 594 if (opl3->hardware >= OPL3_HW_OPL3) 595 opl3->command(opl3, OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT, 0x00); /* Clear 4-op connections */ 596 597 return 0; 598 } 599 600 static int snd_opl3_set_connection(struct snd_opl3 * opl3, int connection) 601 { 602 unsigned char reg_val; 603 604 /* OPL-3 only */ 605 if (opl3->fm_mode != SNDRV_DM_FM_MODE_OPL3) 606 return -EINVAL; 607 608 reg_val = connection & (OPL3_RIGHT_4OP_0 | OPL3_RIGHT_4OP_1 | OPL3_RIGHT_4OP_2 | 609 OPL3_LEFT_4OP_0 | OPL3_LEFT_4OP_1 | OPL3_LEFT_4OP_2); 610 /* Set 4-op connections */ 611 opl3->command(opl3, OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT, reg_val); 612 613 return 0; 614 } 615 616