Save state support for 68K, Z80, sound board, DSB1, and MPEG playback.

This commit is contained in:
Bart Trzynadlowski 2011-08-09 18:36:29 +00:00
parent 52cd9d834b
commit 06f6bf093b
11 changed files with 441 additions and 13 deletions

View file

@ -25,6 +25,12 @@
* 68K CPU interface. This is presently just a wrapper for the Musashi 68K core
* and therefore, only a single CPU is supported. In the future, we may want to
* add in another 68K core (eg., Turbo68K, A68K, or a recompiler).
*
* To-Do List
* ----------
* - Registers may not completely describe the 68K state. Musashi also has
* additional CPU state information in the context that its MAME interface
* accesses (interrupts pending, halted status, etc.)
*/
#include "Supermodel.h"
@ -97,6 +103,102 @@ UINT32 M68KGetPC(void)
return m68k_get_reg(NULL, M68K_REG_PC);
}
void M68KSaveState(CBlockFile *StateFile, const char *name)
{
StateFile->NewBlock(name, __FILE__);
/*
* Rather than writing the context directly to the save state, each
* register is copied into an array first to ensure the same result across
* different compilers (in case the struct is ordered differently). This
* also prevents us from inadvertently modifying the callback pointers.
*
* Note: Some of these are undoubtedly 68010 or 68020 registers and not
* really necessary. But if the layout is changed now, the save state
* version has to be changed, so don't do it!
*/
UINT32 data[31];
data[0] = m68k_get_reg(NULL, M68K_REG_D0);
data[1] = m68k_get_reg(NULL, M68K_REG_D1);
data[2] = m68k_get_reg(NULL, M68K_REG_D2);
data[3] = m68k_get_reg(NULL, M68K_REG_D3);
data[4] = m68k_get_reg(NULL, M68K_REG_D4);
data[5] = m68k_get_reg(NULL, M68K_REG_D5);
data[6] = m68k_get_reg(NULL, M68K_REG_D6);
data[7] = m68k_get_reg(NULL, M68K_REG_D7);
data[8] = m68k_get_reg(NULL, M68K_REG_A0);
data[9] = m68k_get_reg(NULL, M68K_REG_A1);
data[10] = m68k_get_reg(NULL, M68K_REG_A2);
data[11] = m68k_get_reg(NULL, M68K_REG_A3);
data[12] = m68k_get_reg(NULL, M68K_REG_A4);
data[13] = m68k_get_reg(NULL, M68K_REG_A5);
data[14] = m68k_get_reg(NULL, M68K_REG_A6);
data[15] = m68k_get_reg(NULL, M68K_REG_A7);
data[16] = m68k_get_reg(NULL, M68K_REG_PC);
data[17] = m68k_get_reg(NULL, M68K_REG_SR);
data[18] = m68k_get_reg(NULL, M68K_REG_SP);
data[19] = m68k_get_reg(NULL, M68K_REG_USP);
data[20] = m68k_get_reg(NULL, M68K_REG_ISP);
data[21] = m68k_get_reg(NULL, M68K_REG_MSP);
data[22] = m68k_get_reg(NULL, M68K_REG_SFC);
data[23] = m68k_get_reg(NULL, M68K_REG_DFC);
data[24] = m68k_get_reg(NULL, M68K_REG_VBR);
data[25] = m68k_get_reg(NULL, M68K_REG_CACR);
data[26] = m68k_get_reg(NULL, M68K_REG_CAAR);
data[27] = m68k_get_reg(NULL, M68K_REG_PREF_ADDR);
data[28] = m68k_get_reg(NULL, M68K_REG_PREF_DATA);
data[29] = m68k_get_reg(NULL, M68K_REG_PPC);
data[30] = m68k_get_reg(NULL, M68K_REG_IR);
StateFile->Write(data, sizeof(data));
}
void M68KLoadState(CBlockFile *StateFile, const char *name)
{
if (OKAY != StateFile->FindBlock(name))
{
ErrorLog("Unable to load 68K state. Save state file is corrupted.");
return;
}
UINT32 data[31];
StateFile->Read(data, sizeof(data));
m68k_set_reg(M68K_REG_D0, data[0]);
m68k_set_reg(M68K_REG_D1, data[1]);
m68k_set_reg(M68K_REG_D2, data[2]);
m68k_set_reg(M68K_REG_D3, data[3]);
m68k_set_reg(M68K_REG_D4, data[4]);
m68k_set_reg(M68K_REG_D5, data[5]);
m68k_set_reg(M68K_REG_D6, data[6]);
m68k_set_reg(M68K_REG_D7, data[7]);
m68k_set_reg(M68K_REG_A0, data[8]);
m68k_set_reg(M68K_REG_A1, data[9]);
m68k_set_reg(M68K_REG_A2, data[10]);
m68k_set_reg(M68K_REG_A3, data[11]);
m68k_set_reg(M68K_REG_A4, data[12]);
m68k_set_reg(M68K_REG_A5, data[13]);
m68k_set_reg(M68K_REG_A6, data[14]);
m68k_set_reg(M68K_REG_A7, data[15]);
m68k_set_reg(M68K_REG_PC, data[16]);
m68k_set_reg(M68K_REG_SR, data[17]);
m68k_set_reg(M68K_REG_SP, data[18]);
m68k_set_reg(M68K_REG_USP, data[19]);
m68k_set_reg(M68K_REG_ISP, data[20]);
m68k_set_reg(M68K_REG_MSP, data[21]);
m68k_set_reg(M68K_REG_SFC, data[22]);
m68k_set_reg(M68K_REG_DFC, data[23]);
m68k_set_reg(M68K_REG_VBR, data[24]);
m68k_set_reg(M68K_REG_CACR, data[25]);
m68k_set_reg(M68K_REG_CAAR, data[26]);
m68k_set_reg(M68K_REG_PREF_ADDR, data[27]);
m68k_set_reg(M68K_REG_PREF_DATA, data[28]);
m68k_set_reg(M68K_REG_PPC, data[29]);
m68k_set_reg(M68K_REG_IR, data[30]);
}
// Emulation functions
void M68KSetIRQ(int irqLevel)

