mirror of https://github.com/PCSX2/pcsx2.git
SPU2: merging some codebase callbacks
This commit is contained in:
parent
3d3ccbfcd7
commit
9c97092efd
|
@ -222,6 +222,46 @@ set(pcsx2CDVDHeaders
|
||||||
CDVD/zlib_indexed.h
|
CDVD/zlib_indexed.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# SPU2 sources
|
||||||
|
set(pcsx2SPU2Sources
|
||||||
|
SPU2/ADSR.cpp
|
||||||
|
SPU2/Debug.cpp
|
||||||
|
SPU2/DplIIdecoder.cpp
|
||||||
|
SPU2/Dma.cpp
|
||||||
|
SPU2/Lowpass.cpp
|
||||||
|
SPU2/Mixer.cpp
|
||||||
|
SPU2/spu2.cpp
|
||||||
|
SPU2/ReadInput.cpp
|
||||||
|
SPU2/RegLog.cpp
|
||||||
|
SPU2/RegTable.cpp
|
||||||
|
SPU2/Reverb.cpp
|
||||||
|
SPU2/SndOut.cpp
|
||||||
|
SPU2/SndOut_SDL.cpp
|
||||||
|
SPU2/spu2freeze.cpp
|
||||||
|
SPU2/spu2replay.cpp
|
||||||
|
SPU2/spu2sys.cpp
|
||||||
|
SPU2/Timestretcher.cpp
|
||||||
|
SPU2/Wavedump_wav.cpp
|
||||||
|
SPU2/WavFile.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# SPU2 headers
|
||||||
|
set(pcsx2SPU2Headers
|
||||||
|
SPU2/Config.h
|
||||||
|
SPU2/Debug.h
|
||||||
|
SPU2/defs.h
|
||||||
|
SPU2/Dma.h
|
||||||
|
SPU2/Global.h
|
||||||
|
SPU2/Lowpass.h
|
||||||
|
SPU2/Mixer.h
|
||||||
|
SPU2/spu2.h
|
||||||
|
SPU2/regs.h
|
||||||
|
SPU2/SndOut.h
|
||||||
|
SPU2/spdif.h
|
||||||
|
SPU2/spu2replay.h
|
||||||
|
SPU2/WavFile.h
|
||||||
|
)
|
||||||
|
|
||||||
# DebugTools sources
|
# DebugTools sources
|
||||||
set(pcsx2DebugToolsSources
|
set(pcsx2DebugToolsSources
|
||||||
DebugTools/DebugInterface.cpp
|
DebugTools/DebugInterface.cpp
|
||||||
|
@ -651,6 +691,8 @@ set(Common
|
||||||
${pcsx2Headers}
|
${pcsx2Headers}
|
||||||
${pcsx2CDVDSources}
|
${pcsx2CDVDSources}
|
||||||
${pcsx2CDVDHeaders}
|
${pcsx2CDVDHeaders}
|
||||||
|
${pcsx2SPU2Sources}
|
||||||
|
${pcsx2SPU2Headers}
|
||||||
${pcsx2DebugToolsSources}
|
${pcsx2DebugToolsSources}
|
||||||
${pcsx2GuiSources}
|
${pcsx2GuiSources}
|
||||||
${pcsx2GuiResources}
|
${pcsx2GuiResources}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "IPU/IPUdma.h"
|
#include "IPU/IPUdma.h"
|
||||||
#include "Gif_Unit.h"
|
#include "Gif_Unit.h"
|
||||||
#include "IopCommon.h"
|
#include "IopCommon.h"
|
||||||
|
#include "SPU2/spu2.h"
|
||||||
|
|
||||||
using namespace R5900;
|
using namespace R5900;
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "ps2/eeHwTraceLog.inl"
|
#include "ps2/eeHwTraceLog.inl"
|
||||||
|
|
||||||
#include "ps2/pgif.h"
|
#include "ps2/pgif.h"
|
||||||
|
#include "SPU2/spu2.h"
|
||||||
#include "R3000A.h"
|
#include "R3000A.h"
|
||||||
|
|
||||||
using namespace R5900;
|
using namespace R5900;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
#include "IopCommon.h"
|
#include "IopCommon.h"
|
||||||
|
#include "SPU2/spu2.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
#include "IopCommon.h"
|
#include "IopCommon.h"
|
||||||
|
#include "SPU2/spu2.h"
|
||||||
|
|
||||||
#include "Sif.h"
|
#include "Sif.h"
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
#include "IopCommon.h"
|
#include "IopCommon.h"
|
||||||
#include "ps2/pgif.h" // for PSX kernel TTY in iopMemWrite32
|
#include "ps2/pgif.h" // for PSX kernel TTY in iopMemWrite32
|
||||||
|
#include "SPU2/spu2.h"
|
||||||
|
|
||||||
uptr *psxMemWLUT = NULL;
|
uptr *psxMemWLUT = NULL;
|
||||||
const uptr *psxMemRLUT = NULL;
|
const uptr *psxMemRLUT = NULL;
|
||||||
|
|
|
@ -44,6 +44,7 @@ BIOS
|
||||||
|
|
||||||
#include "ps2/HwInternal.h"
|
#include "ps2/HwInternal.h"
|
||||||
#include "ps2/BiosTools.h"
|
#include "ps2/BiosTools.h"
|
||||||
|
#include "SPU2/spu2.h"
|
||||||
|
|
||||||
#include "Utilities/PageFaultSource.h"
|
#include "Utilities/PageFaultSource.h"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,612 @@
|
||||||
|
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
|
||||||
|
* Developed and maintained by the Pcsx2 Development Team.
|
||||||
|
*
|
||||||
|
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
|
||||||
|
*
|
||||||
|
* SPU2-X is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* SPU2-X is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
|
#include "spu2.h"
|
||||||
|
#include "Dma.h"
|
||||||
|
#include "Dialogs.h"
|
||||||
|
|
||||||
|
#include "svnrev.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define snprintf sprintf_s
|
||||||
|
#endif
|
||||||
|
// PCSX2 expects ASNI, not unicode, so this MUST always be char...
|
||||||
|
static char libraryName[256];
|
||||||
|
|
||||||
|
int SampleRate = 48000;
|
||||||
|
|
||||||
|
static bool IsOpened = false;
|
||||||
|
static bool IsInitialized = false;
|
||||||
|
|
||||||
|
static u32 pClocks = 0;
|
||||||
|
|
||||||
|
u32 *cyclePtr = NULL;
|
||||||
|
u32 lClocks = 0;
|
||||||
|
|
||||||
|
|
||||||
|
//static bool cpu_detected = false;
|
||||||
|
|
||||||
|
static bool CheckSSE()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if( !cpu_detected )
|
||||||
|
{
|
||||||
|
cpudetectInit();
|
||||||
|
cpu_detected = true;
|
||||||
|
}
|
||||||
|
if( !x86caps.hasStreamingSIMDExtensions || !x86caps.hasStreamingSIMD2Extensions )
|
||||||
|
{
|
||||||
|
SysMessage( "Your CPU does not support SSE2 instructions.\nThe SPU2-X plugin requires SSE2 to run." );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPU2configure()
|
||||||
|
{
|
||||||
|
if (!CheckSSE())
|
||||||
|
return;
|
||||||
|
configure();
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 SPU2test()
|
||||||
|
{
|
||||||
|
if (!CheckSSE())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ReadSettings();
|
||||||
|
if (SndBuffer::Test() != 0) {
|
||||||
|
// TODO : Implement a proper dialog that allows the user to test different audio out drivers.
|
||||||
|
const wchar_t *wtf = mods[OutputModule]->GetIdent();
|
||||||
|
SysMessage(L"The '%s' driver test failed. Please configure\na different SoundOut module and try again.", wtf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// DMA 4/7 Callbacks from Core Emulator
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
u16 *DMABaseAddr;
|
||||||
|
void (*_irqcallback)();
|
||||||
|
void (*dma4callback)();
|
||||||
|
void (*dma7callback)();
|
||||||
|
|
||||||
|
u32 CALLBACK SPU2ReadMemAddr(int core)
|
||||||
|
{
|
||||||
|
return Cores[core].MADR;
|
||||||
|
}
|
||||||
|
void CALLBACK SPU2WriteMemAddr(int core, u32 value)
|
||||||
|
{
|
||||||
|
Cores[core].MADR = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CALLBACK SPU2setDMABaseAddr(uptr baseaddr)
|
||||||
|
{
|
||||||
|
DMABaseAddr = (u16 *)baseaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CALLBACK SPU2setSettingsDir(const char *dir)
|
||||||
|
{
|
||||||
|
CfgSetSettingsDir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CALLBACK SPU2setLogDir(const char *dir)
|
||||||
|
{
|
||||||
|
CfgSetLogDir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPU2irqCallback(void (*SPU2callback)(), void (*DMA4callback)(), void (*DMA7callback)())
|
||||||
|
{
|
||||||
|
_irqcallback = SPU2callback;
|
||||||
|
dma4callback = DMA4callback;
|
||||||
|
dma7callback = DMA7callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CALLBACK SPU2readDMA4Mem(u16 *pMem, u32 size) // size now in 16bit units
|
||||||
|
{
|
||||||
|
if (cyclePtr != NULL)
|
||||||
|
TimeUpdate(*cyclePtr);
|
||||||
|
|
||||||
|
FileLog("[%10d] SPU2 readDMA4Mem size %x\n", Cycles, size << 1);
|
||||||
|
Cores[0].DoDMAread(pMem, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CALLBACK SPU2writeDMA4Mem(u16 *pMem, u32 size) // size now in 16bit units
|
||||||
|
{
|
||||||
|
if (cyclePtr != NULL)
|
||||||
|
TimeUpdate(*cyclePtr);
|
||||||
|
|
||||||
|
FileLog("[%10d] SPU2 writeDMA4Mem size %x at address %x\n", Cycles, size << 1, Cores[0].TSA);
|
||||||
|
#ifdef S2R_ENABLE
|
||||||
|
if (!replay_mode)
|
||||||
|
s2r_writedma4(Cycles, pMem, size);
|
||||||
|
#endif
|
||||||
|
Cores[0].DoDMAwrite(pMem, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CALLBACK SPU2interruptDMA4()
|
||||||
|
{
|
||||||
|
FileLog("[%10d] SPU2 interruptDMA4\n", Cycles);
|
||||||
|
Cores[0].Regs.STATX |= 0x80;
|
||||||
|
//Cores[0].Regs.ATTR &= ~0x30;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CALLBACK SPU2interruptDMA7()
|
||||||
|
{
|
||||||
|
FileLog("[%10d] SPU2 interruptDMA7\n", Cycles);
|
||||||
|
Cores[1].Regs.STATX |= 0x80;
|
||||||
|
//Cores[1].Regs.ATTR &= ~0x30;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CALLBACK SPU2readDMA7Mem(u16 *pMem, u32 size)
|
||||||
|
{
|
||||||
|
if (cyclePtr != NULL)
|
||||||
|
TimeUpdate(*cyclePtr);
|
||||||
|
|
||||||
|
FileLog("[%10d] SPU2 readDMA7Mem size %x\n", Cycles, size << 1);
|
||||||
|
Cores[1].DoDMAread(pMem, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CALLBACK SPU2writeDMA7Mem(u16 *pMem, u32 size)
|
||||||
|
{
|
||||||
|
if (cyclePtr != NULL)
|
||||||
|
TimeUpdate(*cyclePtr);
|
||||||
|
|
||||||
|
FileLog("[%10d] SPU2 writeDMA7Mem size %x at address %x\n", Cycles, size << 1, Cores[1].TSA);
|
||||||
|
#ifdef S2R_ENABLE
|
||||||
|
if (!replay_mode)
|
||||||
|
s2r_writedma7(Cycles, pMem, size);
|
||||||
|
#endif
|
||||||
|
Cores[1].DoDMAwrite(pMem, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 SPU2reset()
|
||||||
|
{
|
||||||
|
if (SndBuffer::Test() == 0 && SampleRate != 48000)
|
||||||
|
{
|
||||||
|
SampleRate = 48000;
|
||||||
|
SndBuffer::Cleanup();
|
||||||
|
|
||||||
|
try {
|
||||||
|
SndBuffer::Init();
|
||||||
|
}
|
||||||
|
catch (std::exception& ex) {
|
||||||
|
fprintf(stderr, "SPU2-X Error: Could not initialize device, or something.\nReason: %s", ex.what());
|
||||||
|
SPU2close();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SampleRate = 48000;
|
||||||
|
|
||||||
|
memset(spu2regs, 0, 0x010000);
|
||||||
|
memset(_spu2mem, 0, 0x200000);
|
||||||
|
memset(_spu2mem + 0x2800, 7, 0x10); // from BIOS reversal. Locks the voices so they don't run free.
|
||||||
|
Cores[0].Init(0);
|
||||||
|
Cores[1].Init(1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 SPU2ps1reset()
|
||||||
|
{
|
||||||
|
printf("RESET PS1 \n");
|
||||||
|
|
||||||
|
if (SndBuffer::Test() == 0 && SampleRate != 44100)
|
||||||
|
{
|
||||||
|
SampleRate = 44100;
|
||||||
|
SndBuffer::Cleanup();
|
||||||
|
|
||||||
|
try {
|
||||||
|
SndBuffer::Init();
|
||||||
|
}
|
||||||
|
catch (std::exception& ex) {
|
||||||
|
fprintf(stderr, "SPU2-X Error: Could not initialize device, or something.\nReason: %s", ex.what());
|
||||||
|
SPU2close();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SampleRate = 44100;
|
||||||
|
|
||||||
|
/* memset(spu2regs, 0, 0x010000);
|
||||||
|
memset(_spu2mem, 0, 0x200000);
|
||||||
|
memset(_spu2mem + 0x2800, 7, 0x10); // from BIOS reversal. Locks the voices so they don't run free.
|
||||||
|
Cores[0].Init(0);
|
||||||
|
Cores[1].Init(1);*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 SPU2init()
|
||||||
|
{
|
||||||
|
assert(regtable[0x400] == NULL);
|
||||||
|
|
||||||
|
if (IsInitialized) {
|
||||||
|
printf(" * SPU2-X: Already initialized - Ignoring SPU2init signal.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsInitialized = true;
|
||||||
|
|
||||||
|
ReadSettings();
|
||||||
|
|
||||||
|
#ifdef SPU2_LOG
|
||||||
|
if (AccessLog()) {
|
||||||
|
spu2Log = OpenLog(AccessLogFileName);
|
||||||
|
setvbuf(spu2Log, NULL, _IONBF, 0);
|
||||||
|
FileLog("SPU2init\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
srand((unsigned)time(NULL));
|
||||||
|
|
||||||
|
spu2regs = (s16 *)malloc(0x010000);
|
||||||
|
_spu2mem = (s16 *)malloc(0x200000);
|
||||||
|
|
||||||
|
// adpcm decoder cache:
|
||||||
|
// the cache data size is determined by taking the number of adpcm blocks
|
||||||
|
// (2MB / 16) and multiplying it by the decoded block size (28 samples).
|
||||||
|
// Thus: pcm_cache_data = 7,340,032 bytes (ouch!)
|
||||||
|
// Expanded: 16 bytes expands to 56 bytes [3.5:1 ratio]
|
||||||
|
// Resulting in 2MB * 3.5.
|
||||||
|
|
||||||
|
pcm_cache_data = (PcmCacheEntry *)calloc(pcm_BlockCount, sizeof(PcmCacheEntry));
|
||||||
|
|
||||||
|
if ((spu2regs == NULL) || (_spu2mem == NULL) || (pcm_cache_data == NULL)) {
|
||||||
|
SysMessage("SPU2-X: Error allocating Memory\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch up a copy of regtable that directly maps "NULLs" to SPU2 memory.
|
||||||
|
|
||||||
|
memcpy(regtable, regtable_original, sizeof(regtable));
|
||||||
|
|
||||||
|
for (uint mem = 0; mem < 0x800; mem++) {
|
||||||
|
u16 *ptr = regtable[mem >> 1];
|
||||||
|
if (!ptr) {
|
||||||
|
regtable[mem >> 1] = &(spu2Ru16(mem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPU2reset();
|
||||||
|
|
||||||
|
DMALogOpen();
|
||||||
|
InitADSR();
|
||||||
|
|
||||||
|
#ifdef S2R_ENABLE
|
||||||
|
if (!replay_mode)
|
||||||
|
s2r_open(Cycles, "replay_dump.s2r");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// Bit ugly to have this here instead of in RealttimeDebugger.cpp, but meh :p
|
||||||
|
extern bool debugDialogOpen;
|
||||||
|
extern HWND hDebugDialog;
|
||||||
|
|
||||||
|
static INT_PTR CALLBACK DebugProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
int wmId;
|
||||||
|
|
||||||
|
switch (uMsg) {
|
||||||
|
case WM_PAINT:
|
||||||
|
return FALSE;
|
||||||
|
case WM_INITDIALOG: {
|
||||||
|
debugDialogOpen = true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case WM_COMMAND:
|
||||||
|
wmId = LOWORD(wParam);
|
||||||
|
// Parse the menu selections:
|
||||||
|
switch (wmId) {
|
||||||
|
case IDOK:
|
||||||
|
case IDCANCEL:
|
||||||
|
debugDialogOpen = false;
|
||||||
|
EndDialog(hWnd, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
uptr gsWindowHandle = 0;
|
||||||
|
|
||||||
|
s32 SPU2open(void *pDsp)
|
||||||
|
{
|
||||||
|
if (IsOpened)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
FileLog("[%10d] SPU2 Open\n", Cycles);
|
||||||
|
|
||||||
|
if (pDsp != NULL)
|
||||||
|
gsWindowHandle = *(uptr *)pDsp;
|
||||||
|
else
|
||||||
|
gsWindowHandle = 0;
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#ifdef PCSX2_DEVBUILD // Define may not be needed but not tested yet. Better make sure.
|
||||||
|
if (IsDevBuild && VisualDebug()) {
|
||||||
|
if (debugDialogOpen == 0) {
|
||||||
|
hDebugDialog = CreateDialogParam(hInstance, MAKEINTRESOURCE(IDD_DEBUG), 0, DebugProc, 0);
|
||||||
|
ShowWindow(hDebugDialog, SW_SHOWNORMAL);
|
||||||
|
debugDialogOpen = 1;
|
||||||
|
}
|
||||||
|
} else if (debugDialogOpen) {
|
||||||
|
DestroyWindow(hDebugDialog);
|
||||||
|
debugDialogOpen = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
IsOpened = true;
|
||||||
|
lClocks = (cyclePtr != NULL) ? *cyclePtr : 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
SndBuffer::Init();
|
||||||
|
|
||||||
|
#ifndef __POSIX__
|
||||||
|
DspLoadLibrary(dspPlugin, dspPluginModule);
|
||||||
|
#endif
|
||||||
|
WaveDump::Open();
|
||||||
|
} catch (std::exception &ex) {
|
||||||
|
fprintf(stderr, "SPU2-X Error: Could not initialize device, or something.\nReason: %s", ex.what());
|
||||||
|
SPU2close();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPU2close()
|
||||||
|
{
|
||||||
|
if (!IsOpened)
|
||||||
|
return;
|
||||||
|
IsOpened = false;
|
||||||
|
|
||||||
|
FileLog("[%10d] SPU2 Close\n", Cycles);
|
||||||
|
|
||||||
|
#ifndef __POSIX__
|
||||||
|
DspCloseLibrary();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SndBuffer::Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPU2shutdown()
|
||||||
|
{
|
||||||
|
if (!IsInitialized)
|
||||||
|
return;
|
||||||
|
IsInitialized = false;
|
||||||
|
|
||||||
|
ConLog("* SPU2-X: Shutting down.\n");
|
||||||
|
|
||||||
|
SPU2close();
|
||||||
|
|
||||||
|
#ifdef S2R_ENABLE
|
||||||
|
if (!replay_mode)
|
||||||
|
s2r_close();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DoFullDump();
|
||||||
|
#ifdef STREAM_DUMP
|
||||||
|
fclose(il0);
|
||||||
|
fclose(il1);
|
||||||
|
#endif
|
||||||
|
#ifdef EFFECTS_DUMP
|
||||||
|
fclose(el0);
|
||||||
|
fclose(el1);
|
||||||
|
#endif
|
||||||
|
WaveDump::Close();
|
||||||
|
|
||||||
|
DMALogClose();
|
||||||
|
|
||||||
|
safe_free(spu2regs);
|
||||||
|
safe_free(_spu2mem);
|
||||||
|
safe_free(pcm_cache_data);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SPU2_LOG
|
||||||
|
if (!AccessLog())
|
||||||
|
return;
|
||||||
|
FileLog("[%10d] SPU2shutdown\n", Cycles);
|
||||||
|
if (spu2Log)
|
||||||
|
fclose(spu2Log);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPU2setClockPtr(u32 *ptr)
|
||||||
|
{
|
||||||
|
cyclePtr = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_KEYS
|
||||||
|
static u32 lastTicks;
|
||||||
|
static bool lState[6];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void SPU2async(u32 cycles)
|
||||||
|
{
|
||||||
|
DspUpdate();
|
||||||
|
|
||||||
|
if (cyclePtr != NULL) {
|
||||||
|
TimeUpdate(*cyclePtr);
|
||||||
|
} else {
|
||||||
|
pClocks += cycles;
|
||||||
|
TimeUpdate(pClocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_KEYS
|
||||||
|
u32 curTicks = GetTickCount();
|
||||||
|
if ((curTicks - lastTicks) >= 50) {
|
||||||
|
int oldI = Interpolation;
|
||||||
|
bool cState[6];
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
cState[i] = !!(GetAsyncKeyState(VK_NUMPAD0 + i) & 0x8000);
|
||||||
|
|
||||||
|
if ((cState[i] && !lState[i]) && i != 5)
|
||||||
|
Interpolation = i;
|
||||||
|
|
||||||
|
if ((cState[i] && !lState[i]) && i == 5) {
|
||||||
|
postprocess_filter_enabled = !postprocess_filter_enabled;
|
||||||
|
printf("Post process filters %s \n", postprocess_filter_enabled ? "enabled" : "disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
lState[i] = cState[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Interpolation != oldI) {
|
||||||
|
printf("Interpolation set to %d", Interpolation);
|
||||||
|
switch (Interpolation) {
|
||||||
|
case 0:
|
||||||
|
printf(" - Nearest.\n");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
printf(" - Linear.\n");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
printf(" - Cubic.\n");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
printf(" - Hermite.\n");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
printf(" - Catmull-Rom.\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf(" (unknown).\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastTicks = curTicks;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 SPU2read(u32 rmem)
|
||||||
|
{
|
||||||
|
// if(!replay_mode)
|
||||||
|
// s2r_readreg(Cycles,rmem);
|
||||||
|
|
||||||
|
u16 ret = 0xDEAD;
|
||||||
|
u32 core = 0, mem = rmem & 0xFFFF, omem = mem;
|
||||||
|
if (mem & 0x400) {
|
||||||
|
omem ^= 0x400;
|
||||||
|
core = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (omem == 0x1f9001AC) {
|
||||||
|
ret = Cores[core].DmaRead();
|
||||||
|
} else {
|
||||||
|
if (cyclePtr != NULL)
|
||||||
|
TimeUpdate(*cyclePtr);
|
||||||
|
|
||||||
|
if (rmem >> 16 == 0x1f80) {
|
||||||
|
ret = Cores[0].ReadRegPS1(rmem);
|
||||||
|
} else if (mem >= 0x800) {
|
||||||
|
ret = spu2Ru16(mem);
|
||||||
|
ConLog("* SPU2-X: Read from reg>=0x800: %x value %x\n", mem, ret);
|
||||||
|
} else {
|
||||||
|
ret = *(regtable[(mem >> 1)]);
|
||||||
|
//FileLog("[%10d] SPU2 read mem %x (core %d, register %x): %x\n",Cycles, mem, core, (omem & 0x7ff), ret);
|
||||||
|
SPU2writeLog("read", rmem, ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPU2write(u32 rmem, u16 value)
|
||||||
|
{
|
||||||
|
#ifdef S2R_ENABLE
|
||||||
|
if (!replay_mode)
|
||||||
|
s2r_writereg(Cycles, rmem, value);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Note: Reverb/Effects are very sensitive to having precise update timings.
|
||||||
|
// If the SPU2 isn't in in sync with the IOP, samples can end up playing at rather
|
||||||
|
// incorrect pitches and loop lengths.
|
||||||
|
|
||||||
|
if (cyclePtr != NULL)
|
||||||
|
TimeUpdate(*cyclePtr);
|
||||||
|
|
||||||
|
if (rmem >> 16 == 0x1f80)
|
||||||
|
Cores[0].WriteRegPS1(rmem, value);
|
||||||
|
else {
|
||||||
|
SPU2writeLog("write", rmem, value);
|
||||||
|
SPU2_FastWrite(rmem, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if start is 1, starts recording spu2 data, else stops
|
||||||
|
// returns a non zero value if successful
|
||||||
|
// for now, pData is not used
|
||||||
|
int SPU2setupRecording(int start, std::wstring* filename)
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
RecordStop();
|
||||||
|
else if (start == 1)
|
||||||
|
RecordStart(filename);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 SPU2freeze(int mode, freezeData *data)
|
||||||
|
{
|
||||||
|
pxAssume(data != NULL);
|
||||||
|
if (!data) {
|
||||||
|
printf("SPU2-X savestate null pointer!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == FREEZE_SIZE) {
|
||||||
|
data->size = Savestate::SizeIt();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxAssume(mode == FREEZE_LOAD || mode == FREEZE_SAVE);
|
||||||
|
|
||||||
|
if (data->data == NULL) {
|
||||||
|
printf("SPU2-X savestate null pointer!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Savestate::DataBlock &spud = (Savestate::DataBlock &)*(data->data);
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case FREEZE_LOAD:
|
||||||
|
return Savestate::ThawIt(spud);
|
||||||
|
case FREEZE_SAVE:
|
||||||
|
return Savestate::FreezeIt(spud);
|
||||||
|
|
||||||
|
jNO_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// technically unreachable, but kills a warning:
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
|
||||||
|
* Developed and maintained by the Pcsx2 Development Team.
|
||||||
|
*
|
||||||
|
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
|
||||||
|
*
|
||||||
|
* SPU2-X is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* SPU2-X is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Pcsx2Defs.h"
|
||||||
|
|
||||||
|
s32 SPU2init();
|
||||||
|
s32 SPU2reset();
|
||||||
|
s32 SPU2ps1reset();
|
||||||
|
s32 SPU2open(void *pDsp);
|
||||||
|
void SPU2close();
|
||||||
|
void SPU2shutdown();
|
||||||
|
void SPU2write(u32 mem, u16 value);
|
||||||
|
u16 SPU2read(u32 mem);
|
||||||
|
|
||||||
|
// extended funcs
|
||||||
|
// if start is 1, starts recording spu2 data, else stops
|
||||||
|
// returns a non zero value if successful
|
||||||
|
// for now, pData is not used
|
||||||
|
int SPU2setupRecording(int start, std::wstring* filename);
|
||||||
|
|
||||||
|
void SPU2setClockPtr(u32 *ptr);
|
||||||
|
|
||||||
|
void SPU2async(u32 cycles);
|
||||||
|
s32 SPU2freeze(int mode, freezeData *data);
|
||||||
|
void SPU2configure();
|
||||||
|
void SPU2about();
|
||||||
|
s32 SPU2test();
|
||||||
|
|
||||||
|
#include "Spu2replay.h"
|
||||||
|
|
||||||
|
extern u8 callirq;
|
||||||
|
|
||||||
|
extern void (*_irqcallback)();
|
||||||
|
|
||||||
|
extern void (*dma4callback)();
|
||||||
|
extern void (*dma7callback)();
|
||||||
|
|
||||||
|
extern s16 *input_data;
|
||||||
|
extern u32 input_data_ptr;
|
||||||
|
|
||||||
|
extern double srate_pv;
|
||||||
|
|
||||||
|
extern int recording;
|
||||||
|
extern u32 lClocks;
|
||||||
|
extern u32 *cyclePtr;
|
||||||
|
|
||||||
|
extern void SPU2writeLog(const char *action, u32 rmem, u16 value);
|
||||||
|
extern void TimeUpdate(u32 cClocks);
|
||||||
|
extern void SPU2_FastWrite(u32 rmem, u16 value);
|
||||||
|
|
||||||
|
extern void LowPassFilterInit();
|
||||||
|
|
||||||
|
//#define PCM24_S1_INTERLEAVE
|
|
@ -0,0 +1,321 @@
|
||||||
|
//GiGaHeRz's SPU2 Driver
|
||||||
|
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
|
||||||
|
//
|
||||||
|
//This library is free software; you can redistribute it and/or
|
||||||
|
//modify it under the terms of the GNU Lesser General Public
|
||||||
|
//License as published by the Free Software Foundation; either
|
||||||
|
//version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
//This library is distributed in the hope that it will be useful,
|
||||||
|
//but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
//Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
//You should have received a copy of the GNU Lesser General Public
|
||||||
|
//License along with this library; if not, write to the Free Software
|
||||||
|
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
|
#include "PS2E-spu2.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include "Windows.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FILE *s2rfile;
|
||||||
|
|
||||||
|
void s2r_write16(s16 data)
|
||||||
|
{
|
||||||
|
fwrite(&data, 2, 1, s2rfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void s2r_write32(u32 data)
|
||||||
|
{
|
||||||
|
fwrite(&data, 4, 1, s2rfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EMITC(u32 i, u32 a)
|
||||||
|
{
|
||||||
|
s2r_write32(((i & 0x7u) << 29u) | (a & 0x1FFFFFFFu));
|
||||||
|
}
|
||||||
|
|
||||||
|
int s2r_open(u32 ticks, char *filename)
|
||||||
|
{
|
||||||
|
s2rfile = fopen(filename, "wb");
|
||||||
|
if (s2rfile)
|
||||||
|
s2r_write32(ticks);
|
||||||
|
return s2rfile ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void s2r_readreg(u32 ticks, u32 addr)
|
||||||
|
{
|
||||||
|
if (!s2rfile)
|
||||||
|
return;
|
||||||
|
s2r_write32(ticks);
|
||||||
|
EMITC(0, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void s2r_writereg(u32 ticks, u32 addr, s16 value)
|
||||||
|
{
|
||||||
|
if (!s2rfile)
|
||||||
|
return;
|
||||||
|
s2r_write32(ticks);
|
||||||
|
EMITC(1, addr);
|
||||||
|
s2r_write16(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void s2r_writedma4(u32 ticks, u16 *data, u32 len)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
if (!s2rfile)
|
||||||
|
return;
|
||||||
|
s2r_write32(ticks);
|
||||||
|
EMITC(2, len);
|
||||||
|
for (i = 0; i < len; i++, data++)
|
||||||
|
s2r_write16(*data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void s2r_writedma7(u32 ticks, u16 *data, u32 len)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
if (!s2rfile)
|
||||||
|
return;
|
||||||
|
s2r_write32(ticks);
|
||||||
|
EMITC(3, len);
|
||||||
|
for (i = 0; i < len; i++, data++)
|
||||||
|
s2r_write16(*data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void s2r_close()
|
||||||
|
{
|
||||||
|
if (!s2rfile)
|
||||||
|
return;
|
||||||
|
fclose(s2rfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
// replay code
|
||||||
|
|
||||||
|
bool replay_mode = false;
|
||||||
|
|
||||||
|
u16 dmabuffer[0xFFFFF];
|
||||||
|
|
||||||
|
const u32 IOP_CLK = 768 * 48000;
|
||||||
|
const u32 IOPCiclesPerMS = 768 * 48;
|
||||||
|
u32 CurrentIOPCycle = 0;
|
||||||
|
|
||||||
|
u64 HighResFreq;
|
||||||
|
u64 HighResPrev;
|
||||||
|
double HighResScale;
|
||||||
|
|
||||||
|
bool Running = false;
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
int conprintf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
char s[1024];
|
||||||
|
va_list list;
|
||||||
|
|
||||||
|
va_start(list, fmt);
|
||||||
|
vsprintf(s, fmt, list);
|
||||||
|
va_end(list);
|
||||||
|
|
||||||
|
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
if (handle == INVALID_HANDLE_VALUE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
DWORD written = 0;
|
||||||
|
WriteConsoleA(handle, s, strlen(s), &written, 0);
|
||||||
|
FlushFileBuffers(handle);
|
||||||
|
|
||||||
|
return written;
|
||||||
|
#else
|
||||||
|
va_list list;
|
||||||
|
va_start(list, fmt);
|
||||||
|
int ret = vsprintf(stderr, fmt, list);
|
||||||
|
va_end(list);
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void dummy1()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void dummy4()
|
||||||
|
{
|
||||||
|
SPU2interruptDMA4();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dummy7()
|
||||||
|
{
|
||||||
|
SPU2interruptDMA7();
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 HighResFrequency()
|
||||||
|
{
|
||||||
|
u64 freq;
|
||||||
|
#ifdef _WIN32
|
||||||
|
QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
|
||||||
|
#else
|
||||||
|
// TODO
|
||||||
|
#endif
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 HighResCounter()
|
||||||
|
{
|
||||||
|
u64 time;
|
||||||
|
#ifdef _WIN32
|
||||||
|
QueryPerformanceCounter((LARGE_INTEGER *)&time);
|
||||||
|
#else
|
||||||
|
// TODO
|
||||||
|
#endif
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitWaitSync() // not extremely accurate but enough.
|
||||||
|
{
|
||||||
|
HighResFreq = HighResFrequency();
|
||||||
|
HighResPrev = HighResCounter();
|
||||||
|
HighResScale = (double)HighResFreq / (double)IOP_CLK;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 WaitSync(u32 TargetCycle)
|
||||||
|
{
|
||||||
|
u32 WaitCycles = (TargetCycle - CurrentIOPCycle);
|
||||||
|
u32 WaitTime = WaitCycles / IOPCiclesPerMS;
|
||||||
|
if (WaitTime > 10)
|
||||||
|
WaitTime = 10;
|
||||||
|
if (WaitTime == 0)
|
||||||
|
WaitTime = 1;
|
||||||
|
SleepEx(WaitTime, TRUE);
|
||||||
|
|
||||||
|
// Refresh current time after sleeping
|
||||||
|
u64 Current = HighResCounter();
|
||||||
|
u32 delta = (u32)floor((Current - HighResPrev) / HighResScale + 0.5); // We lose some precision here, cycles might drift away over long periods of time ;P
|
||||||
|
|
||||||
|
// Calculate time delta
|
||||||
|
CurrentIOPCycle += delta;
|
||||||
|
HighResPrev += (u64)floor(delta * HighResScale + 0.5); // Trying to compensate drifting mentioned above, not necessarily useful.
|
||||||
|
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
|
||||||
|
{
|
||||||
|
Running = false;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "Windows/Dialogs.h"
|
||||||
|
EXPORT_C_(void)
|
||||||
|
s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow)
|
||||||
|
{
|
||||||
|
int events = 0;
|
||||||
|
|
||||||
|
Running = true;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
AllocConsole();
|
||||||
|
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
|
||||||
|
|
||||||
|
conprintf("Playing %s file on %x...", filename, hwnd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// load file
|
||||||
|
FILE *file = fopen(filename, "rb");
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
conprintf("Could not open the replay file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if successful, init the plugin
|
||||||
|
|
||||||
|
#define TryRead(dest, size, count, file) \
|
||||||
|
if (fread(dest, size, count, file) < count) { \
|
||||||
|
conprintf("Error reading from file."); \
|
||||||
|
goto Finish; /* Need to exit the while() loop and maybe also the switch */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
TryRead(&CurrentIOPCycle, 4, 1, file);
|
||||||
|
|
||||||
|
replay_mode = true;
|
||||||
|
|
||||||
|
InitWaitSync(); // Initialize the WaitSync stuff
|
||||||
|
|
||||||
|
SPU2init();
|
||||||
|
SPU2irqCallback(dummy1, dummy4, dummy7);
|
||||||
|
SPU2setClockPtr(&CurrentIOPCycle);
|
||||||
|
SPU2open(&hwnd);
|
||||||
|
|
||||||
|
CurrentIOPCycle = 0;
|
||||||
|
|
||||||
|
SPU2async(0);
|
||||||
|
|
||||||
|
while (!feof(file) && Running) {
|
||||||
|
u32 ccycle = 0;
|
||||||
|
u32 evid = 0;
|
||||||
|
u32 sval = 0;
|
||||||
|
u32 tval = 0;
|
||||||
|
|
||||||
|
TryRead(&ccycle, 4, 1, file);
|
||||||
|
TryRead(&sval, 4, 1, file);
|
||||||
|
|
||||||
|
evid = sval >> 29;
|
||||||
|
sval &= 0x1FFFFFFF;
|
||||||
|
|
||||||
|
u32 TargetCycle = ccycle * 768;
|
||||||
|
|
||||||
|
while (TargetCycle > CurrentIOPCycle) {
|
||||||
|
u32 delta = WaitSync(TargetCycle);
|
||||||
|
SPU2async(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (evid) {
|
||||||
|
case 0:
|
||||||
|
SPU2read(sval);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
TryRead(&tval, 2, 1, file);
|
||||||
|
SPU2write(sval, tval);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
TryRead(dmabuffer, sval, 2, file);
|
||||||
|
SPU2writeDMA4Mem(dmabuffer, sval);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
TryRead(dmabuffer, sval, 2, file);
|
||||||
|
SPU2writeDMA7Mem(dmabuffer, sval);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// not implemented
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
events++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Finish:
|
||||||
|
|
||||||
|
//shutdown
|
||||||
|
SPU2close();
|
||||||
|
SPU2shutdown();
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
conprintf("Finished playing %s file (%d cycles, %d events).", filename, CurrentIOPCycle, events);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
FreeConsole();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
replay_mode = false;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,31 @@
|
||||||
|
//GiGaHeRz's SPU2 Driver
|
||||||
|
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
|
||||||
|
//
|
||||||
|
//This library is free software; you can redistribute it and/or
|
||||||
|
//modify it under the terms of the GNU Lesser General Public
|
||||||
|
//License as published by the Free Software Foundation; either
|
||||||
|
//version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
//This library is distributed in the hope that it will be useful,
|
||||||
|
//but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
//Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
//You should have received a copy of the GNU Lesser General Public
|
||||||
|
//License along with this library; if not, write to the Free Software
|
||||||
|
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//#define S2R_ENABLE
|
||||||
|
|
||||||
|
// s2r dumping
|
||||||
|
int s2r_open(u32 ticks, char *filename);
|
||||||
|
void s2r_readreg(u32 ticks, u32 addr);
|
||||||
|
void s2r_writereg(u32 ticks, u32 addr, s16 value);
|
||||||
|
void s2r_writedma4(u32 ticks, u16 *data, u32 len);
|
||||||
|
void s2r_writedma7(u32 ticks, u16 *data, u32 len);
|
||||||
|
void s2r_close();
|
||||||
|
|
||||||
|
extern bool replay_mode;
|
Loading…
Reference in New Issue