[Core/Sound] added (optional) YM2612 DAC distortion emulation in MAME core & removed configurable YM2612 DAC resolution (deprecated)

This commit is contained in:
EkeEke 2017-12-22 20:43:28 +01:00
parent b62ce884b8
commit 902dc4c4c0
18 changed files with 214 additions and 129 deletions

View File

@ -121,6 +121,7 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke)
[Core/Sound]
---------------
* added discrete YM2612 DAC distortion emulation (optional)
* rewrote optimized & more accurate PSG core from scratch
* removed PSG boost noise feature & added optional high-quality PSG resampling
* fixed YM2612 self-feedback regression introduced in 1.7.1

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 MiB

After

Width:  |  Height:  |  Size: 3.4 MiB

View File

@ -150,7 +150,7 @@ void sound_init( void )
{
/* MAME */
YM2612Init();
YM2612Config(config.dac_bits);
YM2612Config(config.ym2612);
YM_Reset = YM2612ResetChip;
YM_Update = YM2612Update;
YM_Write = YM2612Write;
@ -288,7 +288,6 @@ int sound_context_save(uint8 *state)
else
{
bufferptr += YM2612SaveContext(state + sizeof(config.ym3438));
YM2612Config(config.dac_bits);
}
#else
bufferptr = YM2612SaveContext(state);
@ -325,11 +324,9 @@ int sound_context_load(uint8 *state)
else
{
bufferptr += YM2612LoadContext(state + sizeof(config_ym3438));
YM2612Config(config.dac_bits);
}
#else
bufferptr = YM2612LoadContext(state);
YM2612Config(config.dac_bits);
#endif
}
else

View File

