Merge pull request #179 from nukeykt/ym3438

Nuked OPN2: minor optimization + ASIC YM3438 & YM2612 DAC emulation (experimental)
This commit is contained in:
ekeeke 2017-09-29 21:23:49 +02:00 committed by GitHub
commit 296b3c7a08
4 changed files with 226 additions and 157 deletions

View File

@ -89,8 +89,8 @@ void YM3438_Update(int *buffer, int length)
ym3438_sample[1] += ym3438_accm[j][1]; ym3438_sample[1] += ym3438_accm[j][1];
} }
} }
*buffer++ = ym3438_sample[0] * 8; *buffer++ = ym3438_sample[0] * 11;
*buffer++ = ym3438_sample[1] * 8; *buffer++ = ym3438_sample[1] * 11;
} }
} }

View File

@ -39,7 +39,7 @@
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
* OPL2 ROMs. * OPL2 ROMs.
* *
* version: 1.0.4 * version: 1.0.6
*/ */
#include <string.h> #include <string.h>
@ -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) void OPN2_DoIO(ym3438_t *chip)
{ {
/* Write signal check */ /* Write signal check */
@ -506,7 +508,7 @@ void OPN2_PhaseCalcIncrement(ym3438_t *chip)
basefreq = (fnum << chip->pg_block) >> 2; basefreq = (fnum << chip->pg_block) >> 2;
/* Apply detune */ /* Apply detune */
if (dt & 0x03) if (dt_l)
{ {
if (kcode > 0x1c) if (kcode > 0x1c)
{ {
@ -514,7 +516,7 @@ void OPN2_PhaseCalcIncrement(ym3438_t *chip)
} }
block = kcode >> 2; block = kcode >> 2;
note = kcode & 0x03; 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_h = sum >> 1;
sum_l = sum & 0x01; sum_l = sum & 0x01;
detune = pg_detune[(sum_l << 2) | note] >> (9 - sum_h); detune = pg_detune[(sum_l << 2) | note] >> (9 - sum_h);
@ -671,7 +673,7 @@ void OPN2_EnvelopeADSR(ym3438_t *chip)
} }
break; break;
case eg_num_decay: case eg_num_decay:
if (!eg_off && (level >> 5) == chip->eg_sl[1]) if ((level >> 5) == chip->eg_sl[1])
{ {
nextstate = eg_num_sustain; nextstate = eg_num_sustain;
} }
@ -803,11 +805,11 @@ void OPN2_EnvelopePrepare(ym3438_t *chip)
chip->eg_ksv = chip->pg_kcode >> (chip->ks[slot] ^ 0x03); chip->eg_ksv = chip->pg_kcode >> (chip->ks[slot] ^ 0x03);
if (chip->am[slot]) 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 else
{ {
chip->eg_am_shift = 0; chip->eg_lfo_am = 0;
} }
/* Delay TL & SL value */ /* Delay TL & SL value */
chip->eg_tl[1] = chip->eg_tl[0]; chip->eg_tl[1] = chip->eg_tl[0];
@ -835,7 +837,7 @@ void OPN2_EnvelopeGenerate(ym3438_t *chip)
level &= 0x3ff; level &= 0x3ff;
/* Apply AM LFO */ /* Apply AM LFO */
level += chip->lfo_am >> eg_am_shift[chip->eg_am_shift]; level += chip->eg_lfo_am;
/* Apply TL */ /* Apply TL */
if (!(chip->mode_csm && chip->channel == 2 + 1)) if (!(chip->mode_csm && chip->channel == 2 + 1))
@ -966,6 +968,8 @@ void OPN2_ChOutput(ym3438_t *chip)
Bit32u channel = chip->channel; Bit32u channel = chip->channel;
Bit32u test_dac = chip->mode_test_2c[5]; Bit32u test_dac = chip->mode_test_2c[5];
Bit16s out; Bit16s out;
Bit16s sign;
Bit32u out_en;
chip->ch_read = chip->ch_lock; chip->ch_read = chip->ch_lock;
if (chip->slot < 12) if (chip->slot < 12)
{ {
@ -995,14 +999,54 @@ void OPN2_ChOutput(ym3438_t *chip)
} }
chip->mol = 0; chip->mol = 0;
chip->mor = 0; chip->mor = 0;
if (chip->ch_lock_l)
if (chip_type == ym3438_type_ym2612)
{
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; chip->mol = out;
} }
if (chip->ch_lock_r) else
{
chip->mol = sign;
}
if (chip->ch_lock_r && out_en)
{ {
chip->mor = out; chip->mor = out;
} }
else
{
chip->mor = sign;
}
/* Amplify signal */
chip->mol *= 3;
chip->mor *= 3;
}
else
{
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;
}
}
} }
void OPN2_FMGenerate(ym3438_t *chip) void OPN2_FMGenerate(ym3438_t *chip)
@ -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) void OPN2_Clock(ym3438_t *chip, Bit32u *buffer)
{ {
chip->lfo_inc = chip->mode_test_21[1]; 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) 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]) if (chip->mode_test_21[6])
{ {

View File

@ -39,12 +39,18 @@
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
* OPL2 ROMs. * OPL2 ROMs.
* *
* version: 1.0.4 * version: 1.0.6
*/ */
#ifndef YM3438_H #ifndef YM3438_H
#define 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 <stdint.h> #include <stdint.h>
typedef uintptr_t Bitu; typedef uintptr_t Bitu;
@ -111,7 +117,7 @@ typedef struct
Bit8u eg_inc; Bit8u eg_inc;
Bit8u eg_ratemax; Bit8u eg_ratemax;
Bit8u eg_sl[2]; Bit8u eg_sl[2];
Bit8u eg_am_shift; Bit8u eg_lfo_am;
Bit8u eg_tl[2]; Bit8u eg_tl[2];
Bit8u eg_state[24]; Bit8u eg_state[24];
Bit16u eg_level[24]; Bit16u eg_level[24];
@ -202,6 +208,7 @@ typedef struct
} ym3438_t; } ym3438_t;
void OPN2_Reset(ym3438_t *chip); void OPN2_Reset(ym3438_t *chip);
void OPN2_SetChipType(Bit32u type);
void OPN2_Clock(ym3438_t *chip, Bit32u *buffer); void OPN2_Clock(ym3438_t *chip, Bit32u *buffer);
void OPN2_Write(ym3438_t *chip, Bit32u port, Bit8u data); void OPN2_Write(ym3438_t *chip, Bit32u port, Bit8u data);
void OPN2_SetTestPin(ym3438_t *chip, Bit32u value); void OPN2_SetTestPin(ym3438_t *chip, Bit32u value);

View File

@ -1106,12 +1106,25 @@ static void check_variables(void)
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var); environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
{ {
orig_value = config.ym3438; orig_value = config.ym3438;
if (!strcmp(var.value, "nuked opn2")) if (!strcmp(var.value, "nuked (ym2612)"))
{
OPN2_SetChipType(ym3438_type_ym2612);
config.ym3438 = 1; 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 else
config.ym3438 = 0; config.ym3438 = 0;
if (orig_value != config.ym3438) if (orig_value == 0 && config.ym3438 > 0 || orig_value > 0 && config.ym3438 == 0)
{ {
sound_init(); sound_init();
sound_reset(); 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_ym2413", "Master System FM; auto|disabled|enabled" },
{ "genesis_plus_gx_dac_bits", "YM2612 DAC quantization; disabled|enabled" }, { "genesis_plus_gx_dac_bits", "YM2612 DAC quantization; disabled|enabled" },
#ifdef HAVE_YM3438_CORE #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 #endif
{ "genesis_plus_gx_audio_filter", "Audio filter; disabled|low-pass" }, { "genesis_plus_gx_audio_filter", "Audio filter; disabled|low-pass" },