View file

@ -122,6 +122,29 @@ extern UINT32 M68KGetDRegister(int reg);
*/
extern UINT32 M68KGetPC(void);
/*
* M68KSaveState(StateFile, name):
*
* Saves the CPU state to the block file.
*
* Parameters:
* StateFile Block file.
* name Name of block to create (e.g. "Main 68K"), to facilitate
* multiple 68K states in the same file.
*/
extern void M68KSaveState(CBlockFile *StateFile, const char *name);
/*
* M68KLoadState(StateFile, name):
*
* Loads the CPU state.
*
* Parameters:
* StateFile Block file.
* name Name of block to load.
*/
extern void M68KLoadState(CBlockFile *StateFile, const char *name);
/*
* M68KSetIRQ(irqLevel):
*

View file

@ -30,7 +30,8 @@
*/
#include <cstdio> // for NULL
#include "Z80.h"
#include "Z80.h" // must include this first to define CZ80
#include "Supermodel.h"
/******************************************************************************
@ -3766,6 +3767,60 @@ void CZ80::Reset(void)
nmiTrigger = FALSE;
}
void CZ80::SaveState(CBlockFile *StateFile, const char *name)
{
StateFile->NewBlock(name, __FILE__);
for (int i = 0; i < 2; i++)
{
StateFile->Write(&regs[i].bc, sizeof(regs[i].bc));
StateFile->Write(&regs[i].de, sizeof(regs[i].de));
StateFile->Write(&regs[i].hl, sizeof(regs[i].hl));
}
StateFile->Write(af, sizeof(af));
StateFile->Write(&ir, sizeof(ir));
StateFile->Write(&ix, sizeof(ix));
StateFile->Write(&iy, sizeof(iy));
StateFile->Write(&sp, sizeof(sp));
StateFile->Write(&pc, sizeof(pc));
StateFile->Write(&iff, sizeof(iff));
StateFile->Write(&im, sizeof(im));
StateFile->Write(&regs_sel, sizeof(regs_sel));
StateFile->Write(&af_sel, sizeof(af_sel));
StateFile->Write(&nmiTrigger, sizeof(nmiTrigger));
StateFile->Write(&intLine, sizeof(intLine));
}
void CZ80::LoadState(CBlockFile *StateFile, const char *name)
{
if (OKAY != StateFile->FindBlock(name))
{
ErrorLog("Unable to load Z80 state. Save state file is corrupted.");
return;
}
for (int i = 0; i < 2; i++)
{
StateFile->Read(&regs[i].bc, sizeof(regs[i].bc));
StateFile->Read(&regs[i].de, sizeof(regs[i].de));
StateFile->Read(&regs[i].hl, sizeof(regs[i].hl));
}
StateFile->Read(af, sizeof(af));
StateFile->Read(&ir, sizeof(ir));
StateFile->Read(&ix, sizeof(ix));
StateFile->Read(&iy, sizeof(iy));
StateFile->Read(&sp, sizeof(sp));
StateFile->Read(&pc, sizeof(pc));
StateFile->Read(&iff, sizeof(iff));
StateFile->Read(&im, sizeof(im));
StateFile->Read(&regs_sel, sizeof(regs_sel));
StateFile->Read(&af_sel, sizeof(af_sel));
StateFile->Read(&nmiTrigger, sizeof(nmiTrigger));
StateFile->Read(&intLine, sizeof(intLine));
}
void CZ80::Init(CBus *BusPtr, int (*INTF)(CZ80 *Z80))
{
Bus = BusPtr;

View file

@ -45,6 +45,7 @@
#include "Types.h"
#include "CPU/Bus.h"
#include "BlockFile.h"
/*
* Special Return Codes for Interrupt Callbacks
@ -115,6 +116,29 @@ public:
*/
void Reset(void);
/*
* SaveState(StateFile, name):
*
* Saves the CPU state to the block file.
*
* Parameters:
* StateFile Block file.
* name Name of block to create (e.g. "Main Z80"), to facilitate
* multiple Z80 states in the same file.
*/
void SaveState(CBlockFile *StateFile, const char *name);
/*
* LoadState(StateFile, name):
*
* Loads the CPU state.
*
* Parameters:
* StateFile Block file.
* name Name of block to load.
*/
void LoadState(CBlockFile *StateFile, const char *name);
/*
* Init(BusPtr, INTF):
*

View file

@ -222,7 +222,9 @@ static CInputs *CreateInputs(CInputSystem *InputSystem, BOOL configure)
/******************************************************************************
Save States and NVRAM
Save states and NVRAM use the same basic format.
Save states and NVRAM use the same basic format. When anything changes that
breaks compatibility with previous versions of Supermodel, the save state
and NVRAM version numbers must be incremented as needed.
Header block name: "Supermodel Save State" or "Supermodel NVRAM State"
Data: Save state file version (4-byte integer), ROM set ID (up to 9 bytes,
@ -231,7 +233,8 @@ static CInputs *CreateInputs(CInputSystem *InputSystem, BOOL configure)
Different subsystems output their own blocks.
******************************************************************************/
#define STATE_FILE_VERSION 0 // save state file version
#define STATE_FILE_VERSION 1 // save state file version
#define NVRAM_FILE_VERSION 0 // NVRAM file version
static unsigned saveSlot = 0; // save state slot #
@ -284,7 +287,7 @@ static void LoadState(CModel3 *Model3)
SaveState.Read(&fileVersion, sizeof(fileVersion));
if (fileVersion != STATE_FILE_VERSION)
{
ErrorLog("Format of %s is incompatible with this version of Supermodel.", filePath);
ErrorLog("%s is incompatible with this version of Supermodel.", filePath);
return;
}
@ -299,7 +302,7 @@ static void SaveNVRAM(CModel3 *Model3)
{
CBlockFile NVRAM;
char filePath[24];
int fileVersion = STATE_FILE_VERSION;
int fileVersion = NVRAM_FILE_VERSION;
sprintf(filePath, "NVRAM/%s.nv", Model3->GetGameInfo()->id);
if (OKAY != NVRAM.Create(filePath, "Supermodel NVRAM State", "Supermodel Version " SUPERMODEL_VERSION))
@ -341,9 +344,9 @@ static void LoadNVRAM(CModel3 *Model3)
}
NVRAM.Read(&fileVersion, sizeof(fileVersion));
if (fileVersion != STATE_FILE_VERSION)
if (fileVersion != NVRAM_FILE_VERSION)
{
ErrorLog("Format of %s is incompatible with this version of Supermodel.", filePath);
ErrorLog("%s is incompatible with this version of Supermodel.", filePath);
return;
}