@ -18,12 +18,16 @@
** TODO:
** - better documentation
** - BUSY flag emulation
** - accurate DAC output
*/
/*
** CHANGELOG:
**
** 03-12-2017 Eke-Eke (Genesis Plus GX):
** - improved 9-bit DAC emulation accuracy
** - added discrete YM2612 DAC distortion emulation ("ladder effect")
** - replaced configurable DAC depth with configurable chip types (discrete, integrated or enhanced)
**
** 26-09-2017 Eke-Eke (Genesis Plus GX):
** - fixed EG counter loopback behavior (verified on YM3438 die)
** - reverted changes to EG rates 2-7 increment values
@ -626,8 +630,11 @@ static YM2612 ym2612;
/* current chip state */
static INT32 m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */
static INT32 mem; /* one sample delay memory */
static INT32 out_fm[8]; /* outputs of working channels */
static UINT32 bitmask; /* working channels output bitmasking (DAC quantization) */
static INT32 out_fm[6]; /* outputs of working channels */
/* chip type */
static UINT32 op_mask[8][4]; /* operator output bitmasking (DAC quantization) */
static int chip_type = YM2612_DISCRETE;
INLINE void FM_KEYON(FM_CH *CH , int s )
@ -1408,22 +1415,22 @@ INLINE void refresh_fc_eg_chan(FM_CH *CH )
#define volume_calc(OP) ((OP)->vol_out + (AM & (OP)->AMmask))
INLINE signed int op_calc(UINT32 phase, unsigned int env, unsigned int pm)
INLINE signed int op_calc(UINT32 phase, unsigned int env, unsigned int pm, unsigned int opmask)
{
UINT32 p = (env<<3) + sin_tab[ ( (phase >> SIN_BITS) + (pm >> 1) ) & SIN_MASK ];
if (p >= TL_TAB_LEN)
return 0;
return tl_tab[p];
return (tl_tab[p] & opmask);
}
INLINE signed int op_calc1(UINT32 phase, unsigned int env, unsigned int pm)
INLINE signed int op_calc1(UINT32 phase, unsigned int env, unsigned int pm, unsigned int opmask)
{
UINT32 p = (env<<3) + sin_tab[ ( ( phase >> SIN_BITS ) + pm ) & SIN_MASK ];
if (p >= TL_TAB_LEN)
return 0;
return tl_tab[p];
return (tl_tab[p] & opmask);
}
INLINE void chan_calc(FM_CH *CH, int num)
@ -1433,6 +1440,7 @@ INLINE void chan_calc(FM_CH *CH, int num)
INT32 out = 0;
UINT32 AM = ym2612.OPN.LFO_AM >> CH->ams;
unsigned int eg_out = volume_calc(&CH->SLOT[SLOT1]);
UINT32 *mask = op_mask[CH->ALGO];
m2 = c1 = c2 = mem = 0;
@ -1443,7 +1451,7 @@ INLINE void chan_calc(FM_CH *CH, int num)
if (CH->FB < SIN_BITS)
out = (CH->op1_out[0] + CH->op1_out[1]) >> CH->FB;
out = op_calc1(CH->SLOT[SLOT1].phase, eg_out, out );
out = op_calc1(CH->SLOT[SLOT1].phase, eg_out, out, mask[0]);
}
CH->op1_out[0] = CH->op1_out[1];
@ -1459,22 +1467,21 @@ INLINE void chan_calc(FM_CH *CH, int num)
eg_out = volume_calc(&CH->SLOT[SLOT3]);
if( eg_out < ENV_QUIET ) /* SLOT 3 */
*CH->connect3 += op_calc(CH->SLOT[SLOT3].phase, eg_out, m2);
*CH->connect3 += op_calc(CH->SLOT[SLOT3].phase, eg_out, m2, mask[2]);
eg_out = volume_calc(&CH->SLOT[SLOT2]);
if( eg_out < ENV_QUIET ) /* SLOT 2 */
*CH->connect2 += op_calc(CH->SLOT[SLOT2].phase, eg_out, c1);
*CH->connect2 += op_calc(CH->SLOT[SLOT2].phase, eg_out, c1, mask[1]);
eg_out = volume_calc(&CH->SLOT[SLOT4]);
if( eg_out < ENV_QUIET ) /* SLOT 4 */
*CH->connect4 += op_calc(CH->SLOT[SLOT4].phase, eg_out, c2);
*CH->connect4 += op_calc(CH->SLOT[SLOT4].phase, eg_out, c2, mask[3]);
/* store current MEM */
CH->mem_value = mem;
/* update phase counters AFTER output calculations */
if(CH->pms)
if (CH->pms)
{
/* 3-slot mode */
if ((ym2612.OPN.ST.mode & 0xC0) && (CH == &ym2612.CH[2]))
@ -1515,7 +1522,7 @@ INLINE void OPNWriteMode(int r, int v)
case 0x21: /* Test */
break;
case 0x22: /* LFO FREQ (YM2608/YM2610/YM2610B/ym2612) */
case 0x22: /* LFO FREQ */
if (v&8) /* LFO enabled ? */
{
ym2612.OPN.lfo_timer_overflow = lfo_samples_per_step[v&7];
@ -1550,7 +1557,6 @@ INLINE void OPNWriteMode(int r, int v)
if( c == 3 ) break;
if (v&0x04) c+=3; /* CH 4-6 */
CH = &ym2612.CH[c];
if (v&0x10) FM_KEYON(CH,SLOT1); else FM_KEYOFF(CH,SLOT1);
if (v&0x20) FM_KEYON(CH,SLOT2); else FM_KEYOFF(CH,SLOT2);
if (v&0x40) FM_KEYON(CH,SLOT3); else FM_KEYOFF(CH,SLOT3);
@ -1686,8 +1692,6 @@ INLINE void OPNWriteReg(int r, int v)
That is not necessary, but then EG will be generating Attack phase.
*/
break;
case 0xa0:
@ -1722,7 +1726,7 @@ INLINE void OPNWriteReg(int r, int v)
ym2612.OPN.SL3.block_fnum[c] = (blk<<11) | fn;
ym2612.CH[2].SLOT[SLOT1].Incr=-1;
}
break;
break;
case 3: /* 0xac-0xae : 3CH FNUM2,BLK */
if(r < 0x100)
ym2612.OPN.SL3.fn_h = v&0x3f;
@ -1737,7 +1741,7 @@ INLINE void OPNWriteReg(int r, int v)
CH->ALGO = v&7;
CH->FB = SIN_BITS - ((v>>3)&7);
setup_connection( CH, c );
break;
break;
}
case 1: /* 0xb4-0xb6 : L , R , AMS , PMS */
/* b0-2 PMS */
@ -1747,8 +1751,8 @@ INLINE void OPNWriteReg(int r, int v)
CH->ams = lfo_ams_depth_shift[(v>>4) & 0x03];
/* PAN : b7 = L, b6 = R */
ym2612.OPN.pan[ c*2 ] = (v & 0x80) ? bitmask : 0;
ym2612.OPN.pan[ c*2+1 ] = (v & 0x40) ? bitmask : 0;
ym2612.OPN.pan[ c*2 ] = (v & 0x80) ? 0xffffffff : 0;
ym2612.OPN.pan[ c*2+1 ] = (v & 0x40) ? 0xffffffff : 0;
break;
}
break;
@ -1884,6 +1888,15 @@ static void init_tables(void)
}
}
/* build default OP mask table */
for (i = 0;i < 8;i++)
{
for (d = 0;d < 4;d++)
{
op_mask[i][d] = 0xffffffff;
}
}
}
@ -2020,7 +2033,7 @@ void YM2612Update(int *buffer, int length)
refresh_fc_eg_chan(&ym2612.CH[5]);
/* buffering */
for(i=0; i<length ; i++)
for(i=0; i<length; i++)
{
/* clear outputs */
out_fm[0] = 0;
@ -2066,21 +2079,21 @@ void YM2612Update(int *buffer, int length)
advance_eg_channels(&ym2612.CH[0], ym2612.OPN.eg_cnt);
}
/* 14-bit accumulator channels outputs (range is -8192;+8192) */
if (out_fm[0] > 8192) out_fm[0] = 8192;
/* channels accumulator output clipping (14-bit max) */
if (out_fm[0] > 8191) out_fm[0] = 8191;
else if (out_fm[0] < -8192) out_fm[0] = -8192;
if (out_fm[1] > 8192) out_fm[1] = 8192;
if (out_fm[1] > 8191) out_fm[1] = 8191;
else if (out_fm[1] < -8192) out_fm[1] = -8192;
if (out_fm[2] > 8192) out_fm[2] = 8192;
if (out_fm[2] > 8191) out_fm[2] = 8191;
else if (out_fm[2] < -8192) out_fm[2] = -8192;
if (out_fm[3] > 8192) out_fm[3] = 8192;
if (out_fm[3] > 8191) out_fm[3] = 8191;
else if (out_fm[3] < -8192) out_fm[3] = -8192;
if (out_fm[4] > 8192) out_fm[4] = 8192;
if (out_fm[4] > 8191) out_fm[4] = 8191;
else if (out_fm[4] < -8192) out_fm[4] = -8192;
if (out_fm[5] > 8192) out_fm[5] = 8192;
if (out_fm[5] > 8191) out_fm[5] = 8191;
else if (out_fm[5] < -8192) out_fm[5] = -8192;
/* stereo DAC channels outputs mixing */
/* stereo DAC output panning & mixing */
lt = ((out_fm[0]) & ym2612.OPN.pan[0]);
rt = ((out_fm[0]) & ym2612.OPN.pan[1]);
lt += ((out_fm[1]) & ym2612.OPN.pan[2]);
@ -2094,11 +2107,34 @@ void YM2612Update(int *buffer, int length)
lt += ((out_fm[5]) & ym2612.OPN.pan[10]);
rt += ((out_fm[5]) & ym2612.OPN.pan[11]);
/* discrete YM2612 DAC */
if (chip_type == YM2612_DISCRETE)
{
int i;
/* DAC 'ladder effect' */
for (i=0; i<6; i++)
{
if (out_fm[i] < 0)
{
/* -4 offset (-3 when not muted) on negative channel output (9-bit) */
lt -= ((4 - (ym2612.OPN.pan[(2*i)+0] & 1)) << 5);
rt -= ((4 - (ym2612.OPN.pan[(2*i)+1] & 1)) << 5);
}
else
{
/* +4 offset (when muted or not) on positive channel output (9-bit) */
lt += (4 << 5);
rt += (4 << 5);
}
}
}
/* buffering */
*buffer++ = lt;
*buffer++ = rt;
/* CSM mode: if CSM Key ON has occured, CSM Key OFF need to be sent */
/* CSM mode: if CSM Key ON has occurred, CSM Key OFF need to be sent */
/* only if Timer A does not overflow again (i.e CSM Key ON not set again) */
ym2612.OPN.SL3.key_csm <<= 1;
@ -2121,20 +2157,51 @@ void YM2612Update(int *buffer, int length)
INTERNAL_TIMER_B(length);
}
void YM2612Config(unsigned char dac_bits)
void YM2612Config(int type)
{
int i;
/* YM2612 chip type */
chip_type = type;
/* DAC precision (normally 9-bit on real hardware, implemented through simple 14-bit channel output bitmasking) */
bitmask = ~((1 << (TL_BITS - dac_bits)) - 1);
/* update L/R panning bitmasks */
for (i=0; i<2*6; i++)
/* carrier operator outputs bitmask */
if (chip_type < YM2612_ENHANCED)
{
if (ym2612.OPN.pan[i])
{
ym2612.OPN.pan[i] = bitmask;
}
/* 9-bit DAC */
op_mask[0][3] = 0xffffffe0;
op_mask[1][3] = 0xffffffe0;
op_mask[2][3] = 0xffffffe0;
op_mask[3][3] = 0xffffffe0;
op_mask[4][1] = 0xffffffe0;
op_mask[4][3] = 0xffffffe0;
op_mask[5][1] = 0xffffffe0;
op_mask[5][2] = 0xffffffe0;
op_mask[5][3] = 0xffffffe0;
op_mask[6][1] = 0xffffffe0;
op_mask[6][2] = 0xffffffe0;
op_mask[6][3] = 0xffffffe0;
op_mask[7][0] = 0xffffffe0;
op_mask[7][1] = 0xffffffe0;
op_mask[7][2] = 0xffffffe0;
op_mask[7][3] = 0xffffffe0;
}
else
{
/* 14-bit DAC */
op_mask[0][3] = 0xffffffff;
op_mask[1][3] = 0xffffffff;
op_mask[2][3] = 0xffffffff;
op_mask[3][3] = 0xffffffff;
op_mask[4][1] = 0xffffffff;
op_mask[4][3] = 0xffffffff;
op_mask[5][1] = 0xffffffff;
op_mask[5][2] = 0xffffffff;
op_mask[5][3] = 0xffffffff;
op_mask[6][1] = 0xffffffff;
op_mask[6][2] = 0xffffffff;
op_mask[6][3] = 0xffffffff;
op_mask[7][0] = 0xffffffff;
op_mask[7][1] = 0xffffffff;
op_mask[7][2] = 0xffffffff;
op_mask[7][3] = 0xffffffff;
}
}

