From 4c3ddb77cdb931112fff23b540fda61760cfe47b Mon Sep 17 00:00:00 2001 From: Barry Harris <44396066+barry65536@users.noreply.github.com> Date: Sat, 4 Feb 2012 20:55:41 +0000 Subject: [PATCH] Add savestate support to fmopl.c and the YM3812, YM3526 and Y8950 interfaces --- src/burn/drv/pre90s/d_ginganin.cpp | 5 +- src/burn/snd/burn_y8950.cpp | 1 + src/burn/snd/burn_ym3526.cpp | 1 + src/burn/snd/burn_ym3812.cpp | 1 + src/burn/snd/fmopl.c | 264 +++++++++++++++++++++-------- src/burn/snd/fmopl.h | 5 + 6 files changed, 209 insertions(+), 68 deletions(-) diff --git a/src/burn/drv/pre90s/d_ginganin.cpp b/src/burn/drv/pre90s/d_ginganin.cpp index 47cef346b..04d6c347b 100644 --- a/src/burn/drv/pre90s/d_ginganin.cpp +++ b/src/burn/drv/pre90s/d_ginganin.cpp @@ -654,7 +654,7 @@ static INT32 DrvScan(INT32 nAction,INT32 *pnMin) struct BurnArea ba; if (pnMin) { - *pnMin = 0x029707; + *pnMin = 0x029722; } if (nAction & ACB_VOLATILE) { @@ -666,9 +666,10 @@ static INT32 DrvScan(INT32 nAction,INT32 *pnMin) BurnAcb(&ba); SekScan(nAction); - ZetScan(nAction); + M6809Scan(nAction); AY8910Scan(nAction, pnMin); + BurnY8950Scan(nAction, pnMin); SCAN_VAR(MC6840_idx0); SCAN_VAR(MC6840_idx1); diff --git a/src/burn/snd/burn_y8950.cpp b/src/burn/snd/burn_y8950.cpp index fe532a1dc..d48ce18c6 100644 --- a/src/burn/snd/burn_y8950.cpp +++ b/src/burn/snd/burn_y8950.cpp @@ -568,6 +568,7 @@ void BurnY8950Scan(INT32 nAction, INT32* pnMin) #endif BurnTimerScanY8950(nAction, pnMin); + FMOPLScan(FM_OPL_SAVESTATE_Y8950, 0, nAction, pnMin); if (nAction & ACB_DRIVER_DATA) { SCAN_VAR(nY8950Position); diff --git a/src/burn/snd/burn_ym3526.cpp b/src/burn/snd/burn_ym3526.cpp index d3081b371..6f748e318 100644 --- a/src/burn/snd/burn_ym3526.cpp +++ b/src/burn/snd/burn_ym3526.cpp @@ -567,6 +567,7 @@ void BurnYM3526Scan(INT32 nAction, INT32* pnMin) #endif BurnTimerScanYM3526(nAction, pnMin); + FMOPLScan(FM_OPL_SAVESTATE_YM3526, 0, nAction, pnMin); if (nAction & ACB_DRIVER_DATA) { SCAN_VAR(nYM3526Position); diff --git a/src/burn/snd/burn_ym3812.cpp b/src/burn/snd/burn_ym3812.cpp index f87818272..15c389170 100644 --- a/src/burn/snd/burn_ym3812.cpp +++ b/src/burn/snd/burn_ym3812.cpp @@ -582,6 +582,7 @@ void BurnYM3812Scan(INT32 nAction, INT32* pnMin) #endif BurnTimerScanYM3812(nAction, pnMin); + FMOPLScan(FM_OPL_SAVESTATE_YM3812, 0, nAction, pnMin); if (nAction & ACB_DRIVER_DATA) { SCAN_VAR(nYM3812Position); diff --git a/src/burn/snd/fmopl.c b/src/burn/snd/fmopl.c index ec59a8c39..1046d371d 100644 --- a/src/burn/snd/fmopl.c +++ b/src/burn/snd/fmopl.c @@ -72,6 +72,7 @@ Revision History: #include #include "driver.h" /* use M.A.M.E. */ +#include "state.h" #include "ymdeltat.h" @@ -274,6 +275,9 @@ typedef struct fm_opl_f { UINT32 fn_tab[1024]; /* fnumber->increment counter */ /* LFO */ + UINT32 LFO_AM; + INT32 LFO_PM; + UINT8 lfo_am_depth; UINT8 lfo_pm_depth_range; UINT32 lfo_am_cnt; @@ -324,6 +328,13 @@ typedef struct fm_opl_f { int rate; /* sampling rate (Hz) */ double freqbase; /* frequency base */ double TimerBase; /* Timer base time (==sampling time)*/ + + signed int phase_modulation; /* phase modulation input (SLOT 2) */ + signed int output[1]; + +#if BUILD_Y8950 + INT32 output_deltat[4]; /* for Y8950 DELTA-T, chip is mono, that 4 here is just for safety */ +#endif } FM_OPL; @@ -641,17 +652,6 @@ static int num_lock = 0; static void *cur_chip = NULL; /* current chip pointer */ static OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2; -static signed int phase_modulation; /* phase modulation input (SLOT 2) */ -static signed int output[1]; - -#if BUILD_Y8950 -static INT32 output_deltat[4]; /* for Y8950 DELTA-T, chip is mono, that 4 here is just for safety */ -#endif - -static UINT32 LFO_AM; -static INT32 LFO_PM; - - INLINE int limit( int val, int max, int min ) { if ( val > max ) @@ -718,12 +718,12 @@ INLINE void advance_lfo(FM_OPL *OPL) tmp = lfo_am_table[ OPL->lfo_am_cnt >> LFO_SH ]; if (OPL->lfo_am_depth) - LFO_AM = tmp; + OPL->LFO_AM = tmp; else - LFO_AM = tmp>>2; + OPL->LFO_AM = tmp>>2; OPL->lfo_pm_cnt += OPL->lfo_pm_inc; - LFO_PM = ((OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range; + OPL->LFO_PM = ((OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range; } /* advance to next sample */ @@ -833,7 +833,7 @@ INLINE void advance(FM_OPL *OPL) unsigned int fnum_lfo = (block_fnum&0x0380) >> 7; - signed int lfo_fn_table_index_offset = lfo_pm_table[LFO_PM + 16*fnum_lfo ]; + signed int lfo_fn_table_index_offset = lfo_pm_table[OPL->LFO_PM + 16*fnum_lfo ]; if (lfo_fn_table_index_offset) /* LFO phase modulation active */ { @@ -913,16 +913,16 @@ INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsign } -#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask)) +#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (OPL->LFO_AM & (OP)->AMmask)) /* calculate output */ -INLINE void OPL_CALC_CH( OPL_CH *CH ) +INLINE void OPL_CALC_CH( FM_OPL *OPL, OPL_CH *CH ) { OPL_SLOT *SLOT; unsigned int env; signed int out; - phase_modulation = 0; + OPL->phase_modulation = 0; /* SLOT 1 */ SLOT = &CH->SLOT[SLOT1]; @@ -942,7 +942,7 @@ INLINE void OPL_CALC_CH( OPL_CH *CH ) SLOT++; env = volume_calc(SLOT); if( env < ENV_QUIET ) - output[0] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable); + OPL->output[0] += op_calc(SLOT->Cnt, env, OPL->phase_modulation, SLOT->wavetable); } /* @@ -982,7 +982,7 @@ number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal /* calculate rhythm */ -INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) +INLINE void OPL_CALC_RH( FM_OPL *OPL, OPL_CH *CH, unsigned int noise ) { OPL_SLOT *SLOT; signed int out; @@ -996,7 +996,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) - output sample always is multiplied by 2 */ - phase_modulation = 0; + OPL->phase_modulation = 0; /* SLOT 1 */ SLOT = &CH[6].SLOT[SLOT1]; env = volume_calc(SLOT); @@ -1005,7 +1005,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) SLOT->op1_out[0] = SLOT->op1_out[1]; if (!SLOT->CON) - phase_modulation = SLOT->op1_out[0]; + OPL->phase_modulation = SLOT->op1_out[0]; /* else ignore output of operator 1 */ SLOT->op1_out[1] = 0; @@ -1020,7 +1020,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) SLOT++; env = volume_calc(SLOT); if( env < ENV_QUIET ) - output[0] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable) * 2; + OPL->output[0] += op_calc(SLOT->Cnt, env, OPL->phase_modulation, SLOT->wavetable) * 2; /* Phase generation is based on: */ @@ -1088,7 +1088,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) phase = 0xd0>>2; } - output[0] += op_calc(phase<wavetable) * 2; + OPL->output[0] += op_calc(phase<wavetable) * 2; } /* Snare Drum (verified on real YM3812) */ @@ -1109,13 +1109,13 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) if (noise) phase ^= 0x100; - output[0] += op_calc(phase<wavetable) * 2; + OPL->output[0] += op_calc(phase<wavetable) * 2; } /* Tom Tom (verified on real YM3812) */ env = volume_calc(SLOT8_1); if( env < ENV_QUIET ) - output[0] += op_calc(SLOT8_1->Cnt, env, 0, SLOT8_1->wavetable) * 2; + OPL->output[0] += op_calc(SLOT8_1->Cnt, env, 0, SLOT8_1->wavetable) * 2; /* Top Cymbal (verified on real YM3812) */ env = volume_calc(SLOT8_2); @@ -1142,7 +1142,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) if (res2) phase = 0x300; - output[0] += op_calc(phase<wavetable) * 2; + OPL->output[0] += op_calc(phase<wavetable) * 2; } } @@ -1710,7 +1710,7 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) CH = &OPL->P_CH[r&0x0f]; CH->SLOT[SLOT1].FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0; CH->SLOT[SLOT1].CON = v&1; - CH->SLOT[SLOT1].connect1 = CH->SLOT[SLOT1].CON ? &output[0] : &phase_modulation; + CH->SLOT[SLOT1].connect1 = CH->SLOT[SLOT1].CON ? &OPL->output[0] : &OPL->phase_modulation; break; case 0xe0: /* waveform select */ /* simply ignore write to the waveform select register if selecting not enabled in test register */ @@ -1817,7 +1817,7 @@ static void OPLResetChip(FM_OPL *OPL) YM_DELTAT *DELTAT = OPL->deltat; DELTAT->freqbase = OPL->freqbase; - DELTAT->output_pointer = &output_deltat[0]; + DELTAT->output_pointer = &OPL->output_deltat[0]; DELTAT->portshift = 5; DELTAT->output_range = 1<<23; YM_DELTAT_ADPCM_Reset(DELTAT,0,YM_DELTAT_EMULATION_MODE_NORMAL); @@ -2125,30 +2125,30 @@ void YM3812UpdateOne(int which, INT16 *buffer, int length) { int lt; - output[0] = 0; + OPL->output[0] = 0; advance_lfo(OPL); /* FM part */ - OPL_CALC_CH(&OPL->P_CH[0]); - OPL_CALC_CH(&OPL->P_CH[1]); - OPL_CALC_CH(&OPL->P_CH[2]); - OPL_CALC_CH(&OPL->P_CH[3]); - OPL_CALC_CH(&OPL->P_CH[4]); - OPL_CALC_CH(&OPL->P_CH[5]); + OPL_CALC_CH(OPL, &OPL->P_CH[0]); + OPL_CALC_CH(OPL, &OPL->P_CH[1]); + OPL_CALC_CH(OPL, &OPL->P_CH[2]); + OPL_CALC_CH(OPL, &OPL->P_CH[3]); + OPL_CALC_CH(OPL, &OPL->P_CH[4]); + OPL_CALC_CH(OPL, &OPL->P_CH[5]); if(!rhythm) { - OPL_CALC_CH(&OPL->P_CH[6]); - OPL_CALC_CH(&OPL->P_CH[7]); - OPL_CALC_CH(&OPL->P_CH[8]); + OPL_CALC_CH(OPL, &OPL->P_CH[6]); + OPL_CALC_CH(OPL, &OPL->P_CH[7]); + OPL_CALC_CH(OPL, &OPL->P_CH[8]); } else /* Rhythm part */ { - OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); } - lt = output[0]; + lt = OPL->output[0]; lt >>= FINAL_SH; @@ -2276,30 +2276,30 @@ void YM3526UpdateOne(int which, INT16 *buffer, int length) { int lt; - output[0] = 0; + OPL->output[0] = 0; advance_lfo(OPL); /* FM part */ - OPL_CALC_CH(&OPL->P_CH[0]); - OPL_CALC_CH(&OPL->P_CH[1]); - OPL_CALC_CH(&OPL->P_CH[2]); - OPL_CALC_CH(&OPL->P_CH[3]); - OPL_CALC_CH(&OPL->P_CH[4]); - OPL_CALC_CH(&OPL->P_CH[5]); + OPL_CALC_CH(OPL, &OPL->P_CH[0]); + OPL_CALC_CH(OPL, &OPL->P_CH[1]); + OPL_CALC_CH(OPL, &OPL->P_CH[2]); + OPL_CALC_CH(OPL, &OPL->P_CH[3]); + OPL_CALC_CH(OPL, &OPL->P_CH[4]); + OPL_CALC_CH(OPL, &OPL->P_CH[5]); if(!rhythm) { - OPL_CALC_CH(&OPL->P_CH[6]); - OPL_CALC_CH(&OPL->P_CH[7]); - OPL_CALC_CH(&OPL->P_CH[8]); + OPL_CALC_CH(OPL, &OPL->P_CH[6]); + OPL_CALC_CH(OPL, &OPL->P_CH[7]); + OPL_CALC_CH(OPL, &OPL->P_CH[8]); } else /* Rhythm part */ { - OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); } - lt = output[0]; + lt = OPL->output[0]; lt >>= FINAL_SH; @@ -2452,8 +2452,8 @@ void Y8950UpdateOne(int which, INT16 *buffer, int length) { int lt; - output[0] = 0; - output_deltat[0] = 0; + OPL->output[0] = 0; + OPL->output_deltat[0] = 0; advance_lfo(OPL); @@ -2462,25 +2462,25 @@ void Y8950UpdateOne(int which, INT16 *buffer, int length) YM_DELTAT_ADPCM_CALC(DELTAT); /* FM part */ - OPL_CALC_CH(&OPL->P_CH[0]); - OPL_CALC_CH(&OPL->P_CH[1]); - OPL_CALC_CH(&OPL->P_CH[2]); - OPL_CALC_CH(&OPL->P_CH[3]); - OPL_CALC_CH(&OPL->P_CH[4]); - OPL_CALC_CH(&OPL->P_CH[5]); + OPL_CALC_CH(OPL, &OPL->P_CH[0]); + OPL_CALC_CH(OPL, &OPL->P_CH[1]); + OPL_CALC_CH(OPL, &OPL->P_CH[2]); + OPL_CALC_CH(OPL, &OPL->P_CH[3]); + OPL_CALC_CH(OPL, &OPL->P_CH[4]); + OPL_CALC_CH(OPL, &OPL->P_CH[5]); if(!rhythm) { - OPL_CALC_CH(&OPL->P_CH[6]); - OPL_CALC_CH(&OPL->P_CH[7]); - OPL_CALC_CH(&OPL->P_CH[8]); + OPL_CALC_CH(OPL, &OPL->P_CH[6]); + OPL_CALC_CH(OPL, &OPL->P_CH[7]); + OPL_CALC_CH(OPL, &OPL->P_CH[8]); } else /* Rhythm part */ { - OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); } - lt = output[0] + (output_deltat[0]>>11); + lt = OPL->output[0] + (OPL->output_deltat[0]>>11); lt >>= FINAL_SH; @@ -2520,3 +2520,135 @@ void Y8950SetKeyboardHandler(int which,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_P #endif +void FMOPLScan(INT32 nType, INT32 which, INT32 nAction, INT32 *pnMin) +{ + FM_OPL *OPL = OPL_YM3812[which]; + + if (nType == FM_OPL_SAVESTATE_YM3526) { + OPL = OPL_YM3526[which]; + } + + if (nType == FM_OPL_SAVESTATE_Y8950) { + OPL = OPL_Y8950[which]; + } + + if (nAction & ACB_DRIVER_DATA) { + for (INT32 ch = 0; ch < 9; ch++) { + OPL_CH *CH = &OPL->P_CH[ch]; + + SCAN_VAR(CH->block_fnum); + SCAN_VAR(CH->kcode); + + for (INT32 slot = 0; slot < 2; slot++) { + OPL_SLOT *SLOT = &CH->SLOT[slot]; + + SCAN_VAR(SLOT->ar); + SCAN_VAR(SLOT->dr); + SCAN_VAR(SLOT->rr); + SCAN_VAR(SLOT->KSR); + SCAN_VAR(SLOT->ksl); + SCAN_VAR(SLOT->mul); + + SCAN_VAR(SLOT->Cnt); + SCAN_VAR(SLOT->FB); + SCAN_VAR(SLOT->op1_out); + SCAN_VAR(SLOT->CON); + + SCAN_VAR(SLOT->eg_type); + SCAN_VAR(SLOT->state); + SCAN_VAR(SLOT->TL); + SCAN_VAR(SLOT->volume); + SCAN_VAR(SLOT->sl); + SCAN_VAR(SLOT->key); + + SCAN_VAR(SLOT->AMmask); + SCAN_VAR(SLOT->vib); + + SCAN_VAR(SLOT->wavetable); + } + } + + SCAN_VAR(OPL->eg_cnt); + SCAN_VAR(OPL->eg_timer); + + SCAN_VAR(OPL->rhythm); + + SCAN_VAR(OPL->lfo_am_depth); + SCAN_VAR(OPL->lfo_pm_depth_range); + SCAN_VAR(OPL->lfo_am_cnt); + SCAN_VAR(OPL->lfo_pm_cnt); + + SCAN_VAR(OPL->noise_rng); + SCAN_VAR(OPL->noise_p); + + if (OPL->type & OPL_TYPE_WAVESEL) { + SCAN_VAR(OPL->wavesel); + } + + SCAN_VAR(OPL->T); + SCAN_VAR(OPL->st); + +#if BUILD_Y8950 + if ((OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat)) { + SCAN_VAR(OPL->deltat->portstate); + SCAN_VAR(OPL->deltat->now_addr); + SCAN_VAR(OPL->deltat->now_step); + SCAN_VAR(OPL->deltat->acc); + SCAN_VAR(OPL->deltat->prev_acc); + SCAN_VAR(OPL->deltat->adpcmd); + SCAN_VAR(OPL->deltat->adpcml); + } + + if (OPL->type & OPL_TYPE_IO) { + SCAN_VAR(OPL->portDirection); + SCAN_VAR(OPL->portLatch); + } +#endif + + SCAN_VAR(OPL->address); + SCAN_VAR(OPL->status); + SCAN_VAR(OPL->statusmask); + SCAN_VAR(OPL->mode); + + if (nAction & ACB_WRITE) { + for (INT32 ch = 0; ch < 9; ch++) { + OPL_CH *CH = &OPL->P_CH[ch]; + + UINT32 block_fnum = CH->block_fnum; + CH->ksl_base = ksl_tab[block_fnum >> 6]; + CH->fc = OPL->fn_tab[block_fnum & 0x03ff] >> (7 - (block_fnum >> 10)); + + for (INT32 slot = 0; slot < 2; slot++) { + OPL_SLOT *SLOT = &CH->SLOT[slot]; + + SLOT->ksr = CH->kcode >> SLOT->KSR; + + if ((SLOT->ar + SLOT->ksr) < 16 + 62) { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } else { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; + + SLOT->Incr = CH->fc * SLOT->mul; + + SLOT->TLL = SLOT->TL + (CH->ksl_base >> SLOT->ksl); + + SLOT->connect1 = SLOT->CON ? &OPL->output[0] : &OPL->phase_modulation; + } + } +#if BUILD_Y8950 + if ((OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat)) { + // We really should call the postlod function for the YM_DELTAT, but it's hard without registers + // (see the way the YM2610 does it) + //YM_DELTAT_postload(OPL->deltat, REGS); + } +#endif + } + } +} diff --git a/src/burn/snd/fmopl.h b/src/burn/snd/fmopl.h index 242a32d29..2d7d95604 100644 --- a/src/burn/snd/fmopl.h +++ b/src/burn/snd/fmopl.h @@ -105,5 +105,10 @@ void Y8950SetUpdateHandler (int which, OPL_UPDATEHANDLER UpdateHandler, int para #endif +#define FM_OPL_SAVESTATE_YM3812 1 +#define FM_OPL_SAVESTATE_YM3526 2 +#define FM_OPL_SAVESTATE_Y8950 3 + +void FMOPLScan(INT32 nType, INT32 which, INT32 nAction, INT32 *pnMin); #endif /* __FMOPL_H_ */