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