+fixed LFO implementation according to Nemesis description (UNTESTED, need feedback)

This commit is contained in:
ekeeke31 2009-06-15 16:23:12 +00:00
parent 256d534ea6
commit 0c8c30e3a2

View File

@ -14,12 +14,13 @@
**
** 2006~2009 Eke-Eke (Genesis Plus GX):
** Credits to Nemesis (@spritesmind.net), most of those fixes came from his tests on a Model 1 Sega Mega Drive
** More informations here: http://gendev.spritesmind.net/forum/viewtopic.php?t=386
**
** - removed unused multichip support
** - added YM2612 Context external access functions
** - added LFO phase update in CH3 special mode (Warlock birds, Alladin bug sound)
** - fixed internal timers emulation
** - added Attack Rate immediate update on register write (Batman & Robin intro)
** - implemented LFO phase update in CH3 special mode (Warlock birds, Alladin bug sound)
** - improved internal timers emulation
** - fixed Attack Rate update in some specific case (Batman & Robin intro)
** - fixed EG behavior when Attack Rate is maximal
** - fixed EG behavior when SL=0 (Mega Turrican tracks 03,09...) or/and Key ON occurs at minimal attenuation
** - added EG output immediate update on register writes
@ -29,6 +30,7 @@
** - implemented correct SSG-EG emulation (Asterix, Beavis&Butthead, Bubba'n Six & many others)
** - adjusted some EG rates
** - modified address/data port behavior
** - fixed LFO implementation (only 11 bits of precision)
**
** TODO: complete SSG-EG documentation
**
@ -582,9 +584,8 @@ typedef struct
UINT32 eg_timer_add; /* step of eg_timer */
UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 3 samples (on real chip) */
/* there are 2048 FNUMs that can be generated using FNUM/BLK registers
but LFO works with one more bit of a precision so we really need 4096 elements */
UINT32 fn_table[4096]; /* fnumber->increment counter */
/* there are 2048 FNUMs that can be generated using FNUM/BLK registers */
UINT32 fn_table[2048]; /* fnumber->increment counter */
UINT32 fn_max; /* max increment (required for calculating phase overflow) */
/* LFO */
@ -1237,20 +1238,21 @@ INLINE void update_phase_lfo_slot(FM_SLOT *SLOT , INT32 pms, UINT32 block_fnum)
{
UINT32 fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8;
INT32 lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + pms + LFO_PM ];
if (lfo_fn_table_index_offset) /* LFO phase modulation active */
{
block_fnum = block_fnum*2 + lfo_fn_table_index_offset;
/* retrieve BLOCK register value */
UINT8 blk = (block_fnum >> 11) & 7;
UINT8 blk = (block_fnum&0x7000) >> 12;
UINT32 fn = block_fnum & 0xfff;
/* increase FNUM register value */
UINT32 fn = (block_fnum + lfo_fn_table_index_offset) & 0x7ff;
/* keyscale code */
int kc = (blk<<2) | opn_fktable[fn >> 8];
/* recalculate keyscale code */
int kc = (blk<<2) | opn_fktable[fn >> 7];
/* (frequency) phase increment counter */
/* recalculate (frequency) phase increment counter */
int fc = (ym2612.OPN.fn_table[fn]>>(7-blk)) + SLOT->DT[kc];
/* (frequency) phase overflow (credits to Nemesis) */
if (fc < 0) fc += ym2612.OPN.fn_max;
@ -1266,21 +1268,22 @@ INLINE void update_phase_lfo_slot(FM_SLOT *SLOT , INT32 pms, UINT32 block_fnum)
INLINE void update_phase_lfo_channel(FM_CH *CH)
{
UINT32 block_fnum = CH->block_fnum;
UINT32 fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8;
INT32 lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + CH->pms + LFO_PM ];
if (lfo_fn_table_index_offset) /* LFO phase modulation active */
{
block_fnum = block_fnum*2 + lfo_fn_table_index_offset;
/* retrieve BLOCK register value */
UINT8 blk = (block_fnum >> 11) & 7;
UINT8 blk = (block_fnum&0x7000) >> 12;
UINT32 fn = block_fnum & 0xfff;
/* keyscale code */
int kc = (blk<<2) | opn_fktable[fn >> 8];
/* increase FNUM register value */
UINT32 fn = (block_fnum + lfo_fn_table_index_offset)& 0x7ff;
/* (frequency) phase increment counter */
/* recalculate keyscale code */
int kc = (blk<<2) | opn_fktable[fn >> 7];
/* recalculate (frequency) phase increment counter */
int fc = (ym2612.OPN.fn_table[fn]>>(7-blk));
/* (frequency) phase overflow (credits to Nemesis) */
@ -1316,7 +1319,6 @@ INLINE void chan_calc(FM_CH *CH)
UINT32 AM = LFO_AM >> CH->ams;
m2 = c1 = c2 = mem = 0;
*CH->mem_connect = CH->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */
@ -1356,7 +1358,6 @@ INLINE void chan_calc(FM_CH *CH)
if( eg_out < ENV_QUIET ) /* SLOT 4 */
*CH->connect4 += op_calc(CH->SLOT[SLOT4].phase, eg_out, c2);
/* store current MEM */
CH->mem_value = mem;
@ -1631,14 +1632,17 @@ static void OPNSetPres(int pres)
/* make time tables */
init_timetables(dt_tab);
/* there are 2048 FNUMs that can be generated using FNUM/BLK registers
but LFO works with one more bit of a precision so we really need 4096 elements */
/* there are 2048 FNUMs that can be generated using FNUM/BLK registers */
/* calculate fnumber -> increment counter table */
for(i = 0; i < 4096; i++)
for(i = 0; i < 2048; i++)
{
/* freq table for octave 7 */
/* OPN phase increment counter = 20bit */
ym2612.OPN.fn_table[i] = (UINT32)( (double)i * 32 * ym2612.OPN.ST.freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
/* the correct formula is : F-Number = (144 * fnote * 2^20 / M) / 2^(B-1) */
/* where sample clock is M/144 */
/* this means the increment value for one clock sample is FNUM * 2^(B-1) = FNUM * 64 for octave 7 */
/* we also need to handle the ratio between the chip frequency and the emulated frequency (can be 1.0) */
ym2612.OPN.fn_table[i] = (UINT32)( (double)i * 64 * ym2612.OPN.ST.freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
}
/* maximal frequency is required for Phase overflow calculation, register size is 17 bits (Nemesis) */
@ -1843,7 +1847,7 @@ INLINE void OPNWriteReg(int r, int v)
/* keyscale code */
CH->kcode = (blk<<2) | opn_fktable[fn >> 7];
/* phase increment counter */
CH->fc = ym2612.OPN.fn_table[fn*2]>>(7-blk);
CH->fc = ym2612.OPN.fn_table[fn]>>(7-blk);
/* store fnum in clear form for LFO PM calculations */
CH->block_fnum = (blk<<11) | fn;
@ -1862,7 +1866,7 @@ INLINE void OPNWriteReg(int r, int v)
/* keyscale code */
ym2612.OPN.SL3.kcode[c]= (blk<<2) | opn_fktable[fn >> 7];
/* phase increment counter */
ym2612.OPN.SL3.fc[c] = ym2612.OPN.fn_table[fn*2]>>(7-blk);
ym2612.OPN.SL3.fc[c] = ym2612.OPN.fn_table[fn]>>(7-blk);
ym2612.OPN.SL3.block_fnum[c] = (blk<<11) | fn; //fn;
ym2612.CH[2].SLOT[SLOT1].Incr=-1;
}