diff --git a/core/sound/sound.c b/core/sound/sound.c index 32e997a..9719531 100644 --- a/core/sound/sound.c +++ b/core/sound/sound.c @@ -89,8 +89,8 @@ void YM3438_Update(int *buffer, int length) ym3438_sample[1] += ym3438_accm[j][1]; } } - *buffer++ = ym3438_sample[0] * 8; - *buffer++ = ym3438_sample[1] * 8; + *buffer++ = ym3438_sample[0] * 11; + *buffer++ = ym3438_sample[1] * 11; } } diff --git a/core/sound/ym3438.c b/core/sound/ym3438.c index 420d99b..73163f2 100644 --- a/core/sound/ym3438.c +++ b/core/sound/ym3438.c @@ -39,7 +39,7 @@ * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): * OPL2 ROMs. * - * version: 1.0.4 + * version: 1.0.6 */ #include @@ -232,6 +232,8 @@ static const Bit32u fm_algorithm[4][6][8] = { } }; +static Bit32u chip_type = ym3438_type_discrete; + void OPN2_DoIO(ym3438_t *chip) { /* Write signal check */ @@ -506,7 +508,7 @@ void OPN2_PhaseCalcIncrement(ym3438_t *chip) basefreq = (fnum << chip->pg_block) >> 2; /* Apply detune */ - if (dt & 0x03) + if (dt_l) { if (kcode > 0x1c) { @@ -514,7 +516,7 @@ void OPN2_PhaseCalcIncrement(ym3438_t *chip) } block = kcode >> 2; note = kcode & 0x03; - sum = block + 1 + ((dt_l == 3) | (dt_l & 0x02) | ((dt_l != 0) << 3)); + 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); @@ -671,7 +673,7 @@ void OPN2_EnvelopeADSR(ym3438_t *chip) } break; case eg_num_decay: - if (!eg_off && (level >> 5) == chip->eg_sl[1]) + if ((level >> 5) == chip->eg_sl[1]) { nextstate = eg_num_sustain; } @@ -803,11 +805,11 @@ void OPN2_EnvelopePrepare(ym3438_t *chip) chip->eg_ksv = chip->pg_kcode >> (chip->ks[slot] ^ 0x03); if (chip->am[slot]) { - chip->eg_am_shift = chip->ams[chip->channel]; + chip->eg_lfo_am = chip->lfo_am >> eg_am_shift[chip->ams[chip->channel]]; } else { - chip->eg_am_shift = 0; + chip->eg_lfo_am = 0; } /* Delay TL & SL value */ chip->eg_tl[1] = chip->eg_tl[0]; @@ -835,7 +837,7 @@ void OPN2_EnvelopeGenerate(ym3438_t *chip) level &= 0x3ff; /* Apply AM LFO */ - level += chip->lfo_am >> eg_am_shift[chip->eg_am_shift]; + level += chip->eg_lfo_am; /* Apply TL */ if (!(chip->mode_csm && chip->channel == 2 + 1)) @@ -966,6 +968,8 @@ void OPN2_ChOutput(ym3438_t *chip) 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 (chip->slot < 12) { @@ -995,13 +999,53 @@ void OPN2_ChOutput(ym3438_t *chip) } chip->mol = 0; chip->mor = 0; - if (chip->ch_lock_l) + + if (chip_type == ym3438_type_ym2612) { - chip->mol = out; + out_en = ((chip->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; } - if (chip->ch_lock_r) + else { - chip->mor = out; + out_en = ((chip->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; + } } } @@ -1179,6 +1223,11 @@ void OPN2_Reset(ym3438_t *chip) } } +void OPN2_SetChipType(Bit32u type) +{ + chip_type = type; +} + void OPN2_Clock(ym3438_t *chip, Bit32u *buffer) { chip->lfo_inc = chip->mode_test_21[1]; @@ -1350,7 +1399,7 @@ Bit32u OPN2_ReadIRQPin(ym3438_t *chip) Bit8u OPN2_Read(ym3438_t *chip, Bit32u port) { - if ((port & 3) == 0) + if ((port & 3) == 0 || chip_type == ym3438_type_asic) { if (chip->mode_test_21[6]) { diff --git a/core/sound/ym3438.h b/core/sound/ym3438.h index 6678782..9bf4af0 100644 --- a/core/sound/ym3438.h +++ b/core/sound/ym3438.h @@ -39,12 +39,18 @@ * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): * OPL2 ROMs. * - * version: 1.0.4 + * version: 1.0.6 */ #ifndef YM3438_H #define YM3438_H +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) */ +}; + #include typedef uintptr_t Bitu; @@ -60,148 +66,149 @@ typedef int8_t Bit8s; typedef struct { - Bit32u cycles; - Bit32u slot; - 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_am_shift; - 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]; + Bit32u cycles; + Bit32u slot; + 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]; } ym3438_t; void OPN2_Reset(ym3438_t *chip); +void OPN2_SetChipType(Bit32u type); void OPN2_Clock(ym3438_t *chip, Bit32u *buffer); void OPN2_Write(ym3438_t *chip, Bit32u port, Bit8u data); void OPN2_SetTestPin(ym3438_t *chip, Bit32u value); diff --git a/libretro/libretro.c b/libretro/libretro.c index b6e3ccf..16e5dad 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -1106,12 +1106,25 @@ static void check_variables(void) environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var); { orig_value = config.ym3438; - if (!strcmp(var.value, "nuked opn2")) + if (!strcmp(var.value, "nuked (ym2612)")) + { + OPN2_SetChipType(ym3438_type_ym2612); config.ym3438 = 1; + } + else if (!strcmp(var.value, "nuked (asic ym3438)")) + { + OPN2_SetChipType(ym3438_type_asic); + config.ym3438 = 2; + } + else if (!strcmp(var.value, "nuked (discrete ym3438)")) + { + OPN2_SetChipType(ym3438_type_discrete); + config.ym3438 = 3; + } else config.ym3438 = 0; - if (orig_value != config.ym3438) + if (orig_value == 0 && config.ym3438 > 0 || orig_value > 0 && config.ym3438 == 0) { sound_init(); sound_reset(); @@ -1656,7 +1669,7 @@ void retro_set_environment(retro_environment_t cb) { "genesis_plus_gx_ym2413", "Master System FM; auto|disabled|enabled" }, { "genesis_plus_gx_dac_bits", "YM2612 DAC quantization; disabled|enabled" }, #ifdef HAVE_YM3438_CORE - { "genesis_plus_gx_ym3438", "YM2612/YM3438 core; mame|nuked opn2" }, + { "genesis_plus_gx_ym3438", "YM2612/YM3438 core; mame|nuked (ym2612)|nuked (asic ym3438)|nuked (discrete ym3438)" }, #endif { "genesis_plus_gx_audio_filter", "Audio filter; disabled|low-pass" },