View File

@ -16,8 +16,14 @@
#ifndef _H_YM2612_
#define _H_YM2612_
enum {
YM2612_DISCRETE = 0,
YM2612_INTEGRATED,
YM2612_ENHANCED
};
extern void YM2612Init(void);
extern void YM2612Config(unsigned char dac_bits);
extern void YM2612Config(int type);
extern void YM2612ResetChip(void);
extern void YM2612Update(int *buffer, int length);
extern void YM2612Write(unsigned int a, unsigned int v);

View File

@ -49,8 +49,8 @@ void set_config_defaults(void)
config.lg = 100;
config.mg = 100;
config.hg = 100;
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
config.dac_bits = 14;
config.lp_range = 0x7fff; /* 0.5 in 0.16 fixed point */
config.ym2612 = YM2612_DISCRETE;
config.ym2413 = 1; /* = AUTO (0 = always OFF, 1 = always ON) */
config.mono = 0;

View File

@ -21,7 +21,7 @@ typedef struct
uint8 hq_fm;
uint8 filter;
uint8 hq_psg;
uint8 dac_bits;
uint8 ym2612;
uint8 ym2413;
int16 psg_preamp;
int16 fm_preamp;

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX configuration file support
*
* Copyright Eke-Eke (2007-2016)
* Copyright Eke-Eke (2007-2017)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -103,13 +103,13 @@ void config_default(void)
config.hq_fm = 1;
config.hq_psg = 1;
config.filter = 1;
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
config.lp_range = 0x7FFF; /* 0.5 in 0.16 fixed point */
config.low_freq = 880;
config.high_freq = 5000;
config.lg = 100;
config.mg = 100;
config.hg = 100;
config.dac_bits = 14;
config.ym2612 = YM2612_DISCRETE;
config.ym2413 = 2; /* AUTO */
config.mono = 0;

