fixed broken YM2612 initial state, rewrote SSG-EG implementation (OK), reverted some menu changes

This commit is contained in:
ekeeke31 2009-02-26 17:24:53 +00:00
parent b75d86889e
commit a857fb3990
3 changed files with 92 additions and 74 deletions

View File

@ -6,8 +6,8 @@ Genesis Plus GX 1.3.2 (??/??/????) (Eke-Eke)
------ ------
* modified SN76489 cut-off frequency * modified SN76489 cut-off frequency
* removed outdated Gens YM2612 core * removed old Gens YM2612 core support
* improved MAME YM2612 core accuracy: SSG-EG support, CSM Mode (based upon last Nemesis tests on real hardware) * improved MAME YM2612 core accuracy: SSG-EG mode, CSM mode (based on Nemesis real hardware's last tests)
* fixed YM2612 context restore * fixed YM2612 context restore
* modified sound update engine to fix synchronization issues (see below) * modified sound update engine to fix synchronization issues (see below)
* various code cleanup * various code cleanup

View File

@ -152,15 +152,29 @@ void drawmenu (char items[][25], int maxitems, int selected)
ypos = (226 - (fheight * maxitems)) >> 1; ypos = (226 - (fheight * maxitems)) >> 1;
ypos += 130; ypos += 130;
DrawMenu (main_buttons, 6, selected); /*DrawMenu (main_buttons, 6, selected);*/
/* reset texture data */
png_texture texture;
memset(&texture,0,sizeof(png_texture));
/*WriteCentre (134, menutitle); /* draw background items */
ClearScreen ((GXColor)BLACK);
OpenPNGFromMemory(&texture, Background_main);
DrawTexture(&texture, (640-texture.width)/2, (480-124-texture.height)/2, texture.width, texture.height);
OpenPNGFromMemory(&texture, Banner_bottom);
DrawTexture(&texture, 640-texture.width, 480-texture.height, texture.width, texture.height);
OpenPNGFromMemory(&texture, Banner_top);
DrawTexture(&texture, 640-texture.width, 0, texture.width, texture.height);
OpenPNGFromMemory(&texture, Main_logo);
DrawTexture(&texture, 444, 28, 176, 48);
WriteCentre (134, menutitle);
for (i = 0; i < maxitems; i++) for (i = 0; i < maxitems; i++)
{ {
if (i == selected) WriteCentre_HL (i * fheight + ypos, (char *) items[i]); if (i == selected) WriteCentre_HL (i * fheight + ypos, (char *) items[i]);
else WriteCentre (i * fheight + ypos, (char *) items[i]); else WriteCentre (i * fheight + ypos, (char *) items[i]);
}*/ }
SetScreen (); SetScreen ();
} }

View File