View file

@ -39,13 +39,32 @@
These functions are located in audio.cpp and getbits.cpp.
******************************************************************************/
/*
* MPEG_IsPlaying(void):
*
* Returns:
* TRUE if an MPEG stream is currently playing, otherwise FALSE.
*/
extern BOOL MPEG_IsPlaying(void);
/*
* MPEG_GetProgress(void):
*
* Returns:
* The current byte offset within the MPEG stream.
* The current byte offset within the MPEG stream, relative to the start.
*/
extern int MPEG_GetProgress(void);
extern int MPEG_GetProgress(void);
/*
* MPEG_SetOffset(pos):
*
* Sets the playback position within an MPEG stream.
*
* Parameters:
* pos Byte offset relative to the beginning of the current MPEG
* stream.
*/
extern void MPEG_SetOffset(int pos);
/*
* MPEG_SetLoop(loop, loopend):
@ -54,7 +73,7 @@ extern int MPEG_GetProgress(void);
*
* Parameters:
* loop Start address.
* loopend End address.
* loopend End offset.
*/
extern void MPEG_SetLoop(const char *loop, int loopend);
@ -77,7 +96,8 @@ extern void MPEG_Decode(INT16 **outputs, int length);
* MPEG_PlayMemory(sa, length):
*
* Specifies the memory buffer to decode from. This initializes the playback
* process and will decode the first MPEG frame internally.
* process and will decode the first MPEG frame internally. The loop start
* position is cleared (set looping after this call).
*
* Parameters:
* sa Start address of MPEG stream.

