mirror of
https://github.com/holub/mame
synced 2025-05-24 06:30:04 +03:00
YM2612: More accurate LFO implementation and channel clipping [Eke-Eke, Nemesis, R. Belmont]
This commit is contained in:
parent
f373246c42
commit
c6d4f5faa8
@ -6,7 +6,7 @@
|
||||
** Copyright Jarek Burczynski (bujar at mame dot net)
|
||||
** Copyright Tatsuyuki Satoh , MultiArcadeMachineEmulator development
|
||||
**
|
||||
** Version 1.5 (Genesis Plus GX ym2612.c rev. 346)
|
||||
** Version 1.5.1 (Genesis Plus GX ym2612.c rev. 368)
|
||||
**
|
||||
*/
|
||||
|
||||
@ -14,25 +14,31 @@
|
||||
** History:
|
||||
**
|
||||
** 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
|
||||
** Huge thanks to Nemesis, lot of those fixes came from his tests on Sega Genesis hardware
|
||||
** More informations at http://gendev.spritesmind.net/forum/viewtopic.php?t=386
|
||||
**
|
||||
** - fixed LFO implementation (Spider-Man & Venom : Separation Anxiety intro,Warlock birds, Aladdin bug sound):
|
||||
** .added support for CH3 special mode
|
||||
** .fixed LFO update: it is done after output calculation, like EG/PG updates
|
||||
** .fixed LFO on/off behavior: LFO is reset when switched ON and holded at its current level when switched OFF (AM & PM can still be applied)
|
||||
** TODO:
|
||||
**
|
||||
** - core documentation
|
||||
** - BUSY flag support
|
||||
**
|
||||
** CHANGELOG:
|
||||
**
|
||||
** - fixed LFO implementation:
|
||||
** .added support for CH3 special mode: fixes various sound effects (birds in Warlock, bug sound in Aladdin...)
|
||||
** .modified LFO behavior when switched off (AM/PM current level is held) and on (LFO step is reseted): fixes intro in Spider-Man & Venom : Separation Anxiety
|
||||
** .improved LFO timing accuracy: now updated AFTER sample output, like EG/PG updates, and without any precision loss anymore.
|
||||
** - improved internal timers emulation
|
||||
** - fixed Attack Rate update in some specific case (Batman & Robin intro)
|
||||
** - adjusted lowest EG rates increment values
|
||||
** - fixed Attack Rate not being updated in some specific cases (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
|
||||
** - fixed YM2612 initial values (after the reset)
|
||||
** - implemented Detune overflow (Ariel, Comix Zone, Shaq Fu, Spiderman & many others)
|
||||
** - implemented correct CSM mode emulation
|
||||
** - implemented correct SSG-EG emulation (Asterix, Beavis&Butthead, Bubba'n Six & many others)
|
||||
** - adjusted some EG rates
|
||||
**
|
||||
** TODO: fix SSG-EG documentation, BUSY flag support
|
||||
** - implemented EG output immediate changes on register writes
|
||||
** - fixed YM2612 initial values (after the reset): fixes missing intro in B.O.B
|
||||
** - implemented Detune overflow (Ariel, Comix Zone, Shaq Fu, Spiderman & many other games using GEMS sound engine)
|
||||
** - implemented accurate CSM mode emulation
|
||||
** - implemented accurate SSG-EG emulation (Asterix, Beavis&Butthead, Bubba'n Stix & many other games)
|
||||
** - implemented accurate address/data ports behavior
|
||||
**
|
||||
** 06-23-2007 Zsolt Vasvari:
|
||||
** - changed the timing not to require the use of floating point calculations
|
||||
@ -239,49 +245,8 @@ static const UINT8 eg_inc[19*RATE_STEPS]={
|
||||
#define O(a) (a*RATE_STEPS)
|
||||
|
||||
/*note that there is no O(17) in this table - it's directly in the code */
|
||||
static const UINT8 eg_rate_select[32+64+32]={ /* Envelope Generator rates (32 + 64 rates + 32 RKS) */
|
||||
/* 32 infinite time rates */
|
||||
O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
|
||||
O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
|
||||
O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
|
||||
O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
|
||||
|
||||
/* rates 00-11 */
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
|
||||
/* rate 12 */
|
||||
O( 4),O( 5),O( 6),O( 7),
|
||||
|
||||
/* rate 13 */
|
||||
O( 8),O( 9),O(10),O(11),
|
||||
|
||||
/* rate 14 */
|
||||
O(12),O(13),O(14),O(15),
|
||||
|
||||
/* rate 15 */
|
||||
O(16),O(16),O(16),O(16),
|
||||
|
||||
/* 32 dummy rates (same as 15 3) */
|
||||
O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),
|
||||
O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),
|
||||
O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),
|
||||
O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16)
|
||||
|
||||
};
|
||||
|
||||
static const UINT8 eg_rate_select2612[32+64+32]={ /* Envelope Generator rates (32 + 64 rates + 32 RKS) from tests on YM2612 */
|
||||
/* 32 infinite time rates */
|
||||
static const UINT8 eg_rate_select2612[32+64+32]={ /* Envelope Generator rates (32 + 64 rates + 32 RKS) */
|
||||
/* 32 infinite time rates (same as Rate 0) */
|
||||
O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
|
||||
O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
|
||||
O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
|
||||
@ -334,10 +299,16 @@ O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16)
|
||||
#define O(a) (a*1)
|
||||
static const UINT8 eg_rate_shift[32+64+32]={ /* Envelope Generator counter shifts (32 + 64 rates + 32 RKS) */
|
||||
/* 32 infinite time rates */
|
||||
/* O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
|
||||
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
|
||||
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
|
||||
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
|
||||
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
|
||||
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), */
|
||||
|
||||
/* fixed (should be the same as rate 0, even if it makes no difference since increment value is 0 for these rates) */
|
||||
O(11),O(11),O(11),O(11),O(11),O(11),O(11),O(11),
|
||||
O(11),O(11),O(11),O(11),O(11),O(11),O(11),O(11),
|
||||
O(11),O(11),O(11),O(11),O(11),O(11),O(11),O(11),
|
||||
O(11),O(11),O(11),O(11),O(11),O(11),O(11),O(11),
|
||||
|
||||
/* rates 00-11 */
|
||||
O(11),O(11),O(11),O(11),
|
||||
@ -682,7 +653,7 @@ typedef struct
|
||||
unsigned int pan[6*2]; /* fm channels output masks (0xffffffff = enable) */
|
||||
|
||||
UINT32 eg_cnt; /* global envelope generator counter */
|
||||
UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/64/3 */
|
||||
UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/144/3 */
|
||||
UINT32 eg_timer_add; /* step of eg_timer */
|
||||
UINT32 eg_timer_overflow;/* envelope generator timer overlfows every 3 samples (on real chip) */
|
||||
|
||||
@ -693,15 +664,26 @@ typedef struct
|
||||
UINT32 fn_max; /* maximal phase increment (used for phase overflow) */
|
||||
|
||||
/* LFO */
|
||||
UINT32 lfo_cnt;
|
||||
UINT32 lfo_inc;
|
||||
UINT32 lfo_freq[8]; /* LFO FREQ table */
|
||||
|
||||
UINT32 LFO_AM; /* runtime LFO calculations helper */
|
||||
INT32 LFO_PM; /* runtime LFO calculations helper */
|
||||
UINT8 lfo_cnt; /* current LFO phase (out of 128) */
|
||||
UINT32 lfo_timer; /* current LFO phase runs at LFO frequency */
|
||||
UINT32 lfo_timer_add; /* step of lfo_timer */
|
||||
UINT32 lfo_timer_overflow; /* LFO timer overflows every N samples (depends on LFO frequency) */
|
||||
UINT32 LFO_AM; /* current LFO AM step */
|
||||
UINT32 LFO_PM; /* current LFO PM step */
|
||||
} FM_OPN;
|
||||
|
||||
/* here's the virtual YM2612 */
|
||||
typedef struct
|
||||
{
|
||||
UINT8 REGS[512]; /* registers */
|
||||
FM_OPN OPN; /* OPN state */
|
||||
FM_CH CH[6]; /* channel state */
|
||||
UINT8 addr_A1; /* address line A1 */
|
||||
|
||||
/* dac output (YM2612) */
|
||||
int dacen;
|
||||
INT32 dacout;
|
||||
} YM2612;
|
||||
|
||||
/* current chip state */
|
||||
static INT32 m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */
|
||||
@ -1211,55 +1193,33 @@ INLINE void set_sl_rr(UINT8 type, FM_SLOT *SLOT,int v)
|
||||
SLOT->eg_sel_rr = eg_rate_select2612[SLOT->rr + SLOT->ksr];
|
||||
}
|
||||
|
||||
|
||||
|
||||
INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm)
|
||||
{
|
||||
UINT32 p;
|
||||
|
||||
p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ];
|
||||
|
||||
if (p >= TL_TAB_LEN)
|
||||
return 0;
|
||||
return tl_tab[p];
|
||||
}
|
||||
|
||||
INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm)
|
||||
{
|
||||
UINT32 p;
|
||||
|
||||
p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK ];
|
||||
|
||||
if (p >= TL_TAB_LEN)
|
||||
return 0;
|
||||
return tl_tab[p];
|
||||
}
|
||||
|
||||
/* advance LFO to next sample */
|
||||
INLINE void advance_lfo(FM_OPN *OPN)
|
||||
{
|
||||
int pos;
|
||||
|
||||
if (OPN->lfo_inc) /* LFO enabled ? */
|
||||
if (OPN->lfo_timer_overflow) /* LFO enabled ? */
|
||||
{
|
||||
/* increment LFO counter */
|
||||
/* when LFO is enabled, one level will last for 108, 77, 71, 67, 62, 44, 8 or 5 samples */
|
||||
OPN->lfo_cnt += OPN->lfo_inc;
|
||||
/* increment LFO timer */
|
||||
OPN->lfo_timer += OPN->lfo_timer_add;
|
||||
|
||||
/* LFO current position */
|
||||
pos = ( OPN->lfo_cnt >> LFO_SH) & 127;
|
||||
/* when LFO is enabled, one level will last for 108, 77, 71, 67, 62, 44, 8 or 5 samples */
|
||||
while (OPN->lfo_timer >= OPN->lfo_timer_overflow)
|
||||
{
|
||||
OPN->lfo_timer -= OPN->lfo_timer_overflow;
|
||||
|
||||
/* There are 128 LFO steps */
|
||||
OPN->lfo_cnt = ( OPN->lfo_cnt + 1 ) & 127;
|
||||
|
||||
/* triangle */
|
||||
/* AM: 0 to 126 step +2, 126 to 0 step -2 */
|
||||
if (pos<64)
|
||||
OPN->LFO_AM = pos * 2;
|
||||
if (OPN->lfo_cnt<64)
|
||||
OPN->LFO_AM = OPN->lfo_cnt * 2;
|
||||
else
|
||||
OPN->LFO_AM = 126 - ((pos&63) * 2);
|
||||
OPN->LFO_AM = 126 - ((OPN->lfo_cnt&63) * 2);
|
||||
|
||||
/* PM works with 4 times slower clock */
|
||||
OPN->LFO_PM = pos >> 2;
|
||||
OPN->LFO_PM = OPN->lfo_cnt >> 2;
|
||||
}
|
||||
}
|
||||
/* when LFO is disabled, current level is held (fix Spider-Man & Venom : Separation Anxiety) */
|
||||
}
|
||||
|
||||
/* changed from INLINE to static here to work around gcc 4.2.1 codegen bug */
|
||||
@ -1475,8 +1435,6 @@ static void update_ssg_eg_channel(FM_SLOT *SLOT)
|
||||
}
|
||||
|
||||
|
||||
#define volume_calc(OP) ((OP)->vol_out + (AM & (OP)->AMmask))
|
||||
|
||||
INLINE void update_phase_lfo_slot(FM_OPN *OPN, FM_SLOT *SLOT, INT32 pms, UINT32 block_fnum)
|
||||
{
|
||||
UINT32 fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8;
|
||||
@ -1553,80 +1511,6 @@ INLINE void update_phase_lfo_channel(FM_OPN *OPN, FM_CH *CH)
|
||||
}
|
||||
}
|
||||
|
||||
INLINE void chan_calc(FM_OPN *OPN, FM_CH *CH, int chnum)
|
||||
{
|
||||
unsigned int eg_out;
|
||||
|
||||
UINT32 AM = OPN->LFO_AM >> CH->ams;
|
||||
|
||||
|
||||
m2 = c1 = c2 = mem = 0;
|
||||
|
||||
*CH->mem_connect = CH->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */
|
||||
|
||||
eg_out = volume_calc(&CH->SLOT[SLOT1]);
|
||||
{
|
||||
INT32 out = CH->op1_out[0] + CH->op1_out[1];
|
||||
CH->op1_out[0] = CH->op1_out[1];
|
||||
|
||||
if( !CH->connect1 ){
|
||||
/* algorithm 5 */
|
||||
mem = c1 = c2 = CH->op1_out[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* other algorithms */
|
||||
*CH->connect1 += CH->op1_out[0];
|
||||
}
|
||||
|
||||
CH->op1_out[1] = 0;
|
||||
if( eg_out < ENV_QUIET ) /* SLOT 1 */
|
||||
{
|
||||
if (!CH->FB)
|
||||
out=0;
|
||||
|
||||
CH->op1_out[1] = op_calc1(CH->SLOT[SLOT1].phase, eg_out, (out<<CH->FB) );
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
/* store current MEM */
|
||||
CH->mem_value = mem;
|
||||
|
||||
/* update phase counters AFTER output calculations */
|
||||
if(CH->pms)
|
||||
{
|
||||
/* add support for 3 slot mode */
|
||||
if ((OPN->ST.mode & 0xC0) && (chnum == 2))
|
||||
{
|
||||
update_phase_lfo_slot(OPN, &CH->SLOT[SLOT1], CH->pms, OPN->SL3.block_fnum[1]);
|
||||
update_phase_lfo_slot(OPN, &CH->SLOT[SLOT2], CH->pms, OPN->SL3.block_fnum[2]);
|
||||
update_phase_lfo_slot(OPN, &CH->SLOT[SLOT3], CH->pms, OPN->SL3.block_fnum[0]);
|
||||
update_phase_lfo_slot(OPN, &CH->SLOT[SLOT4], CH->pms, CH->block_fnum);
|
||||
}
|
||||
else update_phase_lfo_channel(OPN, CH);
|
||||
}
|
||||
else /* no LFO phase modulation */
|
||||
{
|
||||
CH->SLOT[SLOT1].phase += CH->SLOT[SLOT1].Incr;
|
||||
CH->SLOT[SLOT2].phase += CH->SLOT[SLOT2].Incr;
|
||||
CH->SLOT[SLOT3].phase += CH->SLOT[SLOT3].Incr;
|
||||
CH->SLOT[SLOT4].phase += CH->SLOT[SLOT4].Incr;
|
||||
}
|
||||
}
|
||||
|
||||
/* update phase increment and envelope generator */
|
||||
INLINE void refresh_fc_eg_slot(FM_OPN *OPN, FM_SLOT *SLOT , int fc , int kc )
|
||||
{
|
||||
@ -1680,174 +1564,100 @@ static void refresh_fc_eg_chan(FM_OPN *OPN, FM_CH *CH )
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize time tables */
|
||||
static void init_timetables( FM_ST *ST , const UINT8 *dttable )
|
||||
#define volume_calc(OP) ((OP)->vol_out + (AM & (OP)->AMmask))
|
||||
|
||||
INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm)
|
||||
{
|
||||
int i,d;
|
||||
double rate;
|
||||
UINT32 p;
|
||||
|
||||
#if 0
|
||||
logerror("FM.C: samplerate=%8i chip clock=%8i freqbase=%f \n",
|
||||
ST->rate, ST->clock, ST->freqbase );
|
||||
#endif
|
||||
|
||||
/* DeTune table */
|
||||
for (d = 0;d <= 3;d++){
|
||||
for (i = 0;i <= 31;i++){
|
||||
rate = ((double)dttable[d*32 + i]) * SIN_LEN * ST->freqbase * (1<<FREQ_SH) / ((double)(1<<20));
|
||||
ST->dt_tab[d][i] = (INT32) rate;
|
||||
ST->dt_tab[d+4][i] = -ST->dt_tab[d][i];
|
||||
#if 0
|
||||
logerror("FM.C: DT [%2i %2i] = %8x \n", d, i, ST->dt_tab[d][i] );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ];
|
||||
|
||||
if (p >= TL_TAB_LEN)
|
||||
return 0;
|
||||
return tl_tab[p];
|
||||
}
|
||||
|
||||
|
||||
static void reset_channels( FM_ST *ST , FM_CH *CH , int num )
|
||||
INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm)
|
||||
{
|
||||
int c,s;
|
||||
UINT32 p;
|
||||
|
||||
ST->mode = 0; /* normal mode */
|
||||
ST->TA = 0;
|
||||
ST->TAC = 0;
|
||||
ST->TB = 0;
|
||||
ST->TBC = 0;
|
||||
p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK ];
|
||||
|
||||
for( c = 0 ; c < num ; c++ )
|
||||
{
|
||||
CH[c].fc = 0;
|
||||
for(s = 0 ; s < 4 ; s++ )
|
||||
{
|
||||
CH[c].SLOT[s].ssg = 0;
|
||||
CH[c].SLOT[s].ssgn = 0;
|
||||
CH[c].SLOT[s].state= EG_OFF;
|
||||
CH[c].SLOT[s].volume = MAX_ATT_INDEX;
|
||||
CH[c].SLOT[s].vol_out= MAX_ATT_INDEX;
|
||||
}
|
||||
}
|
||||
if (p >= TL_TAB_LEN)
|
||||
return 0;
|
||||
return tl_tab[p];
|
||||
}
|
||||
|
||||
/* initialize generic tables */
|
||||
static int init_tables(void)
|
||||
INLINE void chan_calc(YM2612 *F2612, FM_OPN *OPN, FM_CH *CH)
|
||||
{
|
||||
signed int i,x;
|
||||
signed int n;
|
||||
double o,m;
|
||||
UINT32 AM = OPN->LFO_AM >> CH->ams;
|
||||
|
||||
for (x=0; x<TL_RES_LEN; x++)
|
||||
m2 = c1 = c2 = mem = 0;
|
||||
|
||||
*CH->mem_connect = CH->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */
|
||||
|
||||
unsigned int eg_out = volume_calc(&CH->SLOT[SLOT1]);
|
||||
{
|
||||
m = (1<<16) / pow(2, (x+1) * (ENV_STEP/4.0) / 8.0);
|
||||
m = floor(m);
|
||||
INT32 out = CH->op1_out[0] + CH->op1_out[1];
|
||||
CH->op1_out[0] = CH->op1_out[1];
|
||||
|
||||
/* we never reach (1<<16) here due to the (x+1) */
|
||||
/* result fits within 16 bits at maximum */
|
||||
|
||||
n = (int)m; /* 16 bits here */
|
||||
n >>= 4; /* 12 bits here */
|
||||
if (n&1) /* round to nearest */
|
||||
n = (n>>1)+1;
|
||||
else
|
||||
n = n>>1;
|
||||
/* 11 bits here (rounded) */
|
||||
n <<= 2; /* 13 bits here (as in real chip) */
|
||||
tl_tab[ x*2 + 0 ] = n;
|
||||
tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ];
|
||||
|
||||
for (i=1; i<13; i++)
|
||||
{
|
||||
tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i;
|
||||
tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ];
|
||||
}
|
||||
#if 0
|
||||
logerror("tl %04i", x);
|
||||
for (i=0; i<13; i++)
|
||||
logerror(", [%02i] %4x", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ]);
|
||||
logerror("\n");
|
||||
#endif
|
||||
}
|
||||
/*logerror("FM.C: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/
|
||||
|
||||
|
||||
for (i=0; i<SIN_LEN; i++)
|
||||
{
|
||||
/* non-standard sinus */
|
||||
m = sin( ((i*2)+1) * M_PI / SIN_LEN ); /* checked against the real chip */
|
||||
|
||||
/* we never reach zero here due to ((i*2)+1) */
|
||||
|
||||
if (m>0.0)
|
||||
o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */
|
||||
else
|
||||
o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */
|
||||
|
||||
o = o / (ENV_STEP/4);
|
||||
|
||||
n = (int)(2.0*o);
|
||||
if (n&1) /* round to nearest */
|
||||
n = (n>>1)+1;
|
||||
else
|
||||
n = n>>1;
|
||||
|
||||
sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 );
|
||||
/*logerror("FM.C: sin [%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[i],tl_tab[sin_tab[i]]);*/
|
||||
}
|
||||
|
||||
/*logerror("FM.C: ENV_QUIET= %08x\n",ENV_QUIET );*/
|
||||
|
||||
|
||||
/* build LFO PM modulation table */
|
||||
for(i = 0; i < 8; i++) /* 8 PM depths */
|
||||
{
|
||||
UINT8 fnum;
|
||||
for (fnum=0; fnum<128; fnum++) /* 7 bits meaningful of F-NUMBER */
|
||||
{
|
||||
UINT8 value;
|
||||
UINT8 step;
|
||||
UINT32 offset_depth = i;
|
||||
UINT32 offset_fnum_bit;
|
||||
UINT32 bit_tmp;
|
||||
|
||||
for (step=0; step<8; step++)
|
||||
{
|
||||
value = 0;
|
||||
for (bit_tmp=0; bit_tmp<7; bit_tmp++) /* 7 bits */
|
||||
{
|
||||
if (fnum & (1<<bit_tmp)) /* only if bit "bit_tmp" is set */
|
||||
{
|
||||
offset_fnum_bit = bit_tmp * 8;
|
||||
value += lfo_pm_output[offset_fnum_bit + offset_depth][step];
|
||||
}
|
||||
}
|
||||
lfo_pm_table[(fnum*32*8) + (i*32) + step + 0] = value;
|
||||
lfo_pm_table[(fnum*32*8) + (i*32) +(step^7)+ 8] = value;
|
||||
lfo_pm_table[(fnum*32*8) + (i*32) + step +16] = -value;
|
||||
lfo_pm_table[(fnum*32*8) + (i*32) +(step^7)+24] = -value;
|
||||
}
|
||||
#if 0
|
||||
logerror("LFO depth=%1x FNUM=%04x (<<4=%4x): ", i, fnum, fnum<<4);
|
||||
for (step=0; step<16; step++) /* dump only positive part of waveforms */
|
||||
logerror("%02x ", lfo_pm_table[(fnum*32*8) + (i*32) + step] );
|
||||
logerror("\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
if( !CH->connect1 ){
|
||||
/* algorithm 5 */
|
||||
mem = c1 = c2 = CH->op1_out[0];
|
||||
}else{
|
||||
/* other algorithms */
|
||||
*CH->connect1 += CH->op1_out[0];
|
||||
}
|
||||
|
||||
|
||||
CH->op1_out[1] = 0;
|
||||
if( eg_out < ENV_QUIET ) /* SLOT 1 */
|
||||
{
|
||||
if (!CH->FB)
|
||||
out=0;
|
||||
|
||||
#ifdef SAVE_SAMPLE
|
||||
sample[0]=fopen("sampsum.pcm","wb");
|
||||
#endif
|
||||
CH->op1_out[1] = op_calc1(CH->SLOT[SLOT1].phase, eg_out, (out<<CH->FB) );
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
/* store current MEM */
|
||||
CH->mem_value = mem;
|
||||
|
||||
/* update phase counters AFTER output calculations */
|
||||
if(CH->pms)
|
||||
{
|
||||
/* add support for 3 slot mode */
|
||||
if ((OPN->ST.mode & 0xC0) && (CH == &F2612->CH[2]))
|
||||
{
|
||||
update_phase_lfo_slot(OPN, &CH->SLOT[SLOT1], CH->pms, OPN->SL3.block_fnum[1]);
|
||||
update_phase_lfo_slot(OPN, &CH->SLOT[SLOT2], CH->pms, OPN->SL3.block_fnum[2]);
|
||||
update_phase_lfo_slot(OPN, &CH->SLOT[SLOT3], CH->pms, OPN->SL3.block_fnum[0]);
|
||||
update_phase_lfo_slot(OPN, &CH->SLOT[SLOT4], CH->pms, CH->block_fnum);
|
||||
}
|
||||
else update_phase_lfo_channel(OPN, CH);
|
||||
}
|
||||
else /* no LFO phase modulation */
|
||||
{
|
||||
CH->SLOT[SLOT1].phase += CH->SLOT[SLOT1].Incr;
|
||||
CH->SLOT[SLOT2].phase += CH->SLOT[SLOT2].Incr;
|
||||
CH->SLOT[SLOT3].phase += CH->SLOT[SLOT3].Incr;
|
||||
CH->SLOT[SLOT4].phase += CH->SLOT[SLOT4].Incr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void FMCloseTable( void )
|
||||
{
|
||||
#ifdef SAVE_SAMPLE
|
||||
@ -1911,70 +1721,6 @@ static void FMsave_state_st(const device_config *device,FM_ST *ST)
|
||||
#endif /* _STATE_H */
|
||||
|
||||
#if BUILD_OPN
|
||||
|
||||
|
||||
|
||||
/* prescaler set (and make time tables) */
|
||||
static void OPNSetPres(FM_OPN *OPN, int pres, int timer_prescaler, int SSGpres)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* frequency base */
|
||||
OPN->ST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock / OPN->ST.rate) / pres : 0;
|
||||
|
||||
#if 0
|
||||
OPN->ST.rate = (double)OPN->ST.clock / pres;
|
||||
OPN->ST.freqbase = 1.0;
|
||||
#endif
|
||||
|
||||
OPN->eg_timer_add = (1<<EG_SH) * OPN->ST.freqbase;
|
||||
OPN->eg_timer_overflow = ( 3 ) * (1<<EG_SH);
|
||||
|
||||
|
||||
/* Timer base time */
|
||||
OPN->ST.timer_prescaler = timer_prescaler;
|
||||
|
||||
/* SSG part prescaler set */
|
||||
if( SSGpres ) (*OPN->ST.SSG->set_clock)( OPN->ST.param, OPN->ST.clock * 2 / SSGpres );
|
||||
|
||||
/* make time tables */
|
||||
init_timetables( &OPN->ST, 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 */
|
||||
for(i = 0; i < 4096; i++)
|
||||
{
|
||||
/* freq table for octave 7 */
|
||||
/* OPN phase increment counter = 20bit */
|
||||
/* 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) */
|
||||
OPN->fn_table[i] = (UINT32)( (double)i * 32 * OPN->ST.freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
|
||||
#if 0
|
||||
logerror("FM.C: fn_table[%4i] = %08x (dec=%8i)\n",
|
||||
i, OPN->fn_table[i]>>6,OPN->fn_table[i]>>6 );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* maximal frequency is required for Phase overflow calculation, register size is 17 bits (Nemesis) */
|
||||
OPN->fn_max = (UINT32)( (double)0x20000 * OPN->ST.freqbase * (1<<(FREQ_SH-10)) );
|
||||
|
||||
/* LFO freq. table */
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
/* Amplitude modulation: 64 output levels (triangle waveform); 1 level lasts for one of "lfo_samples_per_step" samples */
|
||||
/* Phase modulation: one entry from lfo_pm_output lasts for one of 4 * "lfo_samples_per_step" samples */
|
||||
OPN->lfo_freq[i] = (1.0 / lfo_samples_per_step[i]) * (1<<LFO_SH) * OPN->ST.freqbase;
|
||||
#if 0
|
||||
logerror("FM.C: lfo_freq[%i] = %08x (dec=%8i)\n",
|
||||
i, OPN->lfo_freq[i],OPN->lfo_freq[i] );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* write a OPN mode register 0x20-0x2f */
|
||||
static void OPNWriteMode(FM_OPN *OPN, int r, int v)
|
||||
{
|
||||
@ -1985,21 +1731,22 @@ static void OPNWriteMode(FM_OPN *OPN, int r, int v)
|
||||
case 0x21: /* Test */
|
||||
break;
|
||||
case 0x22: /* LFO FREQ (YM2608/YM2610/YM2610B/YM2612) */
|
||||
if (v&0x08) /* LFO enabled ? */
|
||||
if (v&8) /* LFO enabled ? */
|
||||
{
|
||||
if (!OPN->lfo_inc)
|
||||
if (!OPN->lfo_timer_overflow)
|
||||
{
|
||||
/* restart LFO */
|
||||
OPN->lfo_cnt = 0;
|
||||
OPN->lfo_timer = 0;
|
||||
OPN->LFO_AM = 0;
|
||||
OPN->LFO_PM = 0;
|
||||
}
|
||||
|
||||
OPN->lfo_inc = OPN->lfo_freq[v&7];
|
||||
OPN->lfo_timer_overflow = lfo_samples_per_step[v&7] << LFO_SH;
|
||||
}
|
||||
else
|
||||
{
|
||||
OPN->lfo_inc = 0;
|
||||
OPN->lfo_timer_overflow = 0;
|
||||
}
|
||||
break;
|
||||
case 0x24: /* timer A High 8*/
|
||||
@ -2231,25 +1978,192 @@ static void OPNWriteReg(FM_OPN *OPN, int r, int v)
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize time tables */
|
||||
static void init_timetables(FM_OPN *OPN, double freqbase)
|
||||
{
|
||||
int i,d;
|
||||
double rate;
|
||||
|
||||
/* DeTune table */
|
||||
for (d = 0;d <= 3;d++)
|
||||
{
|
||||
for (i = 0;i <= 31;i++)
|
||||
{
|
||||
rate = ((double)dt_tab[d*32 + i]) * freqbase * (1<<(FREQ_SH-10)); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
|
||||
OPN->ST.dt_tab[d][i] = (INT32) rate;
|
||||
OPN->ST.dt_tab[d+4][i] = -OPN->ST.dt_tab[d][i];
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
/* calculate fnumber -> increment counter table */
|
||||
for(i = 0; i < 4096; i++)
|
||||
{
|
||||
/* freq table for octave 7 */
|
||||
/* OPN phase increment counter = 20bit */
|
||||
/* 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) */
|
||||
OPN->fn_table[i] = (UINT32)( (double)i * 32 * 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) */
|
||||
OPN->fn_max = (UINT32)( (double)0x20000 * freqbase * (1<<(FREQ_SH-10)) );
|
||||
}
|
||||
|
||||
/* prescaler set (and make time tables) */
|
||||
static void OPNSetPres(FM_OPN *OPN, int pres, int timer_prescaler, int SSGpres)
|
||||
{
|
||||
/* frequency base */
|
||||
OPN->ST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock / OPN->ST.rate) / pres : 0;
|
||||
|
||||
/* EG is updated every 3 samples */
|
||||
OPN->eg_timer_add = (UINT32)((1<<EG_SH) * OPN->ST.freqbase);
|
||||
OPN->eg_timer_overflow = ( 3 ) * (1<<EG_SH);
|
||||
|
||||
/* LFO timer increment (every samples) */
|
||||
OPN->lfo_timer_add = (UINT32)((1<<LFO_SH) * OPN->ST.freqbase);
|
||||
|
||||
/* Timer base time */
|
||||
OPN->ST.timer_prescaler = timer_prescaler;
|
||||
|
||||
/* SSG part prescaler set */
|
||||
if( SSGpres ) (*OPN->ST.SSG->set_clock)( OPN->ST.param, OPN->ST.clock * 2 / SSGpres );
|
||||
|
||||
/* make time tables */
|
||||
init_timetables(OPN, OPN->ST.freqbase);
|
||||
}
|
||||
|
||||
static void reset_channels( FM_ST *ST , FM_CH *CH , int num )
|
||||
{
|
||||
int c,s;
|
||||
|
||||
for( c = 0 ; c < num ; c++ )
|
||||
{
|
||||
CH[c].fc = 0;
|
||||
for(s = 0 ; s < 4 ; s++ )
|
||||
{
|
||||
CH[c].SLOT[s].ssg = 0;
|
||||
CH[c].SLOT[s].ssgn = 0;
|
||||
CH[c].SLOT[s].state= EG_OFF;
|
||||
CH[c].SLOT[s].volume = MAX_ATT_INDEX;
|
||||
CH[c].SLOT[s].vol_out= MAX_ATT_INDEX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize generic tables */
|
||||
static void init_tables(void)
|
||||
{
|
||||
signed int i,x;
|
||||
signed int n;
|
||||
double o,m;
|
||||
|
||||
/* build Linear Power Table */
|
||||
for (x=0; x<TL_RES_LEN; x++)
|
||||
{
|
||||
m = (1<<16) / pow(2, (x+1) * (ENV_STEP/4.0) / 8.0);
|
||||
m = floor(m);
|
||||
|
||||
/* we never reach (1<<16) here due to the (x+1) */
|
||||
/* result fits within 16 bits at maximum */
|
||||
|
||||
n = (int)m; /* 16 bits here */
|
||||
n >>= 4; /* 12 bits here */
|
||||
if (n&1) /* round to nearest */
|
||||
n = (n>>1)+1;
|
||||
else
|
||||
n = n>>1;
|
||||
/* 11 bits here (rounded) */
|
||||
n <<= 2; /* 13 bits here (as in real chip) */
|
||||
|
||||
|
||||
/* 14 bits (with sign bit) */
|
||||
tl_tab[ x*2 + 0 ] = n;
|
||||
tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ];
|
||||
|
||||
/* one entry in the 'Power' table use the following format, xxxxxyyyyyyyys with: */
|
||||
/* s = sign bit */
|
||||
/* yyyyyyyy = 8-bits decimal part (0-TL_RES_LEN) */
|
||||
/* xxxxx = 5-bits integer 'shift' value (0-31) but, since Power table output is 13 bits, */
|
||||
/* any value above 13 (included) would be discarded. */
|
||||
for (i=1; i<13; i++)
|
||||
{
|
||||
tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i;
|
||||
tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ];
|
||||
}
|
||||
}
|
||||
|
||||
/* build Logarithmic Sinus table */
|
||||
for (i=0; i<SIN_LEN; i++)
|
||||
{
|
||||
/* non-standard sinus */
|
||||
m = sin( ((i*2)+1) * M_PI / SIN_LEN ); /* checked against the real chip */
|
||||
/* we never reach zero here due to ((i*2)+1) */
|
||||
|
||||
if (m>0.0)
|
||||
o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */
|
||||
else
|
||||
o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */
|
||||
|
||||
o = o / (ENV_STEP/4);
|
||||
|
||||
n = (int)(2.0*o);
|
||||
if (n&1) /* round to nearest */
|
||||
n = (n>>1)+1;
|
||||
else
|
||||
n = n>>1;
|
||||
|
||||
/* 13-bits (8.5) value is formatted for above 'Power' table */
|
||||
sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 );
|
||||
}
|
||||
|
||||
/* build LFO PM modulation table */
|
||||
for(i = 0; i < 8; i++) /* 8 PM depths */
|
||||
{
|
||||
UINT8 fnum;
|
||||
for (fnum=0; fnum<128; fnum++) /* 7 bits meaningful of F-NUMBER */
|
||||
{
|
||||
UINT8 value;
|
||||
UINT8 step;
|
||||
UINT32 offset_depth = i;
|
||||
UINT32 offset_fnum_bit;
|
||||
UINT32 bit_tmp;
|
||||
|
||||
for (step=0; step<8; step++)
|
||||
{
|
||||
value = 0;
|
||||
for (bit_tmp=0; bit_tmp<7; bit_tmp++) /* 7 bits */
|
||||
{
|
||||
if (fnum & (1<<bit_tmp)) /* only if bit "bit_tmp" is set */
|
||||
{
|
||||
offset_fnum_bit = bit_tmp * 8;
|
||||
value += lfo_pm_output[offset_fnum_bit + offset_depth][step];
|
||||
}
|
||||
}
|
||||
/* 32 steps for LFO PM (sinus) */
|
||||
lfo_pm_table[(fnum*32*8) + (i*32) + step + 0] = value;
|
||||
lfo_pm_table[(fnum*32*8) + (i*32) +(step^7)+ 8] = value;
|
||||
lfo_pm_table[(fnum*32*8) + (i*32) + step +16] = -value;
|
||||
lfo_pm_table[(fnum*32*8) + (i*32) +(step^7)+24] = -value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SAVE_SAMPLE
|
||||
sample[0]=fopen("sampsum.pcm","wb");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* BUILD_OPN */
|
||||
|
||||
#if (BUILD_YM2612||BUILD_YM3438)
|
||||
/*******************************************************************************/
|
||||
/* YM2612 local section */
|
||||
/*******************************************************************************/
|
||||
/* here's the virtual YM2612 */
|
||||
typedef struct
|
||||
{
|
||||
UINT8 REGS[512]; /* registers */
|
||||
FM_OPN OPN; /* OPN state */
|
||||
FM_CH CH[6]; /* channel state */
|
||||
UINT8 addr_A1; /* address line A1 */
|
||||
|
||||
/* dac output (YM2612) */
|
||||
int dacen;
|
||||
INT32 dacout;
|
||||
} YM2612;
|
||||
|
||||
static int dacen;
|
||||
|
||||
/* Generate samples for one of the YM2612s */
|
||||
@ -2261,6 +2175,7 @@ void ym2612_update_one(void *chip, FMSAMPLE **buffer, int length)
|
||||
FMSAMPLE *bufL,*bufR;
|
||||
INT32 dacout = F2612->dacout;
|
||||
FM_CH *cch[6];
|
||||
int lt,rt;
|
||||
|
||||
/* set bufer */
|
||||
bufL = buffer[0];
|
||||
@ -2313,15 +2228,15 @@ void ym2612_update_one(void *chip, FMSAMPLE **buffer, int length)
|
||||
update_ssg_eg_channel(&cch[5]->SLOT[SLOT1]);
|
||||
|
||||
/* calculate FM */
|
||||
chan_calc(OPN, cch[0], 0 );
|
||||
chan_calc(OPN, cch[1], 1 );
|
||||
chan_calc(OPN, cch[2], 2 );
|
||||
chan_calc(OPN, cch[3], 3 );
|
||||
chan_calc(OPN, cch[4], 4 );
|
||||
chan_calc(F2612, OPN, cch[0]);
|
||||
chan_calc(F2612, OPN, cch[1]);
|
||||
chan_calc(F2612, OPN, cch[2]);
|
||||
chan_calc(F2612, OPN, cch[3]);
|
||||
chan_calc(F2612, OPN, cch[4]);
|
||||
if( dacen )
|
||||
*cch[5]->connect4 += dacout;
|
||||
else
|
||||
chan_calc(OPN, cch[5], 5 );
|
||||
chan_calc(F2612, OPN, cch[5]);
|
||||
|
||||
/* advance LFO */
|
||||
advance_lfo(OPN);
|
||||
@ -2341,9 +2256,20 @@ void ym2612_update_one(void *chip, FMSAMPLE **buffer, int length)
|
||||
advance_eg_channel(OPN, &cch[5]->SLOT[SLOT1]);
|
||||
}
|
||||
|
||||
{
|
||||
int lt,rt;
|
||||
if (out_fm[0] > 8191) out_fm[0] = 8191;
|
||||
else if (out_fm[0] < -8192) out_fm[0] = -8192;
|
||||
if (out_fm[1] > 8191) out_fm[1] = 8191;
|
||||
else if (out_fm[1] < -8192) out_fm[1] = -8192;
|
||||
if (out_fm[2] > 8191) out_fm[2] = 8191;
|
||||
else if (out_fm[2] < -8192) out_fm[2] = -8192;
|
||||
if (out_fm[3] > 8191) out_fm[3] = 8191;
|
||||
else if (out_fm[3] < -8192) out_fm[3] = -8192;
|
||||
if (out_fm[4] > 8191) out_fm[4] = 8191;
|
||||
else if (out_fm[4] < -8192) out_fm[4] = -8192;
|
||||
if (out_fm[5] > 8191) out_fm[5] = 8191;
|
||||
else if (out_fm[5] < -8192) out_fm[5] = -8192;
|
||||
|
||||
/* 6-channels mixing */
|
||||
lt = ((out_fm[0]>>0) & OPN->pan[0]);
|
||||
rt = ((out_fm[0]>>0) & OPN->pan[1]);
|
||||
lt += ((out_fm[1]>>0) & OPN->pan[2]);
|
||||
@ -2357,8 +2283,8 @@ void ym2612_update_one(void *chip, FMSAMPLE **buffer, int length)
|
||||
lt += ((out_fm[5]>>0) & OPN->pan[10]);
|
||||
rt += ((out_fm[5]>>0) & OPN->pan[11]);
|
||||
|
||||
Limit( lt, MAXOUT, MINOUT );
|
||||
Limit( rt, MAXOUT, MINOUT );
|
||||
// Limit( lt, MAXOUT, MINOUT );
|
||||
// Limit( rt, MAXOUT, MINOUT );
|
||||
|
||||
#ifdef SAVE_SAMPLE
|
||||
SAVE_ALL_CHANNELS
|
||||
@ -2367,7 +2293,6 @@ void ym2612_update_one(void *chip, FMSAMPLE **buffer, int length)
|
||||
/* buffering */
|
||||
bufL[i] = lt;
|
||||
bufR[i] = rt;
|
||||
}
|
||||
|
||||
/* CSM mode: if CSM Key ON has occured, CSM Key OFF need to be sent */
|
||||
/* only if Timer A does not overflow again (i.e CSM Key ON not set again) */
|
||||
@ -2384,8 +2309,9 @@ void ym2612_update_one(void *chip, FMSAMPLE **buffer, int length)
|
||||
FM_KEYOFF_CSM(cch[2],SLOT4);
|
||||
OPN->SL3.key_csm = 0;
|
||||
}
|
||||
INTERNAL_TIMER_B(&OPN->ST,length)
|
||||
|
||||
/* timer B control */
|
||||
INTERNAL_TIMER_B(&OPN->ST,length)
|
||||
}
|
||||
|
||||
#ifdef __STATE_H__
|
||||
@ -2442,11 +2368,7 @@ void * ym2612_init(void *param, const device_config *device, int clock, int rate
|
||||
/* allocate extend state space */
|
||||
F2612 = auto_alloc_clear(device->machine, YM2612);
|
||||
/* allocate total level table (128kb space) */
|
||||
if( !init_tables() )
|
||||
{
|
||||
auto_free( device->machine, F2612 );
|
||||
return NULL;
|
||||
}
|
||||
init_tables();
|
||||
|
||||
F2612->OPN.ST.param = param;
|
||||
F2612->OPN.type = TYPE_YM2612;
|
||||
@ -2490,20 +2412,22 @@ void ym2612_reset_chip(void *chip)
|
||||
|
||||
OPN->eg_timer = 0;
|
||||
OPN->eg_cnt = 0;
|
||||
OPN->ST.status = 0;
|
||||
OPN->ST.mode = 0;
|
||||
|
||||
OPN->lfo_timer = 0;
|
||||
OPN->lfo_cnt = 0;
|
||||
OPN->LFO_AM = 0;
|
||||
OPN->LFO_PM = 0;
|
||||
OPN->lfo_cnt = 0;
|
||||
|
||||
OPN->ST.status = 0;
|
||||
OPN->ST.mode = 0;
|
||||
|
||||
OPNWriteMode(OPN,0x27,0x30);
|
||||
OPNWriteMode(OPN,0x26,0x00);
|
||||
OPNWriteMode(OPN,0x25,0x00);
|
||||
OPNWriteMode(OPN,0x24,0x00);
|
||||
|
||||
FM_STATUS_RESET(&OPN->ST, 0xff);
|
||||
|
||||
reset_channels( &OPN->ST , &F2612->CH[0] , 6 );
|
||||
|
||||
for(i = 0xb6 ; i >= 0xb4 ; i-- )
|
||||
{
|
||||
OPNWriteReg(OPN,i ,0xc0);
|
||||
@ -2514,9 +2438,10 @@ void ym2612_reset_chip(void *chip)
|
||||
OPNWriteReg(OPN,i ,0);
|
||||
OPNWriteReg(OPN,i|0x100,0);
|
||||
}
|
||||
for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
|
||||
|
||||
/* DAC mode clear */
|
||||
F2612->dacen = 0;
|
||||
F2612->dacout = 0;
|
||||
}
|
||||
|
||||
/* YM2612 write */
|
||||
|
Loading…
Reference in New Issue
Block a user