From fbbd1d6057ac78b1e77501613be0ab2d542f64b8 Mon Sep 17 00:00:00 2001 From: ekeeke31 Date: Thu, 11 Sep 2008 16:15:58 +0000 Subject: [PATCH] improved YM2612 emulation --- history.txt | 2 +- source/sound/fm.c | 90 ++++++++++++++++++++++++-------------------- source/sound/sound.c | 5 ++- 3 files changed, 54 insertions(+), 43 deletions(-) diff --git a/history.txt b/history.txt index faaf643..0258b86 100644 --- a/history.txt +++ b/history.txt @@ -5,7 +5,7 @@ CURRENT: --------- [Genesis] - YM2612(MAME): improved Enveloppe Generator accuracy: fix tracks #3 and #9 in Mega Turrican - +- YM2612(MAME): fixed SSG-EG emulation bug: fix Level 1 music in Alisia Dragoon [NGC/Wii] - improved menu scrolling using Wiimote D-PAD diff --git a/source/sound/fm.c b/source/sound/fm.c index 7a2193f..625e12c 100644 --- a/source/sound/fm.c +++ b/source/sound/fm.c @@ -18,12 +18,12 @@ ** - fixed CH3 CSM mode (credits to Nemesis) ** - implemented PG overflow, aka "detune bug" (Ariel, Comix Zone, Shaq Fu, Spiderman,...), credits to Nemesis ** - fixed SSG-EG support, credits to Nemesis -** - modified EG rates and frequency, tested by Nemesis on real hardware +** - modified EG rates, tested by Nemesis on real hardware ** - fixed EG attenuation level on KEY ON (Ecco 2 splash sound) ** - fixed LFO phase update for CH3 special mode (Warlock, Alladin), thanks to AamirM ** - fixed Attack rate refresh (fix Batman&Robin introduction)$ -** - fixed attenuation level when starting Substain Phase (Gynoug ?) -** - fixed Enveloppe Generator updates in some specific cases (AR maximal and/or Susbstain Level minimal) +** - fixed attenuation level at the start of Substain (Gynoug ?) +** - fixed EG updates in some specific cases (AR maximal and/or Susbstain Level minimal) ** ** 03-08-2003 Jarek Burczynski: ** - fixed YM2608 initial values (after the reset) @@ -654,7 +654,7 @@ INLINE void FM_KEYON(FM_CH *CH , int s ) SLOT->key = 1; SLOT->phase = 0; /* restart Phase Generator */ SLOT->ssgn = (SLOT->ssg & 0x04) >> 1; - + if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/) { SLOT->state = EG_ATT; /* phase -> Attack */ @@ -928,10 +928,7 @@ INLINE void advance_eg_channel(FM_SLOT *SLOT) case EG_ATT: /* attack phase */ if (!(ym2612.OPN.eg_cnt & ((1<eg_sh_ar)-1))) { - SLOT->volume += (~SLOT->volume * - (eg_inc[SLOT->eg_sel_ar + ((ym2612.OPN.eg_cnt>>SLOT->eg_sh_ar)&7)]) - )>>4; - + SLOT->volume += (~SLOT->volume * (eg_inc[SLOT->eg_sel_ar + ((ym2612.OPN.eg_cnt>>SLOT->eg_sh_ar)&7)]))>>4; if (SLOT->volume <= MIN_ATT_INDEX) { SLOT->volume = MIN_ATT_INDEX; @@ -1053,7 +1050,7 @@ INLINE void advance_eg_channel(FM_SLOT *SLOT) out = (UINT32)SLOT->volume; /* negate output (changes come from alternate bit, init comes from attack bit) */ - if ((SLOT->ssg&0x08) && (SLOT->ssgn&2)) + if ((SLOT->ssg&0x08) && (SLOT->ssgn&2) && (SLOT->state > EG_REL)) out ^= MAX_ATT_INDEX; /* we need to store the result here because we are going to change ssgn @@ -1206,10 +1203,10 @@ INLINE void chan_calc(FM_CH *CH) /* add support for 3 slot mode */ if ((ym2612.OPN.ST.mode & 0xC0) && (CH == &ym2612.CH[2])) { - update_phase_lfo_slot(&ym2612.CH[2].SLOT[SLOT1], ym2612.CH[2].pms, ym2612.OPN.SL3.block_fnum[1]); - update_phase_lfo_slot(&ym2612.CH[2].SLOT[SLOT2], ym2612.CH[2].pms, ym2612.OPN.SL3.block_fnum[2]); - update_phase_lfo_slot(&ym2612.CH[2].SLOT[SLOT3], ym2612.CH[2].pms, ym2612.OPN.SL3.block_fnum[0]); - update_phase_lfo_slot(&ym2612.CH[2].SLOT[SLOT4], ym2612.CH[2].pms, ym2612.CH[2].block_fnum); + update_phase_lfo_slot(&ym2612.CH[2].SLOT[SLOT1], CH->pms, ym2612.OPN.SL3.block_fnum[1]); + update_phase_lfo_slot(&ym2612.CH[2].SLOT[SLOT2], CH->pms, ym2612.OPN.SL3.block_fnum[2]); + update_phase_lfo_slot(&ym2612.CH[2].SLOT[SLOT3], CH->pms, ym2612.OPN.SL3.block_fnum[0]); + update_phase_lfo_slot(&ym2612.CH[2].SLOT[SLOT4], CH->pms, CH->block_fnum); } else update_phase_lfo_channel(CH); } @@ -1404,22 +1401,33 @@ static int init_tables(void) } -/* CSM Key Controll */ +/* CSM Key Controll (correct implementation, credits to Nemesis) */ INLINE void CSMKeyControll(FM_CH *CH) { - /* correct implementation (credits to Nemesis) */ + /* all key on/off */ + if (CH->SLOT[SLOT1].state == EG_REL) + { + FM_KEYON(CH,SLOT1); + FM_KEYOFF(CH,SLOT1); + } - /* all key on */ - FM_KEYON(CH,SLOT1); + if (CH->SLOT[SLOT2].state == EG_REL) + { FM_KEYON(CH,SLOT2); - FM_KEYON(CH,SLOT3); - FM_KEYON(CH,SLOT4); + FM_KEYOFF(CH,SLOT2); + } - /* all key off */ - FM_KEYOFF(CH,SLOT1); - FM_KEYOFF(CH,SLOT2); - FM_KEYOFF(CH,SLOT3); + if (CH->SLOT[SLOT3].state == EG_REL) + { + FM_KEYON(CH,SLOT3); + FM_KEYOFF(CH,SLOT3); + } + + if (CH->SLOT[SLOT4].state == EG_REL) + { + FM_KEYON(CH,SLOT4); FM_KEYOFF(CH,SLOT4); + } } static void INTERNAL_TIMER_A() @@ -1466,13 +1474,13 @@ static void OPNSetPres(int pres) /* YM2612 running at original frequency (~53 kHz) */ if (config.hq_fm) ym2612.OPN.ST.freqbase = 1.0; + ym2612.OPN.eg_timer_add = (UINT32)((1<= ym2612.OPN.eg_timer_overflow) - { - ym2612.OPN.eg_timer -= ym2612.OPN.eg_timer_overflow; - ym2612.OPN.eg_cnt++; - - advance_eg_channel(&ym2612.CH[0].SLOT[SLOT1]); - advance_eg_channel(&ym2612.CH[1].SLOT[SLOT1]); - advance_eg_channel(&ym2612.CH[2].SLOT[SLOT1]); - advance_eg_channel(&ym2612.CH[3].SLOT[SLOT1]); - advance_eg_channel(&ym2612.CH[4].SLOT[SLOT1]); - advance_eg_channel(&ym2612.CH[5].SLOT[SLOT1]); - } - /* calculate FM */ chan_calc(&ym2612.CH[0]); chan_calc(&ym2612.CH[1]); @@ -1814,6 +1807,21 @@ void YM2612UpdateOne(int **buffer, int length) } else chan_calc(&ym2612.CH[5]); + /* advance envelope generator */ + ym2612.OPN.eg_timer += ym2612.OPN.eg_timer_add; + while (ym2612.OPN.eg_timer >= ym2612.OPN.eg_timer_overflow) + { + ym2612.OPN.eg_timer -= ym2612.OPN.eg_timer_overflow; + ym2612.OPN.eg_cnt++; + + advance_eg_channel(&ym2612.CH[0].SLOT[SLOT1]); + advance_eg_channel(&ym2612.CH[1].SLOT[SLOT1]); + advance_eg_channel(&ym2612.CH[2].SLOT[SLOT1]); + advance_eg_channel(&ym2612.CH[3].SLOT[SLOT1]); + advance_eg_channel(&ym2612.CH[4].SLOT[SLOT1]); + advance_eg_channel(&ym2612.CH[5].SLOT[SLOT1]); + } + lt = ((out_fm[0]>>0) & ym2612.OPN.pan[0]); rt = ((out_fm[0]>>0) & ym2612.OPN.pan[1]); lt += ((out_fm[1]>>0) & ym2612.OPN.pan[2]); diff --git a/source/sound/sound.c b/source/sound/sound.c index 986a7f9..56ad1d9 100644 --- a/source/sound/sound.c +++ b/source/sound/sound.c @@ -218,9 +218,12 @@ void fm_restore(void) /* write FM chip */ void fm_write(unsigned int cpu, unsigned int address, unsigned int data) { + if (address & 1) + { snd.fm.curStage = fm_sample_cnt(cpu); fm_update(); - _YM2612_Write(address & 3, data); + } + _YM2612_Write(address & 3, data); } /* read FM status */