// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ // Based on Nuked OPN2 ym3438.c and ym3438.h #include "Ym2612_Nuked.h" /* * Copyright (C) 2017 Alexey Khokholov (Nuke.YKT) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * * Nuked OPN2(Yamaha YM3438) emulator. * Thanks: * Silicon Pr0n: * Yamaha YM3438 decap and die shot(digshadow). * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): * OPL2 ROMs. * * version: 1.0.7 */ #include #include typedef uintptr_t Bitu; typedef intptr_t Bits; typedef uint64_t Bit64u; typedef int64_t Bit64s; typedef uint32_t Bit32u; typedef int32_t Bit32s; typedef uint16_t Bit16u; typedef int16_t Bit16s; typedef uint8_t Bit8u; typedef int8_t Bit8s; namespace Ym2612_NukedImpl { /*EXTRA*/ #define RSM_FRAC 10 #define OPN_WRITEBUF_SIZE 2048 #define OPN_WRITEBUF_DELAY 15 enum { ym3438_type_discrete = 0, /* Discrete YM3438 (Teradrive) */ ym3438_type_asic = 1, /* ASIC YM3438 (MD1 VA7, MD2, MD3, etc) */ ym3438_type_ym2612 = 2 /* YM2612 (MD1, MD2 VA2) */ }; /*EXTRA*/ typedef struct _opn2_writebuf { Bit64u time; Bit8u port; Bit8u data; Bit8u reserved[6]; } opn2_writebuf; typedef struct { Bit32u cycles; Bit32u channel; Bit16s mol, mor; /* IO */ Bit16u write_data; Bit8u write_a; Bit8u write_d; Bit8u write_a_en; Bit8u write_d_en; Bit8u write_busy; Bit8u write_busy_cnt; Bit8u write_fm_address; Bit8u write_fm_data; Bit8u write_fm_mode_a; Bit16u address; Bit8u data; Bit8u pin_test_in; Bit8u pin_irq; Bit8u busy; /* LFO */ Bit8u lfo_en; Bit8u lfo_freq; Bit8u lfo_pm; Bit8u lfo_am; Bit8u lfo_cnt; Bit8u lfo_inc; Bit8u lfo_quotient; /* Phase generator */ Bit16u pg_fnum; Bit8u pg_block; Bit8u pg_kcode; Bit32u pg_inc[24]; Bit32u pg_phase[24]; Bit8u pg_reset[24]; Bit32u pg_read; /* Envelope generator */ Bit8u eg_cycle; Bit8u eg_cycle_stop; Bit8u eg_shift; Bit8u eg_shift_lock; Bit8u eg_timer_low_lock; Bit16u eg_timer; Bit8u eg_timer_inc; Bit16u eg_quotient; Bit8u eg_custom_timer; Bit8u eg_rate; Bit8u eg_ksv; Bit8u eg_inc; Bit8u eg_ratemax; Bit8u eg_sl[2]; Bit8u eg_lfo_am; Bit8u eg_tl[2]; Bit8u eg_state[24]; Bit16u eg_level[24]; Bit16u eg_out[24]; Bit8u eg_kon[24]; Bit8u eg_kon_csm[24]; Bit8u eg_kon_latch[24]; Bit8u eg_csm_mode[24]; Bit8u eg_ssg_enable[24]; Bit8u eg_ssg_pgrst_latch[24]; Bit8u eg_ssg_repeat_latch[24]; Bit8u eg_ssg_hold_up_latch[24]; Bit8u eg_ssg_dir[24]; Bit8u eg_ssg_inv[24]; Bit32u eg_read[2]; Bit8u eg_read_inc; /* FM */ Bit16s fm_op1[6][2]; Bit16s fm_op2[6]; Bit16s fm_out[24]; Bit16u fm_mod[24]; /* Channel */ Bit16s ch_acc[6]; Bit16s ch_out[6]; Bit16s ch_lock; Bit8u ch_lock_l; Bit8u ch_lock_r; Bit16s ch_read; /* Timer */ Bit16u timer_a_cnt; Bit16u timer_a_reg; Bit8u timer_a_load_lock; Bit8u timer_a_load; Bit8u timer_a_enable; Bit8u timer_a_reset; Bit8u timer_a_load_latch; Bit8u timer_a_overflow_flag; Bit8u timer_a_overflow; Bit16u timer_b_cnt; Bit8u timer_b_subcnt; Bit16u timer_b_reg; Bit8u timer_b_load_lock; Bit8u timer_b_load; Bit8u timer_b_enable; Bit8u timer_b_reset; Bit8u timer_b_load_latch; Bit8u timer_b_overflow_flag; Bit8u timer_b_overflow; /* Register set */ Bit8u mode_test_21[8]; Bit8u mode_test_2c[8]; Bit8u mode_ch3; Bit8u mode_kon_channel; Bit8u mode_kon_operator[4]; Bit8u mode_kon[24]; Bit8u mode_csm; Bit8u mode_kon_csm; Bit8u dacen; Bit16s dacdata; Bit8u ks[24]; Bit8u ar[24]; Bit8u sr[24]; Bit8u dt[24]; Bit8u multi[24]; Bit8u sl[24]; Bit8u rr[24]; Bit8u dr[24]; Bit8u am[24]; Bit8u tl[24]; Bit8u ssg_eg[24]; Bit16u fnum[6]; Bit8u block[6]; Bit8u kcode[6]; Bit16u fnum_3ch[6]; Bit8u block_3ch[6]; Bit8u kcode_3ch[6]; Bit8u reg_a4; Bit8u reg_ac; Bit8u connect[6]; Bit8u fb[6]; Bit8u pan_l[6], pan_r[6]; Bit8u ams[6]; Bit8u pms[6]; /*EXTRA*/ Bit32u mute[7]; Bit32s rateratio; Bit32s samplecnt; Bit32s oldsamples[2]; Bit32s samples[2]; Bit64u writebuf_samplecnt; Bit32u writebuf_cur; Bit32u writebuf_last; Bit64u writebuf_lasttime; opn2_writebuf writebuf[OPN_WRITEBUF_SIZE]; } ym3438_t; /* EXTRA, original was "void OPN2_Reset(ym3438_t *chip)" */ void OPN2_Reset(ym3438_t *chip, Bit32u rate, Bit32u clock); void OPN2_SetChipType(Bit32u type); void OPN2_Clock(ym3438_t *chip, Bit16s *buffer); void OPN2_Write(ym3438_t *chip, Bit32u port, Bit8u data); void OPN2_SetTestPin(ym3438_t *chip, Bit32u value); Bit32u OPN2_ReadTestPin(ym3438_t *chip); Bit32u OPN2_ReadIRQPin(ym3438_t *chip); Bit8u OPN2_Read(ym3438_t *chip, Bit32u port); /*EXTRA*/ void OPN2_WriteBuffered(ym3438_t *chip, Bit32u port, Bit8u data); void OPN2_Generate(ym3438_t *chip, Bit16s *buf); void OPN2_GenerateResampled(ym3438_t *chip, Bit16s *buf); void OPN2_GenerateStream(ym3438_t *chip, Bit16s *output, Bit32u numsamples); void OPN2_GenerateStreamMix(ym3438_t *chip, Bit16s *output, Bit32u numsamples); void OPN2_SetOptions(Bit8u flags); void OPN2_SetMute(ym3438_t *chip, Bit32u mute); enum { eg_num_attack = 0, eg_num_decay = 1, eg_num_sustain = 2, eg_num_release = 3 }; /* logsin table */ static const Bit16u logsinrom[256] = { 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365, 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261, 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd, 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166, 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118, 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db, 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9, 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081, 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060, 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045, 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f, 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e, 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011, 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007, 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002, 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 }; /* exp table */ static const Bit16u exprom[256] = { 0x000, 0x003, 0x006, 0x008, 0x00b, 0x00e, 0x011, 0x014, 0x016, 0x019, 0x01c, 0x01f, 0x022, 0x025, 0x028, 0x02a, 0x02d, 0x030, 0x033, 0x036, 0x039, 0x03c, 0x03f, 0x042, 0x045, 0x048, 0x04b, 0x04e, 0x051, 0x054, 0x057, 0x05a, 0x05d, 0x060, 0x063, 0x066, 0x069, 0x06c, 0x06f, 0x072, 0x075, 0x078, 0x07b, 0x07e, 0x082, 0x085, 0x088, 0x08b, 0x08e, 0x091, 0x094, 0x098, 0x09b, 0x09e, 0x0a1, 0x0a4, 0x0a8, 0x0ab, 0x0ae, 0x0b1, 0x0b5, 0x0b8, 0x0bb, 0x0be, 0x0c2, 0x0c5, 0x0c8, 0x0cc, 0x0cf, 0x0d2, 0x0d6, 0x0d9, 0x0dc, 0x0e0, 0x0e3, 0x0e7, 0x0ea, 0x0ed, 0x0f1, 0x0f4, 0x0f8, 0x0fb, 0x0ff, 0x102, 0x106, 0x109, 0x10c, 0x110, 0x114, 0x117, 0x11b, 0x11e, 0x122, 0x125, 0x129, 0x12c, 0x130, 0x134, 0x137, 0x13b, 0x13e, 0x142, 0x146, 0x149, 0x14d, 0x151, 0x154, 0x158, 0x15c, 0x160, 0x163, 0x167, 0x16b, 0x16f, 0x172, 0x176, 0x17a, 0x17e, 0x181, 0x185, 0x189, 0x18d, 0x191, 0x195, 0x199, 0x19c, 0x1a0, 0x1a4, 0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4, 0x1c8, 0x1cc, 0x1d0, 0x1d4, 0x1d8, 0x1dc, 0x1e0, 0x1e4, 0x1e8, 0x1ec, 0x1f0, 0x1f5, 0x1f9, 0x1fd, 0x201, 0x205, 0x209, 0x20e, 0x212, 0x216, 0x21a, 0x21e, 0x223, 0x227, 0x22b, 0x230, 0x234, 0x238, 0x23c, 0x241, 0x245, 0x249, 0x24e, 0x252, 0x257, 0x25b, 0x25f, 0x264, 0x268, 0x26d, 0x271, 0x276, 0x27a, 0x27f, 0x283, 0x288, 0x28c, 0x291, 0x295, 0x29a, 0x29e, 0x2a3, 0x2a8, 0x2ac, 0x2b1, 0x2b5, 0x2ba, 0x2bf, 0x2c4, 0x2c8, 0x2cd, 0x2d2, 0x2d6, 0x2db, 0x2e0, 0x2e5, 0x2e9, 0x2ee, 0x2f3, 0x2f8, 0x2fd, 0x302, 0x306, 0x30b, 0x310, 0x315, 0x31a, 0x31f, 0x324, 0x329, 0x32e, 0x333, 0x338, 0x33d, 0x342, 0x347, 0x34c, 0x351, 0x356, 0x35b, 0x360, 0x365, 0x36a, 0x370, 0x375, 0x37a, 0x37f, 0x384, 0x38a, 0x38f, 0x394, 0x399, 0x39f, 0x3a4, 0x3a9, 0x3ae, 0x3b4, 0x3b9, 0x3bf, 0x3c4, 0x3c9, 0x3cf, 0x3d4, 0x3da, 0x3df, 0x3e4, 0x3ea, 0x3ef, 0x3f5, 0x3fa }; /* Note table */ static const Bit32u fn_note[16] = { 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3 }; /* Envelope generator */ static const Bit32u eg_stephi[4][4] = { { 0, 0, 0, 0 }, { 1, 0, 0, 0 }, { 1, 0, 1, 0 }, { 1, 1, 1, 0 } }; static const Bit8u eg_am_shift[4] = { 7, 3, 1, 0 }; /* Phase generator */ static const Bit32u pg_detune[8] = { 16, 17, 19, 20, 22, 24, 27, 29 }; static const Bit32u pg_lfo_sh1[8][8] = { { 7, 7, 7, 7, 7, 7, 7, 7 }, { 7, 7, 7, 7, 7, 7, 7, 7 }, { 7, 7, 7, 7, 7, 7, 1, 1 }, { 7, 7, 7, 7, 1, 1, 1, 1 }, { 7, 7, 7, 1, 1, 1, 1, 0 }, { 7, 7, 1, 1, 0, 0, 0, 0 }, { 7, 7, 1, 1, 0, 0, 0, 0 }, { 7, 7, 1, 1, 0, 0, 0, 0 } }; static const Bit32u pg_lfo_sh2[8][8] = { { 7, 7, 7, 7, 7, 7, 7, 7 }, { 7, 7, 7, 7, 2, 2, 2, 2 }, { 7, 7, 7, 2, 2, 2, 7, 7 }, { 7, 7, 2, 2, 7, 7, 2, 2 }, { 7, 7, 2, 7, 7, 7, 2, 7 }, { 7, 7, 7, 2, 7, 7, 2, 1 }, { 7, 7, 7, 2, 7, 7, 2, 1 }, { 7, 7, 7, 2, 7, 7, 2, 1 } }; /* Address decoder */ static const Bit32u op_offset[12] = { 0x000, /* Ch1 OP1/OP2 */ 0x001, /* Ch2 OP1/OP2 */ 0x002, /* Ch3 OP1/OP2 */ 0x100, /* Ch4 OP1/OP2 */ 0x101, /* Ch5 OP1/OP2 */ 0x102, /* Ch6 OP1/OP2 */ 0x004, /* Ch1 OP3/OP4 */ 0x005, /* Ch2 OP3/OP4 */ 0x006, /* Ch3 OP3/OP4 */ 0x104, /* Ch4 OP3/OP4 */ 0x105, /* Ch5 OP3/OP4 */ 0x106 /* Ch6 OP3/OP4 */ }; static const Bit32u ch_offset[6] = { 0x000, /* Ch1 */ 0x001, /* Ch2 */ 0x002, /* Ch3 */ 0x100, /* Ch4 */ 0x101, /* Ch5 */ 0x102 /* Ch6 */ }; /* LFO */ static const Bit32u lfo_cycles[8] = { 108, 77, 71, 67, 62, 44, 8, 5 }; /* FM algorithm */ static const Bit32u fm_algorithm[4][6][8] = { { { 1, 1, 1, 1, 1, 1, 1, 1 }, /* OP1_0 */ { 1, 1, 1, 1, 1, 1, 1, 1 }, /* OP1_1 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP2 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ { 0, 0, 0, 0, 0, 0, 0, 1 } /* Out */ }, { { 0, 1, 0, 0, 0, 1, 0, 0 }, /* OP1_0 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP1_1 */ { 1, 1, 1, 0, 0, 0, 0, 0 }, /* OP2 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ { 0, 0, 0, 0, 0, 1, 1, 1 } /* Out */ }, { { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP1_0 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP1_1 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP2 */ { 1, 0, 0, 1, 1, 1, 1, 0 }, /* Last operator */ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ { 0, 0, 0, 0, 1, 1, 1, 1 } /* Out */ }, { { 0, 0, 1, 0, 0, 1, 0, 0 }, /* OP1_0 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP1_1 */ { 0, 0, 0, 1, 0, 0, 0, 0 }, /* OP2 */ { 1, 1, 0, 1, 1, 0, 0, 0 }, /* Last operator */ { 0, 0, 1, 0, 0, 0, 0, 0 }, /* Last operator */ { 1, 1, 1, 1, 1, 1, 1, 1 } /* Out */ } }; static Bit32u chip_type = ym3438_type_discrete; void OPN2_DoIO(ym3438_t *chip) { /* Write signal check */ chip->write_a_en = (chip->write_a & 0x03) == 0x01; chip->write_d_en = (chip->write_d & 0x03) == 0x01; chip->write_a <<= 1; chip->write_d <<= 1; /* Busy counter */ chip->busy = chip->write_busy; chip->write_busy_cnt += chip->write_busy; chip->write_busy = (chip->write_busy && !(chip->write_busy_cnt >> 5)) || chip->write_d_en; chip->write_busy_cnt &= 0x1f; } void OPN2_DoRegWrite(ym3438_t *chip) { Bit32u i; Bit32u slot = chip->cycles % 12; Bit32u address; Bit32u channel = chip->channel; /* Update registers */ if (chip->write_fm_data) { /* Slot */ if (op_offset[slot] == (chip->address & 0x107)) { if (chip->address & 0x08) { /* OP2, OP4 */ slot += 12; } address = chip->address & 0xf0; switch (address) { case 0x30: /* DT, MULTI */ chip->multi[slot] = chip->data & 0x0f; if (!chip->multi[slot]) { chip->multi[slot] = 1; } else { chip->multi[slot] <<= 1; } chip->dt[slot] = (chip->data >> 4) & 0x07; break; case 0x40: /* TL */ chip->tl[slot] = chip->data & 0x7f; break; case 0x50: /* KS, AR */ chip->ar[slot] = chip->data & 0x1f; chip->ks[slot] = (chip->data >> 6) & 0x03; break; case 0x60: /* AM, DR */ chip->dr[slot] = chip->data & 0x1f; chip->am[slot] = (chip->data >> 7) & 0x01; break; case 0x70: /* SR */ chip->sr[slot] = chip->data & 0x1f; break; case 0x80: /* SL, RR */ chip->rr[slot] = chip->data & 0x0f; chip->sl[slot] = (chip->data >> 4) & 0x0f; chip->sl[slot] |= (chip->sl[slot] + 1) & 0x10; break; case 0x90: /* SSG-EG */ chip->ssg_eg[slot] = chip->data & 0x0f; break; default: break; } } /* Channel */ if (ch_offset[channel] == (chip->address & 0x103)) { address = chip->address & 0xfc; switch (address) { case 0xa0: chip->fnum[channel] = (chip->data & 0xff) | ((chip->reg_a4 & 0x07) << 8); chip->block[channel] = (chip->reg_a4 >> 3) & 0x07; chip->kcode[channel] = (chip->block[channel] << 2) | fn_note[chip->fnum[channel] >> 7]; break; case 0xa4: chip->reg_a4 = chip->data & 0xff; break; case 0xa8: chip->fnum_3ch[channel] = (chip->data & 0xff) | ((chip->reg_ac & 0x07) << 8); chip->block_3ch[channel] = (chip->reg_ac >> 3) & 0x07; chip->kcode_3ch[channel] = (chip->block_3ch[channel] << 2) | fn_note[chip->fnum_3ch[channel] >> 7]; break; case 0xac: chip->reg_ac = chip->data & 0xff; break; case 0xb0: chip->connect[channel] = chip->data & 0x07; chip->fb[channel] = (chip->data >> 3) & 0x07; break; case 0xb4: chip->pms[channel] = chip->data & 0x07; chip->ams[channel] = (chip->data >> 4) & 0x03; chip->pan_l[channel] = (chip->data >> 7) & 0x01; chip->pan_r[channel] = (chip->data >> 6) & 0x01; break; default: break; } } } if (chip->write_a_en || chip->write_d_en) { /* Data */ if (chip->write_a_en) { chip->write_fm_data = 0; } if (chip->write_fm_address && chip->write_d_en) { chip->write_fm_data = 1; } /* Address */ if (chip->write_a_en) { if ((chip->write_data & 0xf0) != 0x00) { /* FM Write */ chip->address = chip->write_data; chip->write_fm_address = 1; } else { /* SSG write */ chip->write_fm_address = 0; } } /* FM Mode */ /* Data */ if (chip->write_d_en && (chip->write_data & 0x100) == 0) { switch (chip->address) { case 0x21: /* LSI test 1 */ for (i = 0; i < 8; i++) { chip->mode_test_21[i] = (chip->write_data >> i) & 0x01; } break; case 0x22: /* LFO control */ if ((chip->write_data >> 3) & 0x01) { chip->lfo_en = 0x7f; } else { chip->lfo_en = 0; } chip->lfo_freq = chip->write_data & 0x07; break; case 0x24: /* Timer A */ chip->timer_a_reg &= 0x03; chip->timer_a_reg |= (chip->write_data & 0xff) << 2; break; case 0x25: chip->timer_a_reg &= 0x3fc; chip->timer_a_reg |= chip->write_data & 0x03; break; case 0x26: /* Timer B */ chip->timer_b_reg = chip->write_data & 0xff; break; case 0x27: /* CSM, Timer control */ chip->mode_ch3 = (chip->write_data & 0xc0) >> 6; chip->mode_csm = chip->mode_ch3 == 2; chip->timer_a_load = chip->write_data & 0x01; chip->timer_a_enable = (chip->write_data >> 2) & 0x01; chip->timer_a_reset = (chip->write_data >> 4) & 0x01; chip->timer_b_load = (chip->write_data >> 1) & 0x01; chip->timer_b_enable = (chip->write_data >> 3) & 0x01; chip->timer_b_reset = (chip->write_data >> 5) & 0x01; break; case 0x28: /* Key on/off */ for (i = 0; i < 4; i++) { chip->mode_kon_operator[i] = (chip->write_data >> (4 + i)) & 0x01; } if ((chip->write_data & 0x03) == 0x03) { /* Invalid address */ chip->mode_kon_channel = 0xff; } else { chip->mode_kon_channel = (chip->write_data & 0x03) + ((chip->write_data >> 2) & 1) * 3; } break; case 0x2a: /* DAC data */ chip->dacdata &= 0x01; chip->dacdata |= (chip->write_data ^ 0x80) << 1; break; case 0x2b: /* DAC enable */ chip->dacen = chip->write_data >> 7; break; case 0x2c: /* LSI test 2 */ for (i = 0; i < 8; i++) { chip->mode_test_2c[i] = (chip->write_data >> i) & 0x01; } chip->dacdata &= 0x1fe; chip->dacdata |= chip->mode_test_2c[3]; chip->eg_custom_timer = !chip->mode_test_2c[7] && chip->mode_test_2c[6]; break; default: break; } } /* Address */ if (chip->write_a_en) { chip->write_fm_mode_a = chip->write_data & 0xff; } } if (chip->write_fm_data) { chip->data = chip->write_data & 0xff; } } void OPN2_PhaseCalcIncrement(ym3438_t *chip) { Bit32u chan = chip->channel; Bit32u slot = chip->cycles; Bit32u fnum = chip->pg_fnum; Bit32u fnum_h = fnum >> 4; Bit32u fm; Bit32u basefreq; Bit8u lfo = chip->lfo_pm; Bit8u lfo_l = lfo & 0x0f; Bit8u pms = chip->pms[chan]; Bit8u dt = chip->dt[slot]; Bit8u dt_l = dt & 0x03; Bit8u detune = 0; Bit8u block, note; Bit8u sum, sum_h, sum_l; Bit8u kcode = chip->pg_kcode; fnum <<= 1; /* Apply LFO */ if (lfo_l & 0x08) { lfo_l ^= 0x0f; } fm = (fnum_h >> pg_lfo_sh1[pms][lfo_l]) + (fnum_h >> pg_lfo_sh2[pms][lfo_l]); if (pms > 5) { fm <<= pms - 5; } fm >>= 2; if (lfo & 0x10) { fnum -= fm; } else { fnum += fm; } fnum &= 0xfff; basefreq = (fnum << chip->pg_block) >> 2; /* Apply detune */ if (dt_l) { if (kcode > 0x1c) { kcode = 0x1c; } block = kcode >> 2; note = kcode & 0x03; sum = block + 9 + ((dt_l == 3) | (dt_l & 0x02)); sum_h = sum >> 1; sum_l = sum & 0x01; detune = pg_detune[(sum_l << 2) | note] >> (9 - sum_h); } if (dt & 0x04) { basefreq -= detune; } else { basefreq += detune; } basefreq &= 0x1ffff; chip->pg_inc[slot] = (basefreq * chip->multi[slot]) >> 1; chip->pg_inc[slot] &= 0xfffff; } void OPN2_PhaseGenerate(ym3438_t *chip) { Bit32u slot; /* Mask increment */ slot = (chip->cycles + 20) % 24; if (chip->pg_reset[slot]) { chip->pg_inc[slot] = 0; } /* Phase step */ slot = (chip->cycles + 19) % 24; chip->pg_phase[slot] += chip->pg_inc[slot]; chip->pg_phase[slot] &= 0xfffff; if (chip->pg_reset[slot] || chip->mode_test_21[3]) { chip->pg_phase[slot] = 0; } } void OPN2_EnvelopeSSGEG(ym3438_t *chip) { Bit32u slot = chip->cycles; Bit8u direction = 0; chip->eg_ssg_pgrst_latch[slot] = 0; chip->eg_ssg_repeat_latch[slot] = 0; chip->eg_ssg_hold_up_latch[slot] = 0; chip->eg_ssg_inv[slot] = 0; if (chip->ssg_eg[slot] & 0x08) { direction = chip->eg_ssg_dir[slot]; if (chip->eg_level[slot] & 0x200) { /* Reset */ if ((chip->ssg_eg[slot] & 0x03) == 0x00) { chip->eg_ssg_pgrst_latch[slot] = 1; } /* Repeat */ if ((chip->ssg_eg[slot] & 0x01) == 0x00) { chip->eg_ssg_repeat_latch[slot] = 1; } /* Inverse */ if ((chip->ssg_eg[slot] & 0x03) == 0x02) { direction ^= 1; } if ((chip->ssg_eg[slot] & 0x03) == 0x03) { direction = 1; } } /* Hold up */ if (chip->eg_kon_latch[slot] && ((chip->ssg_eg[slot] & 0x07) == 0x05 || (chip->ssg_eg[slot] & 0x07) == 0x03)) { chip->eg_ssg_hold_up_latch[slot] = 1; } direction &= chip->eg_kon[slot]; chip->eg_ssg_inv[slot] = (chip->eg_ssg_dir[slot] ^ ((chip->ssg_eg[slot] >> 2) & 0x01)) & chip->eg_kon[slot]; } chip->eg_ssg_dir[slot] = direction; chip->eg_ssg_enable[slot] = (chip->ssg_eg[slot] >> 3) & 0x01; } void OPN2_EnvelopeADSR(ym3438_t *chip) { Bit32u slot = (chip->cycles + 22) % 24; Bit8u nkon = chip->eg_kon_latch[slot]; Bit8u okon = chip->eg_kon[slot]; Bit8u kon_event; Bit8u koff_event; Bit8u eg_off; Bit16s level; Bit16s nextlevel = 0; Bit16s ssg_level; Bit8u nextstate = chip->eg_state[slot]; Bit16s inc = 0; chip->eg_read[0] = chip->eg_read_inc; chip->eg_read_inc = chip->eg_inc > 0; /* Reset phase generator */ chip->pg_reset[slot] = (nkon && !okon) || chip->eg_ssg_pgrst_latch[slot]; /* KeyOn/Off */ kon_event = (nkon && !okon) || (okon && chip->eg_ssg_repeat_latch[slot]); koff_event = okon && !nkon; ssg_level = level = (Bit16s)chip->eg_level[slot]; if (chip->eg_ssg_inv[slot]) { /* Inverse */ ssg_level = 512 - level; ssg_level &= 0x3ff; } if (koff_event) { level = ssg_level; } if (chip->eg_ssg_enable[slot]) { eg_off = level >> 9; } else { eg_off = (level & 0x3f0) == 0x3f0; } nextlevel = level; if (kon_event) { nextstate = eg_num_attack; /* Instant attack */ if (chip->eg_ratemax) { nextlevel = 0; } else if (chip->eg_state[slot] == eg_num_attack && level != 0 && chip->eg_inc && nkon) { inc = (~level << chip->eg_inc) >> 5; } } else { switch (chip->eg_state[slot]) { case eg_num_attack: if (level == 0) { nextstate = eg_num_decay; } else if(chip->eg_inc && !chip->eg_ratemax && nkon) { inc = (~level << chip->eg_inc) >> 5; } break; case eg_num_decay: if ((level >> 5) == chip->eg_sl[1]) { nextstate = eg_num_sustain; } else if (!eg_off && chip->eg_inc) { inc = 1 << (chip->eg_inc - 1); if (chip->eg_ssg_enable[slot]) { inc <<= 2; } } break; case eg_num_sustain: case eg_num_release: if (!eg_off && chip->eg_inc) { inc = 1 << (chip->eg_inc - 1); if (chip->eg_ssg_enable[slot]) { inc <<= 2; } } break; default: break; } if (!nkon) { nextstate = eg_num_release; } } if (chip->eg_kon_csm[slot]) { nextlevel |= chip->eg_tl[1] << 3; } /* Envelope off */ if (!kon_event && !chip->eg_ssg_hold_up_latch[slot] && chip->eg_state[slot] != eg_num_attack && eg_off) { nextstate = eg_num_release; nextlevel = 0x3ff; } nextlevel += inc; chip->eg_kon[slot] = chip->eg_kon_latch[slot]; chip->eg_level[slot] = (Bit16u)nextlevel & 0x3ff; chip->eg_state[slot] = nextstate; } void OPN2_EnvelopePrepare(ym3438_t *chip) { Bit8u rate; Bit8u sum; Bit8u inc = 0; Bit32u slot = chip->cycles; Bit8u rate_sel; /* Prepare increment */ rate = (chip->eg_rate << 1) + chip->eg_ksv; if (rate > 0x3f) { rate = 0x3f; } sum = ((rate >> 2) + chip->eg_shift_lock) & 0x0f; if (chip->eg_rate != 0 && chip->eg_quotient == 2) { if (rate < 48) { switch (sum) { case 12: inc = 1; break; case 13: inc = (rate >> 1) & 0x01; break; case 14: inc = rate & 0x01; break; default: break; } } else { inc = eg_stephi[rate & 0x03][chip->eg_timer_low_lock] + (rate >> 2) - 11; if (inc > 4) { inc = 4; } } } chip->eg_inc = inc; chip->eg_ratemax = (rate >> 1) == 0x1f; /* Prepare rate & ksv */ rate_sel = chip->eg_state[slot]; if ((chip->eg_kon[slot] && chip->eg_ssg_repeat_latch[slot]) || (!chip->eg_kon[slot] && chip->eg_kon_latch[slot])) { rate_sel = eg_num_attack; } switch (rate_sel) { case eg_num_attack: chip->eg_rate = chip->ar[slot]; break; case eg_num_decay: chip->eg_rate = chip->dr[slot]; break; case eg_num_sustain: chip->eg_rate = chip->sr[slot]; break; case eg_num_release: chip->eg_rate = (chip->rr[slot] << 1) | 0x01; break; default: break; } chip->eg_ksv = chip->pg_kcode >> (chip->ks[slot] ^ 0x03); if (chip->am[slot]) { chip->eg_lfo_am = chip->lfo_am >> eg_am_shift[chip->ams[chip->channel]]; } else { chip->eg_lfo_am = 0; } /* Delay TL & SL value */ chip->eg_tl[1] = chip->eg_tl[0]; chip->eg_tl[0] = chip->tl[slot]; chip->eg_sl[1] = chip->eg_sl[0]; chip->eg_sl[0] = chip->sl[slot]; } void OPN2_EnvelopeGenerate(ym3438_t *chip) { Bit32u slot = (chip->cycles + 23) % 24; Bit16u level; level = chip->eg_level[slot]; if (chip->eg_ssg_inv[slot]) { /* Inverse */ level = 512 - level; } if (chip->mode_test_21[5]) { level = 0; } level &= 0x3ff; /* Apply AM LFO */ level += chip->eg_lfo_am; /* Apply TL */ if (!(chip->mode_csm && chip->channel == 2 + 1)) { level += chip->eg_tl[0] << 3; } if (level > 0x3ff) { level = 0x3ff; } chip->eg_out[slot] = level; } void OPN2_UpdateLFO(ym3438_t *chip) { if ((chip->lfo_quotient & lfo_cycles[chip->lfo_freq]) == lfo_cycles[chip->lfo_freq]) { chip->lfo_quotient = 0; chip->lfo_cnt++; } else { chip->lfo_quotient += chip->lfo_inc; } chip->lfo_cnt &= chip->lfo_en; } void OPN2_FMPrepare(ym3438_t *chip) { Bit32u slot = (chip->cycles + 6) % 24; Bit32u channel = chip->channel; Bit16s mod, mod1, mod2; Bit32u op = slot / 6; Bit8u connect = chip->connect[channel]; Bit32u prevslot = (chip->cycles + 18) % 24; /* Calculate modulation */ mod1 = mod2 = 0; if (fm_algorithm[op][0][connect]) { mod2 |= chip->fm_op1[channel][0]; } if (fm_algorithm[op][1][connect]) { mod1 |= chip->fm_op1[channel][1]; } if (fm_algorithm[op][2][connect]) { mod1 |= chip->fm_op2[channel]; } if (fm_algorithm[op][3][connect]) { mod2 |= chip->fm_out[prevslot]; } if (fm_algorithm[op][4][connect]) { mod1 |= chip->fm_out[prevslot]; } mod = mod1 + mod2; if (op == 0) { /* Feedback */ mod = mod >> (10 - chip->fb[channel]); if (!chip->fb[channel]) { mod = 0; } } else { mod >>= 1; } chip->fm_mod[slot] = mod; slot = (chip->cycles + 18) % 24; /* OP1 */ if (slot / 6 == 0) { chip->fm_op1[channel][1] = chip->fm_op1[channel][0]; chip->fm_op1[channel][0] = chip->fm_out[slot]; } /* OP2 */ if (slot / 6 == 2) { chip->fm_op2[channel] = chip->fm_out[slot]; } } void OPN2_ChGenerate(ym3438_t *chip) { Bit32u slot = (chip->cycles + 18) % 24; Bit32u channel = chip->channel; Bit32u op = slot / 6; Bit32u test_dac = chip->mode_test_2c[5]; Bit16s acc = chip->ch_acc[channel]; Bit16s add = test_dac; Bit16s sum = 0; if (op == 0 && !test_dac) { acc = 0; } if (fm_algorithm[op][5][chip->connect[channel]] && !test_dac) { add += chip->fm_out[slot] >> 5; } sum = acc + add; /* Clamp */ if (sum > 255) { sum = 255; } else if(sum < -256) { sum = -256; } if (op == 0 || test_dac) { chip->ch_out[channel] = chip->ch_acc[channel]; } chip->ch_acc[channel] = sum; } void OPN2_ChOutput(ym3438_t *chip) { Bit32u cycles = chip->cycles; Bit32u slot = chip->cycles; Bit32u channel = chip->channel; Bit32u test_dac = chip->mode_test_2c[5]; Bit16s out; Bit16s sign; Bit32u out_en; chip->ch_read = chip->ch_lock; if (slot < 12) { /* Ch 4,5,6 */ channel++; } if ((cycles & 3) == 0) { if (!test_dac) { /* Lock value */ chip->ch_lock = chip->ch_out[channel]; } chip->ch_lock_l = chip->pan_l[channel]; chip->ch_lock_r = chip->pan_r[channel]; } /* Ch 6 */ if (((cycles >> 2) == 1 && chip->dacen) || test_dac) { out = (Bit16s)chip->dacdata; out <<= 7; out >>= 7; } else { out = chip->ch_lock; } chip->mol = 0; chip->mor = 0; if (chip_type == ym3438_type_ym2612) { out_en = ((cycles & 3) == 3) || test_dac; /* YM2612 DAC emulation(not verified) */ sign = out >> 8; if (out >= 0) { out++; sign++; } if (chip->ch_lock_l && out_en) { chip->mol = out; } else { chip->mol = sign; } if (chip->ch_lock_r && out_en) { chip->mor = out; } else { chip->mor = sign; } /* Amplify signal */ chip->mol *= 3; chip->mor *= 3; } else { out_en = ((cycles & 3) != 0) || test_dac; /* Discrete YM3438 seems has the ladder effect too */ if (out >= 0 && chip_type == ym3438_type_discrete) { out++; } if (chip->ch_lock_l && out_en) { chip->mol = out; } if (chip->ch_lock_r && out_en) { chip->mor = out; } } } void OPN2_FMGenerate(ym3438_t *chip) { Bit32u slot = (chip->cycles + 19) % 24; /* Calculate phase */ Bit16u phase = (chip->fm_mod[slot] + (chip->pg_phase[slot] >> 10)) & 0x3ff; Bit16u quarter; Bit16u level; Bit16s output; if (phase & 0x100) { quarter = (phase ^ 0xff) & 0xff; } else { quarter = phase & 0xff; } level = logsinrom[quarter]; /* Apply envelope */ level += chip->eg_out[slot] << 2; /* Transform */ if (level > 0x1fff) { level = 0x1fff; } output = ((exprom[(level & 0xff) ^ 0xff] | 0x400) << 2) >> (level >> 8); if (phase & 0x200) { output = ((~output) ^ (chip->mode_test_21[4] << 13)) + 1; } else { output = output ^ (chip->mode_test_21[4] << 13); } output <<= 2; output >>= 2; chip->fm_out[slot] = output; } void OPN2_DoTimerA(ym3438_t *chip) { Bit16u time; Bit8u load; load = chip->timer_a_overflow; if (chip->cycles == 2) { /* Lock load value */ load |= (!chip->timer_a_load_lock && chip->timer_a_load); chip->timer_a_load_lock = chip->timer_a_load; if (chip->mode_csm) { /* CSM KeyOn */ chip->mode_kon_csm = load; } else { chip->mode_kon_csm = 0; } } /* Load counter */ if (chip->timer_a_load_latch) { time = chip->timer_a_reg; } else { time = chip->timer_a_cnt; } chip->timer_a_load_latch = load; /* Increase counter */ if ((chip->cycles == 1 && chip->timer_a_load_lock) || chip->mode_test_21[2]) { time++; } /* Set overflow flag */ if (chip->timer_a_reset) { chip->timer_a_reset = 0; chip->timer_a_overflow_flag = 0; } else { chip->timer_a_overflow_flag |= chip->timer_a_overflow & chip->timer_a_enable; } chip->timer_a_overflow = (time >> 10); chip->timer_a_cnt = time & 0x3ff; } void OPN2_DoTimerB(ym3438_t *chip) { Bit16u time; Bit8u load; load = chip->timer_b_overflow; if (chip->cycles == 2) { /* Lock load value */ load |= (!chip->timer_b_load_lock && chip->timer_b_load); chip->timer_b_load_lock = chip->timer_b_load; } /* Load counter */ if (chip->timer_b_load_latch) { time = chip->timer_b_reg; } else { time = chip->timer_b_cnt; } chip->timer_b_load_latch = load; /* Increase counter */ if (chip->cycles == 1) { chip->timer_b_subcnt++; } if ((chip->timer_b_subcnt == 0x10 && chip->timer_b_load_lock) || chip->mode_test_21[2]) { time++; } chip->timer_b_subcnt &= 0x0f; /* Set overflow flag */ if (chip->timer_b_reset) { chip->timer_b_reset = 0; chip->timer_b_overflow_flag = 0; } else { chip->timer_b_overflow_flag |= chip->timer_b_overflow & chip->timer_b_enable; } chip->timer_b_overflow = (time >> 8); chip->timer_b_cnt = time & 0xff; } void OPN2_KeyOn(ym3438_t*chip) { Bit32u slot = chip->cycles; Bit32u chan = chip->channel; /* Key On */ chip->eg_kon_latch[slot] = chip->mode_kon[slot]; chip->eg_kon_csm[slot] = 0; if (chip->channel == 2 && chip->mode_kon_csm) { /* CSM Key On */ chip->eg_kon_latch[slot] = 1; chip->eg_kon_csm[slot] = 1; } if (chip->cycles == chip->mode_kon_channel) { /* OP1 */ chip->mode_kon[chan] = chip->mode_kon_operator[0]; /* OP2 */ chip->mode_kon[chan + 12] = chip->mode_kon_operator[1]; /* OP3 */ chip->mode_kon[chan + 6] = chip->mode_kon_operator[2]; /* OP4 */ chip->mode_kon[chan + 18] = chip->mode_kon_operator[3]; } } void OPN2_Reset(ym3438_t *chip, Bit32u rate, Bit32u clock) { Bit32u i, rateratio; rateratio = (Bit32u)chip->rateratio; memset(chip, 0, sizeof(ym3438_t)); for (i = 0; i < 24; i++) { chip->eg_out[i] = 0x3ff; chip->eg_level[i] = 0x3ff; chip->eg_state[i] = eg_num_release; chip->multi[i] = 1; } for (i = 0; i < 6; i++) { chip->pan_l[i] = 1; chip->pan_r[i] = 1; } if (rate != 0) { chip->rateratio = (Bit32s)(Bit32u)((((Bit64u)144 * rate) << RSM_FRAC) / clock); } else { chip->rateratio = (Bit32s)rateratio; } } void OPN2_SetChipType(Bit32u type) { chip_type = type; } void OPN2_Clock(ym3438_t *chip, Bit16s *buffer) { Bit32u slot = chip->cycles; chip->lfo_inc = chip->mode_test_21[1]; chip->pg_read >>= 1; chip->eg_read[1] >>= 1; chip->eg_cycle++; /* Lock envelope generator timer value */ if (chip->cycles == 1 && chip->eg_quotient == 2) { if (chip->eg_cycle_stop) { chip->eg_shift_lock = 0; } else { chip->eg_shift_lock = chip->eg_shift + 1; } chip->eg_timer_low_lock = chip->eg_timer & 0x03; } /* Cycle specific functions */ switch (chip->cycles) { case 0: chip->lfo_pm = chip->lfo_cnt >> 2; if (chip->lfo_cnt & 0x40) { chip->lfo_am = chip->lfo_cnt & 0x3f; } else { chip->lfo_am = chip->lfo_cnt ^ 0x3f; } chip->lfo_am <<= 1; break; case 1: chip->eg_quotient++; chip->eg_quotient %= 3; chip->eg_cycle = 0; chip->eg_cycle_stop = 1; chip->eg_shift = 0; chip->eg_timer_inc |= chip->eg_quotient >> 1; chip->eg_timer = chip->eg_timer + chip->eg_timer_inc; chip->eg_timer_inc = chip->eg_timer >> 12; chip->eg_timer &= 0xfff; break; case 2: chip->pg_read = chip->pg_phase[21] & 0x3ff; chip->eg_read[1] = chip->eg_out[0]; break; case 13: chip->eg_cycle = 0; chip->eg_cycle_stop = 1; chip->eg_shift = 0; chip->eg_timer = chip->eg_timer + chip->eg_timer_inc; chip->eg_timer_inc = chip->eg_timer >> 12; chip->eg_timer &= 0xfff; break; case 23: chip->lfo_inc |= 1; break; } chip->eg_timer &= ~(chip->mode_test_21[5] << chip->eg_cycle); if (((chip->eg_timer >> chip->eg_cycle) | (chip->pin_test_in & chip->eg_custom_timer)) & chip->eg_cycle_stop) { chip->eg_shift = chip->eg_cycle; chip->eg_cycle_stop = 0; } OPN2_DoIO(chip); OPN2_DoTimerA(chip); OPN2_DoTimerB(chip); OPN2_KeyOn(chip); OPN2_ChOutput(chip); OPN2_ChGenerate(chip); OPN2_FMPrepare(chip); OPN2_FMGenerate(chip); OPN2_PhaseGenerate(chip); OPN2_PhaseCalcIncrement(chip); OPN2_EnvelopeADSR(chip); OPN2_EnvelopeGenerate(chip); OPN2_EnvelopeSSGEG(chip); OPN2_EnvelopePrepare(chip); /* Prepare fnum & block */ if (chip->mode_ch3) { /* Channel 3 special mode */ switch (slot) { case 1: /* OP1 */ chip->pg_fnum = chip->fnum_3ch[1]; chip->pg_block = chip->block_3ch[1]; chip->pg_kcode = chip->kcode_3ch[1]; break; case 7: /* OP3 */ chip->pg_fnum = chip->fnum_3ch[0]; chip->pg_block = chip->block_3ch[0]; chip->pg_kcode = chip->kcode_3ch[0]; break; case 13: /* OP2 */ chip->pg_fnum = chip->fnum_3ch[2]; chip->pg_block = chip->block_3ch[2]; chip->pg_kcode = chip->kcode_3ch[2]; break; case 19: /* OP4 */ default: chip->pg_fnum = chip->fnum[(chip->channel + 1) % 6]; chip->pg_block = chip->block[(chip->channel + 1) % 6]; chip->pg_kcode = chip->kcode[(chip->channel + 1) % 6]; break; } } else { chip->pg_fnum = chip->fnum[(chip->channel + 1) % 6]; chip->pg_block = chip->block[(chip->channel + 1) % 6]; chip->pg_kcode = chip->kcode[(chip->channel + 1) % 6]; } OPN2_UpdateLFO(chip); OPN2_DoRegWrite(chip); chip->cycles = (chip->cycles + 1) % 24; chip->channel = chip->cycles % 6; buffer[0] = chip->mol; buffer[1] = chip->mor; } void OPN2_Write(ym3438_t *chip, Bit32u port, Bit8u data) { port &= 3; chip->write_data = ((port << 7) & 0x100) | data; if (port & 1) { /* Data */ chip->write_d |= 1; } else { /* Address */ chip->write_a |= 1; } } void OPN2_SetTestPin(ym3438_t *chip, Bit32u value) { chip->pin_test_in = value & 1; } Bit32u OPN2_ReadTestPin(ym3438_t *chip) { if (!chip->mode_test_2c[7]) { return 0; } return chip->cycles == 23; } Bit32u OPN2_ReadIRQPin(ym3438_t *chip) { return chip->timer_a_overflow_flag | chip->timer_b_overflow_flag; } Bit8u OPN2_Read(ym3438_t *chip, Bit32u port) { if ((port & 3) == 0 || chip_type == ym3438_type_asic) { if (chip->mode_test_21[6]) { /* Read test data */ Bit32u slot = (chip->cycles + 18) % 24; Bit16u testdata = ((chip->pg_read & 0x01) << 15) | ((chip->eg_read[chip->mode_test_21[0]] & 0x01) << 14); if (chip->mode_test_2c[4]) { testdata |= chip->ch_read & 0x1ff; } else { testdata |= chip->fm_out[slot] & 0x3fff; } if (chip->mode_test_21[7]) { return testdata & 0xff; } else { return testdata >> 8; } } else { return (Bit8u)(chip->busy << 7) | (Bit8u)(chip->timer_b_overflow_flag << 1) | (Bit8u)chip->timer_a_overflow_flag; } } return 0; } void OPN2_WriteBuffered(ym3438_t *chip, Bit32u port, Bit8u data) { Bit64u time1, time2; Bit16s buffer[2]; Bit64u skip; if (chip->writebuf[chip->writebuf_last].port & 0x04) { OPN2_Write(chip, chip->writebuf[chip->writebuf_last].port & 0X03, chip->writebuf[chip->writebuf_last].data); chip->writebuf_cur = (chip->writebuf_last + 1) % OPN_WRITEBUF_SIZE; skip = chip->writebuf[chip->writebuf_last].time - chip->writebuf_samplecnt; chip->writebuf_samplecnt = chip->writebuf[chip->writebuf_last].time; while (skip--) { OPN2_Clock(chip, buffer); } } chip->writebuf[chip->writebuf_last].port = (port & 0x03) | 0x04; chip->writebuf[chip->writebuf_last].data = data; time1 = chip->writebuf_lasttime + OPN_WRITEBUF_DELAY; time2 = chip->writebuf_samplecnt; if (time1 < time2) { time1 = time2; } chip->writebuf[chip->writebuf_last].time = time1; chip->writebuf_lasttime = time1; chip->writebuf_last = (chip->writebuf_last + 1) % OPN_WRITEBUF_SIZE; } void OPN2_Generate(ym3438_t *chip, Bit16s *buf) { Bit32u i; Bit16s buffer[2]; Bit32u mute; buf[0] = 0; buf[1] = 0; for (i = 0; i < 24; i++) { switch (chip->cycles >> 2) { case 0: /* Ch 2 */ mute = chip->mute[1]; break; case 1: /* Ch 6, DAC */ mute = chip->mute[5 + chip->dacen]; break; case 2: /* Ch 4 */ mute = chip->mute[3]; break; case 3: /* Ch 1 */ mute = chip->mute[0]; break; case 4: /* Ch 5 */ mute = chip->mute[4]; break; case 5: /* Ch 3 */ mute = chip->mute[2]; break; default: mute = 0; break; } OPN2_Clock(chip, buffer); if (!mute) { buf[0] += buffer[0]; buf[1] += buffer[1]; } while (chip->writebuf[chip->writebuf_cur].time <= chip->writebuf_samplecnt) { if (!(chip->writebuf[chip->writebuf_cur].port & 0x04)) { break; } chip->writebuf[chip->writebuf_cur].port &= 0x03; OPN2_Write(chip, chip->writebuf[chip->writebuf_cur].port, chip->writebuf[chip->writebuf_cur].data); chip->writebuf_cur = (chip->writebuf_cur + 1) % OPN_WRITEBUF_SIZE; } chip->writebuf_samplecnt++; } } void OPN2_GenerateResampled(ym3438_t *chip, Bit16s *buf) { Bit16s buffer[2]; while (chip->samplecnt >= chip->rateratio) { chip->oldsamples[0] = chip->samples[0]; chip->oldsamples[1] = chip->samples[1]; OPN2_Generate(chip, buffer); chip->samples[0] = buffer[0] * 11; chip->samples[1] = buffer[1] * 11; chip->samplecnt -= chip->rateratio; } buf[0] = (Bit16s)(((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) + chip->samples[0] * chip->samplecnt) / chip->rateratio)>>1); buf[1] = (Bit16s)(((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) + chip->samples[1] * chip->samplecnt) / chip->rateratio)>>1); chip->samplecnt += 1 << RSM_FRAC; } void OPN2_GenerateStream(ym3438_t *chip, Bit16s *output, Bit32u numsamples) { Bit32u i; Bit16s buffer[2]; for (i = 0; i < numsamples; i++) { OPN2_GenerateResampled(chip, buffer); *output++ = buffer[0]; *output++ = buffer[1]; } } void OPN2_GenerateStreamMix(ym3438_t *chip, Bit16s *output, Bit32u numsamples) { Bit32u i; Bit16s buffer[2]; for (i = 0; i < numsamples; i++) { OPN2_GenerateResampled(chip, buffer); *output++ += buffer[0]; *output++ += buffer[1]; } } void OPN2_SetOptions(Bit8u flags) { switch ((flags >> 3) & 0x03) { case 0x00: /* YM2612 */ default: OPN2_SetChipType(ym3438_type_ym2612); break; case 0x01: /* ASIC YM3438 */ OPN2_SetChipType(ym3438_type_asic); break; case 0x02: /* Discrete YM3438 */ OPN2_SetChipType(ym3438_type_discrete); break; } } void OPN2_SetMute(ym3438_t *chip, Bit32u mute) { Bit32u i; for (i = 0; i < 7; i++) { chip->mute[i] = (mute >> i) & 0x01; } } } // Ym2612_NukedImpl Ym2612_Nuked_Emu::Ym2612_Nuked_Emu() { Ym2612_NukedImpl::OPN2_SetChipType( Ym2612_NukedImpl::ym3438_type_asic ); impl = new Ym2612_NukedImpl::ym3438_t; } Ym2612_Nuked_Emu::~Ym2612_Nuked_Emu() { Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); if ( chip_r ) delete chip_r; } const char *Ym2612_Nuked_Emu::set_rate(double sample_rate, double clock_rate) { Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); if ( !chip_r ) return "Out of memory"; prev_sample_rate = sample_rate; prev_clock_rate = clock_rate; Ym2612_NukedImpl::OPN2_Reset( chip_r, static_cast(sample_rate), static_cast(clock_rate) ); return 0; } void Ym2612_Nuked_Emu::reset() { Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); if ( !chip_r ) Ym2612_NukedImpl::OPN2_Reset( chip_r, static_cast(prev_sample_rate), static_cast(prev_clock_rate) ); } void Ym2612_Nuked_Emu::mute_voices(int mask) { Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); if ( chip_r ) Ym2612_NukedImpl::OPN2_SetMute( chip_r, mask ); } void Ym2612_Nuked_Emu::write0(int addr, int data) { Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); if ( !chip_r ) return; Ym2612_NukedImpl::OPN2_WriteBuffered( chip_r, 0, static_cast(addr) ); Ym2612_NukedImpl::OPN2_WriteBuffered( chip_r, 1, static_cast(data) ); } void Ym2612_Nuked_Emu::write1(int addr, int data) { Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); if ( !chip_r ) return; Ym2612_NukedImpl::OPN2_WriteBuffered( chip_r, 0 + 2, static_cast(addr) ); Ym2612_NukedImpl::OPN2_WriteBuffered( chip_r, 1 + 2, static_cast(data) ); } void Ym2612_Nuked_Emu::run(int pair_count, Ym2612_Nuked_Emu::sample_t *out) { Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); if ( !chip_r ) return; Ym2612_NukedImpl::OPN2_GenerateStreamMix(chip_r, out, pair_count); }