@ -25,8 +25,8 @@
** - fixed YM2612 initial values (after the reset) ** - fixed YM2612 initial values (after the reset)
** - implemented correct Detune overflow (Ariel, Comix Zone, Shaq Fu, Spiderman & many others) ** - implemented correct Detune overflow (Ariel, Comix Zone, Shaq Fu, Spiderman & many others)
** - implemented correct CSM mode support ** - implemented correct CSM mode support
** - rewrote SSG-EG emulation (Asterix, Bubba'n Six & many others) ** - implemented correct SSG-EG support (Asterix, Beavis&Butthead, Bubba'n Six & many others)
** - modified some EG rates ** - adjusted some EG rates
** - modified address/data port behavior ** - modified address/data port behavior
** **
@ -632,7 +632,7 @@ INLINE void FM_KEYON(FM_CH *CH , int s )
if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/) if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/)
{ {
SLOT->state = EG_ATT; /* phase -> Attack */ SLOT->state = (SLOT->volume <= MIN_ATT_INDEX) ? ((SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC) : EG_ATT;
} }
else else
{ {
@ -645,7 +645,7 @@ INLINE void FM_KEYON(FM_CH *CH , int s )
/* recalculate EG output */ /* recalculate EG output */
if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04))) if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04)))
SLOT->vol_out = ((UINT32)SLOT->volume ^ 0x1FF) + 1 + SLOT->tl; /* SSG-EG Output Inversion */ SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl;
else else
SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl;
} }
@ -690,7 +690,7 @@ INLINE void FM_KEYON_CSM(FM_CH *CH , int s )
if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/) if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/)
{ {
SLOT->state = EG_ATT; /* phase -> Attack */ SLOT->state = (SLOT->volume <= MIN_ATT_INDEX) ? ((SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC) : EG_ATT;
} }
else else
{ {
@ -703,7 +703,7 @@ INLINE void FM_KEYON_CSM(FM_CH *CH , int s )
/* recalculate EG output */ /* recalculate EG output */
if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04))) if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04)))
SLOT->vol_out = ((UINT32)SLOT->volume ^ 0x1FF) + 1 + SLOT->tl; /* SSG-EG Output Inversion */ SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl;
else else
SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl;
} }
@ -869,7 +869,7 @@ INLINE void set_tl(FM_CH *CH,FM_SLOT *SLOT , int v)
/* recalculate EG output */ /* recalculate EG output */
if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04)) && (SLOT->state > EG_REL)) if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04)) && (SLOT->state > EG_REL))
SLOT->vol_out = ((UINT32)SLOT->volume ^ 0x1FF) + 1 + SLOT->tl; /* SSG-EG Output Inversion */ SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl;
else else
SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl;
} }
@ -1028,7 +1028,7 @@ INLINE void advance_eg_channel(FM_SLOT *SLOT)
/* recalculate EG output */ /* recalculate EG output */
if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04))) /* SSG-EG Output Inversion */ if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04))) /* SSG-EG Output Inversion */
SLOT->vol_out = ((UINT32)SLOT->volume ^ 0x1FF) + 1 + SLOT->tl; SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl;
else else
SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl;
} }
@ -1042,13 +1042,15 @@ INLINE void advance_eg_channel(FM_SLOT *SLOT)
{ {
/* update attenuation level */ /* update attenuation level */
if (SLOT->volume < 0x200) if (SLOT->volume < 0x200)
{
SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d1r + ((ym2612.OPN.eg_cnt>>SLOT->eg_sh_d1r)&7)]; SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d1r + ((ym2612.OPN.eg_cnt>>SLOT->eg_sh_d1r)&7)];
/* recalculate EG output */ /* recalculate EG output */
if (SLOT->ssgn ^ (SLOT->ssg&0x04)) /* SSG-EG Output Inversion */ if (SLOT->ssgn ^ (SLOT->ssg&0x04)) /* SSG-EG Output Inversion */
SLOT->vol_out = ((UINT32)SLOT->volume ^ 0x1FF) + 1 + SLOT->tl; SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl;
else else
SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl;
}
} }
else else
{ {
@ -1073,13 +1075,15 @@ INLINE void advance_eg_channel(FM_SLOT *SLOT)
{ {
/* update attenuation level */ /* update attenuation level */
if (SLOT->volume < 0x200) if (SLOT->volume < 0x200)
{
SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d2r + ((ym2612.OPN.eg_cnt>>SLOT->eg_sh_d2r)&7)]; SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d2r + ((ym2612.OPN.eg_cnt>>SLOT->eg_sh_d2r)&7)];
/* recalculate EG output */ /* recalculate EG output */
if (SLOT->ssgn ^ (SLOT->ssg&0x04)) /* SSG-EG Output Inversion */ if (SLOT->ssgn ^ (SLOT->ssg&0x04)) /* SSG-EG Output Inversion */
SLOT->vol_out = ((UINT32)SLOT->volume ^ 0x1FF) + 1 + SLOT->tl; SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl;
else else
SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl;
}
} }
else else
{ {
@ -1106,6 +1110,13 @@ INLINE void advance_eg_channel(FM_SLOT *SLOT)
/* update attenuation level */ /* update attenuation level */
if (SLOT->volume < 0x200) if (SLOT->volume < 0x200)
SLOT->volume += 4 * eg_inc[SLOT->eg_sel_rr + ((ym2612.OPN.eg_cnt>>SLOT->eg_sh_rr)&7)]; SLOT->volume += 4 * eg_inc[SLOT->eg_sel_rr + ((ym2612.OPN.eg_cnt>>SLOT->eg_sh_rr)&7)];
/* check phase transition */
if (SLOT->volume >= 0x200)
{
SLOT->volume = MAX_ATT_INDEX;
SLOT->state = EG_OFF;
}
} }
else else
{ {
@ -1132,64 +1143,57 @@ INLINE void advance_eg_channel(FM_SLOT *SLOT)
} while (i); } while (i);
} }
/* SSG-EG update process */
/* The behavior is based upon Nemesis tests on real hardware */
/* This is actually executed before each samples */
INLINE void update_ssg_eg_channel(FM_SLOT *SLOT) INLINE void update_ssg_eg_channel(FM_SLOT *SLOT)
{ {
unsigned int i = 4; /* four operators per channel */ unsigned int i = 4; /* four operators per channel */
int update_out = 0;
do do
{ {
/* check SSG-EG state */ /* detect SSG-EG transition */
if ((SLOT->ssg & 0x08) && (SLOT->volume >= 0x200)) /* this is not required during release phase as the attenuation is set to MAX and output invert flag is not used */
/* if an Attack Phase is programmed, inversion can occur on each sample */
if ((SLOT->ssg & 0x08) && (SLOT->volume >= 0x200) && (SLOT->state > EG_REL))
{ {
/* swap Invert Output flag if required */ if (SLOT->ssg & 0x01) /* bit 0 = hold SSG-EG */
/* if HOLD bit is set, verify we didn't already swapped once */
if ((SLOT->ssg & 0x02) && (!(SLOT->ssg & 0x01) || !(SLOT->ssgn&4)))
{ {
SLOT->ssgn ^= 4; /* set inversion flag */
update_out = 1; if ((SLOT->ssg & 0x02) && !SLOT->ssgn)
SLOT->ssgn = 4;
/* force attenuation level */
if (!(SLOT->ssgn ^ (SLOT->ssg & 0x04)))
SLOT->volume = MAX_ATT_INDEX;
} }
else /* loop SSG-EG */
/* output is not alternated and not hold */
if (!(SLOT->ssg & 0x02) && !(SLOT->ssg & 0x01))
SLOT->phase = 0; /* reset Phase Generator */
/* update EG phase */
if (SLOT->state < EG_ATT)
{ {
if ((SLOT->state != EG_REL) && (!SLOT->ssg&0x01)) /* toggle output inversion flag or reset Phase Generator */
if (SLOT->ssg & 0x02) SLOT->ssgn ^= 4;
else SLOT->phase = 0;
/* same as Key ON */
if (SLOT->state != EG_ATT)
{ {
/* same as Key ON */
if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/) if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/)
{ {
SLOT->state = EG_ATT; /* phase -> Attack */ SLOT->state = (SLOT->volume <= MIN_ATT_INDEX) ? ((SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC) : EG_ATT;
} }
else else
{ {
/* Attack Rate is maximal: directly switch to Decay */ /* Attack Rate is maximal: directly switch to Decay or Substain */
SLOT->volume = MIN_ATT_INDEX; SLOT->volume = MIN_ATT_INDEX;
SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC; /* special case where SL=0 */ SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC;
update_out = 1;
} }
} }
else if (SLOT->state == EG_REL || (!(SLOT->ssgn ^ (SLOT->ssg & 0x04))))
{
SLOT->volume = MAX_ATT_INDEX;
update_out = 1;
}
} }
/* recalculate EG output */ /* recalculate EG output */
if (update_out) if (SLOT->ssgn ^ (SLOT->ssg&0x04))
{ SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl;
update_out = 0; else
SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl;
if ((SLOT->state > EG_REL) && (SLOT->ssgn ^ (SLOT->ssg&0x04)))
SLOT->vol_out = ((UINT32)SLOT->volume ^ 0x1FF) + 1 + SLOT->tl;
else
SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl;
}
} }
/* next slot */ /* next slot */
@ -1198,7 +1202,6 @@ INLINE void update_ssg_eg_channel(FM_SLOT *SLOT)
} while (i); } while (i);
} }
#define volume_calc(OP) ((OP)->vol_out + (AM & (OP)->AMmask)) #define volume_calc(OP) ((OP)->vol_out + (AM & (OP)->AMmask))
INLINE void update_phase_lfo_slot(FM_SLOT *SLOT , INT32 pms, UINT32 block_fnum) INLINE void update_phase_lfo_slot(FM_SLOT *SLOT , INT32 pms, UINT32 block_fnum)
@ -1717,10 +1720,13 @@ static void OPNWriteReg(int r, int v)
SLOT->ssg = v&0x0f; SLOT->ssg = v&0x0f;
/* recalculate EG output */ /* recalculate EG output */
if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04)) && (SLOT->state > EG_REL)) if (SLOT->state > EG_REL)
SLOT->vol_out = ((UINT32)SLOT->volume ^ 0x1FF) + 1 + SLOT->tl; /* SSG-EG Output Inversion */ {
else if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04)))
SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl;
else
SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl;
}
/* SSG-EG envelope shapes : /* SSG-EG envelope shapes :
@ -1730,11 +1736,11 @@ static void OPNWriteReg(int r, int v)
1 0 0 1 \___ 1 0 0 1 \___
1 0 1 0 \/\/ 1 0 1 0 \/\/
___ ___
1 0 1 1 \ 1 0 1 1 \
1 1 0 0 //// 1 1 0 0 ////
___ ___
1 1 0 1 / 1 1 0 1 /
1 1 1 0 /\/\ 1 1 1 0 /\/\
@ -1919,10 +1925,10 @@ void YM2612UpdateOne(int **buffer, int length)
update_ssg_eg_channel(&ym2612.CH[5].SLOT[SLOT1]); update_ssg_eg_channel(&ym2612.CH[5].SLOT[SLOT1]);
/* advance envelope generator */ /* advance envelope generator */
ym2612.OPN.eg_timer += ym2612.OPN.eg_timer_add; ym2612.OPN.eg_timer ++;
while (ym2612.OPN.eg_timer >= ym2612.OPN.eg_timer_overflow) if (ym2612.OPN.eg_timer == 3)
{ {
ym2612.OPN.eg_timer -= ym2612.OPN.eg_timer_overflow; ym2612.OPN.eg_timer = 0;
ym2612.OPN.eg_cnt++; ym2612.OPN.eg_cnt++;
advance_eg_channel(&ym2612.CH[0].SLOT[SLOT1]); advance_eg_channel(&ym2612.CH[0].SLOT[SLOT1]);
@ -2030,10 +2036,8 @@ int YM2612ResetChip(void)
reset_channels(&ym2612.CH[0] , 6 ); reset_channels(&ym2612.CH[0] , 6 );
for(i = 0xb6 ; i >= 0xb4 ; i-- ) for(i = 0xb6 ; i >= 0xb4 ; i-- )
{ {
/*OPNWriteReg(i ,0xc0); OPNWriteReg(i ,0xc0);
OPNWriteReg(i|0x100,0xc0);*/ OPNWriteReg(i|0x100,0xc0);
OPNWriteReg(i ,0);
OPNWriteReg(i|0x100,0);
} }
for(i = 0xb2 ; i >= 0x30 ; i-- ) for(i = 0xb2 ; i >= 0x30 ; i-- )
{ {
@ -2056,7 +2060,7 @@ void YM2612Write(unsigned int a, unsigned int v)
{ {
v &= 0xff; /* adjust to 8 bit bus */ v &= 0xff; /* adjust to 8 bit bus */
switch( a&3 ) switch( a )
{ {
case 0: /* address port 0 */ case 0: /* address port 0 */
ym2612.OPN.ST.address = v; ym2612.OPN.ST.address = v;