View file

@ -370,6 +370,11 @@ void MPEG_StopPlaying(void)
}
}
BOOL MPEG_IsPlaying(void)
{
return playing ? TRUE : FALSE;
}
BOOL MPEG_Init(void)
{
if (!decoder_init)

View file

@ -27,6 +27,11 @@ int MPEG_GetProgress(void)
return offset;
}
void MPEG_SetOffset(int pos)
{
offset = pos;
}
void m1setfile(const char *mstart, int mend)
{
fstart = mstart;

View file

@ -22,6 +22,9 @@
/*
* SCSP.cpp
*
* WARNING: Here be dragons! Tread carefully. Enabling/disabling things may
* break save state support.
*
* SCSP (Sega Custom Sound Processor) emulation. This code was generously
* donated by ElSemi. Interfaces directly to the 68K processor through
* callbacks. Some minor interface changes were made (external global variables
@ -148,7 +151,6 @@ static int RPANTABLE[0x10000];
static int TimPris[3];
static int TimCnt[3];
static DWORD OnIRQ=0;
#define SHIFT 12
#define FIX(v) ((DWORD) ((float) (1<<SHIFT)*(v)))
@ -2012,9 +2014,194 @@ unsigned int SCSP_Slave_r32(unsigned int addr)
/******************************************************************************
Extra Supermodel Interface Functions
Supermodel Interface Functions
******************************************************************************/
void SCSP_SaveState(CBlockFile *StateFile)
{
StateFile->NewBlock("SCSP x 2", __FILE__);
/*
* Save global variables.
*
* Difficult to say exactly what is necessary given that many things are
* commented out and should not be enabled but I try to save as much as
* possible.
*
* Things not saved:
*
* - Reverb buffers and pointers
* - FNS table (populated by SCSP_Init() and only read)
* - RB_VOLUME stuff
* - ARTABLE, DRTABLE
* - RBUFDST
*/
StateFile->Write(&IrqTimA, sizeof(IrqTimA));
StateFile->Write(&IrqTimBC, sizeof(IrqTimBC));
StateFile->Write(&IrqMidi, sizeof(IrqMidi));
StateFile->Write(MidiOutStack, sizeof(MidiOutStack));
StateFile->Write(&MidiOutW, sizeof(MidiOutW));
StateFile->Write(&MidiOutR, sizeof(MidiOutR));
StateFile->Write(MidiStack, sizeof(MidiStack));
StateFile->Write(&MidiOutFill, sizeof(MidiOutFill));
StateFile->Write(&MidiInFill, sizeof(MidiInFill));
StateFile->Write(&MidiW, sizeof(MidiW));
StateFile->Write(&MidiR, sizeof(MidiR));
StateFile->Write(TimPris, sizeof(TimPris));
StateFile->Write(TimCnt, sizeof(TimCnt));
// Save both SCSP states
for (int i = 0; i < 2; i++)
{
StateFile->Write(SCSPs[i].datab, sizeof(SCSPs[i].datab));
StateFile->Write(&(SCSPs[i].BUFPTR), sizeof(SCSPs[i].BUFPTR));
StateFile->Write(&(SCSPs[i].Master), sizeof(SCSPs[i].Master));
// Save each slot
for (int j = 0; j < 32; j++)
{
UINT32 baseOffset;
UINT8 egState;
StateFile->Write(SCSPs[i].Slots[j].datab, sizeof(SCSPs[i].Slots[j].datab));
StateFile->Write(&(SCSPs[i].Slots[j].active), sizeof(SCSPs[i].Slots[j].active));
baseOffset = (UINT32) (SCSPs[i].Slots[j].base - SCSPs[i].SCSPRAM);
StateFile->Write(&baseOffset, sizeof(baseOffset));
StateFile->Write(&(SCSPs[i].Slots[j].cur_addr), sizeof(SCSPs[i].Slots[j].cur_addr));
StateFile->Write(&(SCSPs[i].Slots[j].step), sizeof(SCSPs[i].Slots[j].step));
StateFile->Write(&(SCSPs[i].Slots[j].Back), sizeof(SCSPs[i].Slots[j].Back));
StateFile->Write(&(SCSPs[i].Slots[j].slot), sizeof(SCSPs[i].Slots[j].slot));
StateFile->Write(&(SCSPs[i].Slots[j].Prev), sizeof(SCSPs[i].Slots[j].Prev));
// EG
StateFile->Write(&(SCSPs[i].Slots[j].EG.volume), sizeof(SCSPs[i].Slots[j].EG.volume));
egState = SCSPs[i].Slots[j].EG.state;
StateFile->Write(&egState, sizeof(egState));
StateFile->Write(&(SCSPs[i].Slots[j].EG.step), sizeof(SCSPs[i].Slots[j].EG.step));
StateFile->Write(&(SCSPs[i].Slots[j].EG.AR), sizeof(SCSPs[i].Slots[j].EG.AR));
StateFile->Write(&(SCSPs[i].Slots[j].EG.D1R), sizeof(SCSPs[i].Slots[j].EG.D1R));
StateFile->Write(&(SCSPs[i].Slots[j].EG.D2R), sizeof(SCSPs[i].Slots[j].EG.D2R));
StateFile->Write(&(SCSPs[i].Slots[j].EG.RR), sizeof(SCSPs[i].Slots[j].EG.RR));
StateFile->Write(&(SCSPs[i].Slots[j].EG.DL), sizeof(SCSPs[i].Slots[j].EG.DL));
StateFile->Write(&(SCSPs[i].Slots[j].EG.EGHOLD), sizeof(SCSPs[i].Slots[j].EG.EGHOLD));
StateFile->Write(&(SCSPs[i].Slots[j].EG.LPLINK), sizeof(SCSPs[i].Slots[j].EG.LPLINK));
// PLFO
StateFile->Write(&(SCSPs[i].Slots[j].PLFO.phase), sizeof(SCSPs[i].Slots[j].PLFO.phase));
StateFile->Write(&(SCSPs[i].Slots[j].PLFO.phase_step), sizeof(SCSPs[i].Slots[j].PLFO.phase_step));
// ALFO
StateFile->Write(&(SCSPs[i].Slots[j].ALFO.phase), sizeof(SCSPs[i].Slots[j].ALFO.phase));
StateFile->Write(&(SCSPs[i].Slots[j].ALFO.phase_step), sizeof(SCSPs[i].Slots[j].ALFO.phase_step));
//when loading, make sure to compute lfo
}
// DSP
StateFile->Write(&(SCSPs[i].DSP.RBP), sizeof(SCSPs[i].DSP.RBP));
StateFile->Write(&(SCSPs[i].DSP.RBL), sizeof(SCSPs[i].DSP.RBL));
StateFile->Write(SCSPs[i].DSP.COEF, sizeof(SCSPs[i].DSP.COEF));
StateFile->Write(SCSPs[i].DSP.MADRS, sizeof(SCSPs[i].DSP.MADRS));
StateFile->Write(SCSPs[i].DSP.MPRO, sizeof(SCSPs[i].DSP.MPRO));
StateFile->Write(SCSPs[i].DSP.TEMP, sizeof(SCSPs[i].DSP.TEMP));
StateFile->Write(SCSPs[i].DSP.MEMS, sizeof(SCSPs[i].DSP.MEMS));
StateFile->Write(&(SCSPs[i].DSP.DEC), sizeof(SCSPs[i].DSP.DEC));
StateFile->Write(SCSPs[i].DSP.MIXS, sizeof(SCSPs[i].DSP.MIXS));
StateFile->Write(SCSPs[i].DSP.EXTS, sizeof(SCSPs[i].DSP.EXTS));
StateFile->Write(SCSPs[i].DSP.EFREG, sizeof(SCSPs[i].DSP.EFREG));
StateFile->Write(&(SCSPs[i].DSP.Stopped), sizeof(SCSPs[i].DSP.Stopped));
StateFile->Write(&(SCSPs[i].DSP.LastStep), sizeof(SCSPs[i].DSP.LastStep));
}
}
void SCSP_LoadState(CBlockFile *StateFile)
{
if (OKAY != StateFile->FindBlock("SCSP x 2"))
{
ErrorLog("Unable to load SCSP state. Save state file is corrupted.");
return;
}
// Load global variables
StateFile->Read(&IrqTimA, sizeof(IrqTimA));
StateFile->Read(&IrqTimBC, sizeof(IrqTimBC));
StateFile->Read(&IrqMidi, sizeof(IrqMidi));
StateFile->Read(MidiOutStack, sizeof(MidiOutStack));
StateFile->Read(&MidiOutW, sizeof(MidiOutW));
StateFile->Read(&MidiOutR, sizeof(MidiOutR));
StateFile->Read(MidiStack, sizeof(MidiStack));
StateFile->Read(&MidiOutFill, sizeof(MidiOutFill));
StateFile->Read(&MidiInFill, sizeof(MidiInFill));
StateFile->Read(&MidiW, sizeof(MidiW));
StateFile->Read(&MidiR, sizeof(MidiR));
StateFile->Read(TimPris, sizeof(TimPris));
StateFile->Read(TimCnt, sizeof(TimCnt));
// Load both SCSP states
for (int i = 0; i < 2; i++)
{
StateFile->Read(SCSPs[i].datab, sizeof(SCSPs[i].datab));
StateFile->Read(&(SCSPs[i].BUFPTR), sizeof(SCSPs[i].BUFPTR));
StateFile->Read(&(SCSPs[i].Master), sizeof(SCSPs[i].Master));
// Load each slot
for (int j = 0; j < 32; j++)
{
UINT32 baseOffset;
UINT8 egState;
StateFile->Read(SCSPs[i].Slots[j].datab, sizeof(SCSPs[i].Slots[j].datab));
StateFile->Read(&(SCSPs[i].Slots[j].active), sizeof(SCSPs[i].Slots[j].active));
StateFile->Read(&baseOffset, sizeof(baseOffset));
SCSPs[i].Slots[j].base = &(SCSPs[i].SCSPRAM[baseOffset&0xFFFFF]); // clamp to 1 MB
StateFile->Read(&(SCSPs[i].Slots[j].cur_addr), sizeof(SCSPs[i].Slots[j].cur_addr));
StateFile->Read(&(SCSPs[i].Slots[j].step), sizeof(SCSPs[i].Slots[j].step));
StateFile->Read(&(SCSPs[i].Slots[j].Back), sizeof(SCSPs[i].Slots[j].Back));
StateFile->Read(&(SCSPs[i].Slots[j].slot), sizeof(SCSPs[i].Slots[j].slot));
StateFile->Read(&(SCSPs[i].Slots[j].Prev), sizeof(SCSPs[i].Slots[j].Prev));
// EG
StateFile->Read(&(SCSPs[i].Slots[j].EG.volume), sizeof(SCSPs[i].Slots[j].EG.volume));
StateFile->Read(&egState, sizeof(egState));
SCSPs[i].Slots[j].EG.state = (_STATE) egState;
StateFile->Read(&(SCSPs[i].Slots[j].EG.step), sizeof(SCSPs[i].Slots[j].EG.step));
StateFile->Read(&(SCSPs[i].Slots[j].EG.AR), sizeof(SCSPs[i].Slots[j].EG.AR));
StateFile->Read(&(SCSPs[i].Slots[j].EG.D1R), sizeof(SCSPs[i].Slots[j].EG.D1R));
StateFile->Read(&(SCSPs[i].Slots[j].EG.D2R), sizeof(SCSPs[i].Slots[j].EG.D2R));
StateFile->Read(&(SCSPs[i].Slots[j].EG.RR), sizeof(SCSPs[i].Slots[j].EG.RR));
StateFile->Read(&(SCSPs[i].Slots[j].EG.DL), sizeof(SCSPs[i].Slots[j].EG.DL));
StateFile->Read(&(SCSPs[i].Slots[j].EG.EGHOLD), sizeof(SCSPs[i].Slots[j].EG.EGHOLD));
StateFile->Read(&(SCSPs[i].Slots[j].EG.LPLINK), sizeof(SCSPs[i].Slots[j].EG.LPLINK));
// PLFO
StateFile->Read(&(SCSPs[i].Slots[j].PLFO.phase), sizeof(SCSPs[i].Slots[j].PLFO.phase));
StateFile->Read(&(SCSPs[i].Slots[j].PLFO.phase_step), sizeof(SCSPs[i].Slots[j].PLFO.phase_step));
// ALFO
StateFile->Read(&(SCSPs[i].Slots[j].ALFO.phase), sizeof(SCSPs[i].Slots[j].ALFO.phase));
StateFile->Read(&(SCSPs[i].Slots[j].ALFO.phase_step), sizeof(SCSPs[i].Slots[j].ALFO.phase_step));
// Recompute LFOs
Compute_LFO(&(SCSPs[i].Slots[j]));
}
// DSP
StateFile->Read(&(SCSPs[i].DSP.RBP), sizeof(SCSPs[i].DSP.RBP));
StateFile->Read(&(SCSPs[i].DSP.RBL), sizeof(SCSPs[i].DSP.RBL));
StateFile->Read(SCSPs[i].DSP.COEF, sizeof(SCSPs[i].DSP.COEF));
StateFile->Read(SCSPs[i].DSP.MADRS, sizeof(SCSPs[i].DSP.MADRS));
StateFile->Read(SCSPs[i].DSP.MPRO, sizeof(SCSPs[i].DSP.MPRO));
StateFile->Read(SCSPs[i].DSP.TEMP, sizeof(SCSPs[i].DSP.TEMP));
StateFile->Read(SCSPs[i].DSP.MEMS, sizeof(SCSPs[i].DSP.MEMS));
StateFile->Read(&(SCSPs[i].DSP.DEC), sizeof(SCSPs[i].DSP.DEC));
StateFile->Read(SCSPs[i].DSP.MIXS, sizeof(SCSPs[i].DSP.MIXS));
StateFile->Read(SCSPs[i].DSP.EXTS, sizeof(SCSPs[i].DSP.EXTS));
StateFile->Read(SCSPs[i].DSP.EFREG, sizeof(SCSPs[i].DSP.EFREG));
StateFile->Read(&(SCSPs[i].DSP.Stopped), sizeof(SCSPs[i].DSP.Stopped));
StateFile->Read(&(SCSPs[i].DSP.LastStep), sizeof(SCSPs[i].DSP.LastStep));
}
}
void SCSP_SetBuffers(INT16 *leftBufferPtr, INT16 *rightBufferPtr, int bufferLength)
{
SysFPS = 60.0; // should this be updated to reflect actual FPS?

View file

@ -63,6 +63,8 @@ unsigned short SCSP_Slave_r16(unsigned int addr);
unsigned int SCSP_Slave_r32(unsigned int addr);
// Supermodel interface functions
void SCSP_SaveState(CBlockFile *StateFile);
void SCSP_LoadState(CBlockFile *StateFile);
void SCSP_SetBuffers(INT16 *leftBufferPtr, INT16 *rightBufferPtr, int bufferLength);
void SCSP_Deinit(void);

View file

@ -1075,6 +1075,7 @@ void SCSPDSP_Start(_SCSPDSP *DSP)
}
DSP->LastStep=i+1;
/*
int test=0;
if(test)
{
@ -1086,6 +1087,7 @@ void SCSPDSP_Start(_SCSPDSP *DSP)
fwrite(DSP->MADRS,32*2,1,f1);
fclose(f1);
}
*/
for(int t=0;t<0x10000;++t)
{