View File

@ -52,7 +52,7 @@ typedef struct
uint8 hq_fm;
uint8 filter;
uint8 hq_psg;
uint8 dac_bits;
uint8 ym2612;
uint8 ym2413;
uint8 mono;
int16 psg_preamp;

View File

@ -343,20 +343,20 @@ static gui_item items_options[] =
/* Audio options */
static gui_item items_audio[] =
{
{NULL,NULL,"Master System FM: AUTO", "Enable/Disable YM2413 chip", 56,132,276,48},
{NULL,NULL,"High-Quality FM: ON", "Enable/Disable YM2612/YM2413 high-quality resampling", 56,132,276,48},
{NULL,NULL,"FM Resolution: MAX", "Adjust YM2612 DAC precision", 56,132,276,48},
{NULL,NULL,"FM Volume: 1.00", "Adjust YM2612/YM2413 audio balance", 56,132,276,48},
{NULL,NULL,"PSG Volume: 2.50", "Adjust SN76489 audio balance", 56,132,276,48},
{NULL,NULL,"High-Quality PSG: ON", "Enable/Disable SN76489 high-quality resampling", 56,132,276,48},
{NULL,NULL,"Audio Output: STEREO", "Select audio mixing output type", 56,132,276,48},
{NULL,NULL,"Filtering: 3-BAND EQ", "Select audio filtering type", 56,132,276,48},
{NULL,NULL,"Low Gain: 1.00", "Adjust EQ Low Band Gain", 56,132,276,48},
{NULL,NULL,"Mid Gain: 1.00", "Adjust EQ Mid Band Gain", 56,132,276,48},
{NULL,NULL,"High Gain: 1.00", "Adjust EQ High Band Gain", 56,132,276,48},
{NULL,NULL,"Low Freq: 200 Hz", "Adjust EQ Lowest Frequency", 56,132,276,48},
{NULL,NULL,"High Freq: 20000 Hz", "Adjust EQ Highest Frequency", 56,132,276,48}
};
{NULL,NULL,"Master System FM: AUTO", "Enable/Disable YM2413 chip", 56,132,276,48},
{NULL,NULL,"YM2612 Type: DISCRETE", "Select YM2612 chip model", 56,132,276,48},
{NULL,NULL,"High-Quality FM: ON", "Enable/Disable YM2612/YM2413 high-quality resampling", 56,132,276,48},
{NULL,NULL,"High-Quality PSG: ON", "Enable/Disable SN76489 high-quality resampling", 56,132,276,48},
{NULL,NULL,"FM Volume: 1.00", "Adjust YM2612/YM2413 audio balance", 56,132,276,48},
{NULL,NULL,"PSG Volume: 2.50", "Adjust SN76489 audio balance", 56,132,276,48},
{NULL,NULL,"Audio Output: STEREO", "Select audio mixing output type", 56,132,276,48},
{NULL,NULL,"Filtering: 3-BAND EQ", "Select audio filtering type", 56,132,276,48},
{NULL,NULL,"Low Gain: 1.00", "Adjust EQ Low Band Gain", 56,132,276,48},
{NULL,NULL,"Mid Gain: 1.00", "Adjust EQ Mid Band Gain", 56,132,276,48},
{NULL,NULL,"High Gain: 1.00", "Adjust EQ High Band Gain", 56,132,276,48},
{NULL,NULL,"Low Freq: 200 Hz", "Adjust EQ Lowest Frequency", 56,132,276,48},
{NULL,NULL,"High Freq: 20000 Hz", "Adjust EQ Highest Frequency", 56,132,276,48}
};
/* System ROM paths */
static gui_item items_rompaths[] =
@ -901,14 +901,16 @@ static void soundmenu ()
else if (config.ym2413 == 1) sprintf (items[0].text, "Master System FM: ON");
else sprintf (items[0].text, "Master System FM: AUTO");
sprintf (items[1].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
if (config.ym2612 == YM2612_DISCRETE) sprintf (items[1].text, "YM2612 Type: DISCRETE");
else if (config.ym2612 == YM2612_INTEGRATED) sprintf (items[1].text, "YM2612 Type: ASIC");
else sprintf (items[1].text, "YM2612 Type: ENHANCED");
if (config.dac_bits < 14) sprintf (items[2].text, "FM Resolution: %d bits", config.dac_bits);
else sprintf (items[2].text, "FM Resolution: MAX");
sprintf (items[2].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
sprintf (items[3].text, "High-Quality PSG: %s", config.hq_psg? "ON":"OFF");
sprintf (items[4].text, "FM Volume: %1.2f", fm_volume);
sprintf (items[5].text, "PSG Volume: %1.2f", psg_volume);
sprintf (items[3].text, "FM Volume: %1.2f", fm_volume);
sprintf (items[4].text, "PSG Volume: %1.2f", psg_volume);
sprintf (items[5].text, "High-Quality PSG: %s", config.hq_psg? "ON":"OFF");
sprintf (items[6].text, "Audio Output: %s", config.mono ? "MONO":"STEREO");
if (config.filter == 2)
@ -971,33 +973,41 @@ static void soundmenu ()
case 1:
{
config.hq_fm ^= 1;
sprintf (items[1].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
config.ym2612++;
if (config.ym2612 > YM2612_ENHANCED) config.ym2612 = YM2612_DISCRETE;
if (config.ym2612 == YM2612_DISCRETE) sprintf (items[1].text, "YM2612 Type: DISCRETE");
else if (config.ym2612 == YM2612_INTEGRATED) sprintf (items[1].text, "YM2612 Type: ASIC");
else sprintf (items[1].text, "YM2612 Type: ENHANCED");
YM2612Config(config.ym2612);
break;
}
case 2:
{
config.dac_bits++;
if (config.dac_bits > 14) config.dac_bits = 7;
if (config.dac_bits < 14) sprintf (items[2].text, "FM Resolution: %d bits", config.dac_bits);
else sprintf (items[2].text, "FM Resolution: MAX");
YM2612Config(config.dac_bits);
config.hq_fm ^= 1;
sprintf (items[2].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
break;
}
case 3:
{
GUI_OptionBox(m,0,"FM Volume",(void *)&fm_volume,0.01,0.0,5.0,0);
sprintf (items[3].text, "FM Volume: %1.2f", fm_volume);
config.fm_preamp = (int)(fm_volume * 100.0 + 0.5);
config.hq_psg ^= 1;
sprintf (items[3].text, "High-Quality PSG: %s", config.hq_psg ? "ON":"OFF");
break;
}
case 4:
{
GUI_OptionBox(m,0,"FM Volume",(void *)&fm_volume,0.01,0.0,5.0,0);
sprintf (items[4].text, "FM Volume: %1.2f", fm_volume);
config.fm_preamp = (int)(fm_volume * 100.0 + 0.5);
break;
}
case 5:
{
GUI_OptionBox(m,0,"PSG Volume",(void *)&psg_volume,0.01,0.0,5.0,0);
sprintf (items[4].text, "PSG Volume: %1.2f", psg_volume);
sprintf (items[5].text, "PSG Volume: %1.2f", psg_volume);
config.psg_preamp = (int)(psg_volume * 100.0 + 0.5);
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
@ -1010,13 +1020,6 @@ static void soundmenu ()
break;
}
case 5:
{
config.hq_psg ^= 1;
sprintf (items[5].text, "High-Quality PSG: %s", config.hq_psg ? "ON":"OFF");
break;
}
case 6:
{
config.mono ^= 1;

View File

@ -533,15 +533,18 @@ static void config_default(void)
config.hq_fm = 1; /* high-quality FM resampling (slower) */
config.hq_psg = 1; /* high-quality PSG resampling (slower) */
config.filter = 0; /* no filter */
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
config.lp_range = 0x7fff; /* 0.5 in 0.16 fixed point */
config.low_freq = 880;
config.high_freq = 5000;
config.lg = 100;
config.mg = 100;
config.hg = 100;
config.dac_bits = 14; /* MAX DEPTH */
config.ym2612 = YM2612_DISCRETE;
config.ym2413 = 2; /* AUTO */
config.mono = 0; /* STEREO output */
#ifdef HAVE_YM3438_CORE
config.ym3438 = 0;
#endif
/* system options */
config.system = 0; /* AUTO */
@ -1104,10 +1107,10 @@ static void check_variables(void)
if (!strcmp(var.value, "low-pass"))
config.filter = 1;
#if HAVE_EQ
#if HAVE_EQ
else if (!strcmp(var.value, "EQ"))
config.filter = 2;
#endif
#endif
else
config.filter = 0;
@ -1117,9 +1120,9 @@ static void check_variables(void)
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
{
config.lp_range = (atoi(var.value) * 65536) / 100;
}
#if HAVE_EQ
}
#if HAVE_EQ
var.key = "genesis_plus_gx_audio_eq_low";
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
{
@ -1127,7 +1130,7 @@ static void check_variables(void)
if (new_lg != config.lg) restart_eq = true;
config.lg = new_lg;
}
var.key = "genesis_plus_gx_audio_eq_mid";
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
{
@ -1135,7 +1138,7 @@ static void check_variables(void)
if (new_mg != config.mg) restart_eq = true;
config.mg = new_mg;
}
var.key = "genesis_plus_gx_audio_eq_high";
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
{
@ -1144,23 +1147,12 @@ static void check_variables(void)
config.hg = new_hg;
}
#endif
#endif
var.key = "genesis_plus_gx_dac_bits";
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
{
if (!strcmp(var.value, "enabled"))
config.dac_bits = 9;
else
config.dac_bits = 14;
YM2612Config(config.dac_bits);
}
#ifdef HAVE_YM3438_CORE
var.key = "genesis_plus_gx_ym3438";
var.key = "genesis_plus_gx_ym2612";
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
{
#ifdef HAVE_YM3438_CORE
orig_value = config.ym3438;
if (!strcmp(var.value, "nuked (ym2612)"))
{
@ -1178,15 +1170,33 @@ static void check_variables(void)
config.ym3438 = 3;
}
else
{
config.ym3438 = 0;
}
if (orig_value == 0 && config.ym3438 > 0 || orig_value > 0 && config.ym3438 == 0)
if (((orig_value == 0) && (config.ym3438 > 0)) || ((orig_value > 0) && (config.ym3438 == 0)))
{
sound_init();
sound_reset();
}
#endif
if (!strcmp(var.value, "mame (ym2612)"))
{
config.ym2612 = YM2612_DISCRETE;
YM2612Config(YM2612_DISCRETE);
}
else if (!strcmp(var.value, "mame (asic ym3438)"))
{
config.ym2612 = YM2612_INTEGRATED;
YM2612Config(YM2612_INTEGRATED);
}
else
{
config.ym2612 = YM2612_ENHANCED;
YM2612Config(YM2612_ENHANCED);
}
}
#endif
var.key = "genesis_plus_gx_blargg_ntsc_filter";
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
@ -1754,11 +1764,12 @@ void retro_set_environment(retro_environment_t cb)
{ "genesis_plus_gx_bram", "CD System BRAM; per bios|per game" },
{ "genesis_plus_gx_addr_error", "68k address error; enabled|disabled" },
{ "genesis_plus_gx_lock_on", "Cartridge lock-on; disabled|game genie|action replay (pro)|sonic & knuckles" },
{ "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 (ym2612)|nuked (asic ym3438)|nuked (discrete ym3438)" },
#endif
{ "genesis_plus_gx_ym2413", "Master System FM (YM2413); auto|disabled|enabled" },
#ifdef HAVE_YM3438_CORE
{ "genesis_plus_gx_ym2612", "Mega Drive / Genesis FM; mame (ym2612)|mame (asic ym3438)|mame (enhanced ym3438)|nuked (ym2612)|nuked (asic ym3438)|nuked (discrete ym3438)" },
#else
{ "genesis_plus_gx_ym2612", "Mega Drive / Genesis FM; mame (ym2612)|mame (asic ym3438)|mame (enhanced ym3438)" },
#endif
{ "genesis_plus_gx_sound_output", "Sound output; stereo|mono" },
{ "genesis_plus_gx_audio_filter", "Audio filter; disabled|low-pass" },

View File

@ -94,7 +94,7 @@ struct
uint8 hq_fm;
uint8 filter;
uint8 hq_psg;
uint8 dac_bits;
uint8 ym2612;
uint8 ym2413;
#ifdef HAVE_YM3438_CORE
uint8 ym3438;

View File

@ -18,8 +18,8 @@ void set_config_defaults(void)
config.lg = 100;
config.mg = 100;
config.hg = 100;
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
config.dac_bits = 14;
config.lp_range = 0x7fff; /* 0.5 in 0.16 fixed point */
config.ym2612 = YM2612_DISCRETE;
config.ym2413 = 2; /* = AUTO (0 = always OFF, 1 = always ON) */
config.mono = 0;

View File

@ -20,7 +20,7 @@ typedef struct
uint8 hq_fm;
uint8 filter;
uint8 hq_psg;
uint8 dac_bits;
uint8 ym2612;
uint8 ym2413;
int16 psg_preamp;
int16 fm_preamp;

View File

@ -19,8 +19,8 @@ void set_config_defaults(void)
config.lg = 100;
config.mg = 100;
config.hg = 100;
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
config.dac_bits = 14;
config.lp_range = 0x7fff; /* 0.6 in 0.16 fixed point */
config.ym2612 = YM2612_DISCRETE;
config.ym2413 = 2; /* = AUTO (0 = always OFF, 1 = always ON) */
config.ym3438 = 0;
config.mono = 0;

View File

@ -16,7 +16,7 @@ typedef struct
uint8 hq_fm;
uint8 filter;
uint8 hq_psg;
uint8 dac_bits;
uint8 ym2612;
uint8 ym2413;
uint8 ym3438;
int16 psg_preamp;