pcsxr/plugins/dfsound/freeze.c

205 lines
6.5 KiB
C

/***************************************************************************
freeze.c - description
-------------------
begin : Wed May 15 2002
copyright : (C) 2002 by Pete Bernert
email : BlackDove@addcom.de
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. See also the license.txt file for *
* additional informations. *
* *
***************************************************************************/
#include "stdafx.h"
#define _IN_FREEZE
#include "externals.h"
#include "registers.h"
#include "spu.h"
#include "regs.h"
////////////////////////////////////////////////////////////////////////
// freeze structs
////////////////////////////////////////////////////////////////////////
typedef struct
{
char szSPUName[8];
uint32_t ulFreezeVersion;
uint32_t ulFreezeSize;
unsigned char cSPUPort[0x200];
unsigned char cSPURam[0x80000];
xa_decode_t xaS;
} SPUFreeze_t;
typedef struct
{
unsigned short spuIrq;
uint32_t pSpuIrq;
uint32_t dummy0;
uint32_t dummy1;
uint32_t dummy2;
uint32_t dummy3;
SPUCHAN s_chan[MAXCHAN];
} SPUOSSFreeze_t;
////////////////////////////////////////////////////////////////////////
void LoadStateV5(SPUFreeze_t * pF); // newest version
void LoadStateUnknown(SPUFreeze_t * pF); // unknown format
////////////////////////////////////////////////////////////////////////
// SPUFREEZE: called by main emu on savestate load/save
////////////////////////////////////////////////////////////////////////
long CALLBACK SPUfreeze(uint32_t ulFreezeMode,SPUFreeze_t * pF)
{
int i;SPUOSSFreeze_t * pFO;
if(!pF) return 0; // first check
if(ulFreezeMode) // info or save?
{//--------------------------------------------------//
if(ulFreezeMode==1)
memset(pF,0,sizeof(SPUFreeze_t)+sizeof(SPUOSSFreeze_t));
strcpy(pF->szSPUName,"PBOSS");
pF->ulFreezeVersion=5;
pF->ulFreezeSize=sizeof(SPUFreeze_t)+sizeof(SPUOSSFreeze_t);
if(ulFreezeMode==2) return 1; // info mode? ok, bye
// save mode:
RemoveTimer(); // stop timer
memcpy(pF->cSPURam,spuMem,0x80000); // copy common infos
memcpy(pF->cSPUPort,regArea,0x200);
if(xapGlobal && XAPlay!=XAFeed) // some xa
{
pF->xaS=*xapGlobal;
}
else
memset(&pF->xaS,0,sizeof(xa_decode_t)); // or clean xa
pFO=(SPUOSSFreeze_t *)(pF+1); // store special stuff
pFO->spuIrq=spuIrq;
if(pSpuIrq) pFO->pSpuIrq = (unsigned long)pSpuIrq-(unsigned long)spuMemC;
for(i=0;i<MAXCHAN;i++)
{
memcpy((void *)&pFO->s_chan[i],(void *)&s_chan[i],sizeof(SPUCHAN));
if(pFO->s_chan[i].pStart)
pFO->s_chan[i].pStart-=(unsigned long)spuMemC;
if(pFO->s_chan[i].pCurr)
pFO->s_chan[i].pCurr-=(unsigned long)spuMemC;
if(pFO->s_chan[i].pLoop)
pFO->s_chan[i].pLoop-=(unsigned long)spuMemC;
}
SetupTimer(); // sound processing on again
return 1;
//--------------------------------------------------//
}
if(ulFreezeMode!=0) return 0; // bad mode? bye
RemoveTimer(); // we stop processing while doing the save!
memcpy(spuMem,pF->cSPURam,0x80000); // get ram
memcpy(regArea,pF->cSPUPort,0x200);
if(pF->xaS.nsamples<=4032) // start xa again
SPUplayADPCMchannel(&pF->xaS);
xapGlobal=0;
if(!strcmp(pF->szSPUName,"PBOSS") &&
pF->ulFreezeVersion==5)
LoadStateV5(pF);
else LoadStateUnknown(pF);
// repair some globals
for(i=0;i<=62;i+=2)
SPUwriteRegister(H_Reverb+i,regArea[(H_Reverb+i-0xc00)>>1]);
SPUwriteRegister(H_SPUReverbAddr,regArea[(H_SPUReverbAddr-0xc00)>>1]);
SPUwriteRegister(H_SPUrvolL,regArea[(H_SPUrvolL-0xc00)>>1]);
SPUwriteRegister(H_SPUrvolR,regArea[(H_SPUrvolR-0xc00)>>1]);
SPUwriteRegister(H_SPUctrl,(unsigned short)(regArea[(H_SPUctrl-0xc00)>>1]|0x4000));
SPUwriteRegister(H_SPUstat,regArea[(H_SPUstat-0xc00)>>1]);
SPUwriteRegister(H_CDLeft,regArea[(H_CDLeft-0xc00)>>1]);
SPUwriteRegister(H_CDRight,regArea[(H_CDRight-0xc00)>>1]);
// fix to prevent new interpolations from crashing
for(i=0;i<MAXCHAN;i++) s_chan[i].SB[28]=0;
SetupTimer(); // start sound processing again
return 1;
}
////////////////////////////////////////////////////////////////////////
void LoadStateV5(SPUFreeze_t * pF)
{
int i;SPUOSSFreeze_t * pFO;
pFO=(SPUOSSFreeze_t *)(pF+1);
spuIrq = pFO->spuIrq;
if(pFO->pSpuIrq) pSpuIrq = pFO->pSpuIrq+spuMemC; else pSpuIrq=0;
for(i=0;i<MAXCHAN;i++)
{
memcpy((void *)&s_chan[i],(void *)&pFO->s_chan[i],sizeof(SPUCHAN));
s_chan[i].pStart+=(unsigned long)spuMemC;
s_chan[i].pCurr+=(unsigned long)spuMemC;
s_chan[i].pLoop+=(unsigned long)spuMemC;
s_chan[i].iMute=0;
s_chan[i].iIrqDone=0;
}
spuAddr = 0xffffffff;
}
////////////////////////////////////////////////////////////////////////
void LoadStateUnknown(SPUFreeze_t * pF)
{
int i;
for(i=0;i<MAXCHAN;i++)
{
s_chan[i].bOn=0;
s_chan[i].bNew=0;
s_chan[i].bStop=0;
s_chan[i].ADSR.lVolume=0;
s_chan[i].pLoop=spuMemC;
s_chan[i].pStart=spuMemC;
s_chan[i].pLoop=spuMemC;
s_chan[i].iMute=0;
s_chan[i].iIrqDone=0;
}
dwNewChannel=0;
pSpuIrq=0;
for(i=0;i<0xc0;i++)
{
SPUwriteRegister(0x1f801c00+i*2,regArea[i]);
}
}
////////////////////////////////////////////////////////////////////////