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
|
||||
)
|
||||
|
||||
# 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
|
||||
set(pcsx2DebugToolsSources
|
||||
DebugTools/DebugInterface.cpp
|
||||
|
@ -651,6 +691,8 @@ set(Common
|
|||
${pcsx2Headers}
|
||||
${pcsx2CDVDSources}
|
||||
${pcsx2CDVDHeaders}
|
||||
${pcsx2SPU2Sources}
|
||||
${pcsx2SPU2Headers}
|
||||
${pcsx2DebugToolsSources}
|
||||
${pcsx2GuiSources}
|
||||
${pcsx2GuiResources}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "IPU/IPUdma.h"
|
||||
#include "Gif_Unit.h"
|
||||
#include "IopCommon.h"
|
||||
#include "SPU2/spu2.h"
|
||||
|
||||
using namespace R5900;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "ps2/eeHwTraceLog.inl"
|
||||
|
||||
#include "ps2/pgif.h"
|
||||
#include "SPU2/spu2.h"
|
||||
#include "R3000A.h"
|
||||
|
||||
using namespace R5900;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "IopCommon.h"
|
||||
#include "SPU2/spu2.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "IopCommon.h"
|
||||
#include "SPU2/spu2.h"
|
||||
|
||||
#include "Sif.h"
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
#include "IopCommon.h"
|
||||
#include "ps2/pgif.h" // for PSX kernel TTY in iopMemWrite32
|
||||
#include "SPU2/spu2.h"
|
||||
|
||||
uptr *psxMemWLUT = NULL;
|
||||
const uptr *psxMemRLUT = NULL;
|
||||
|
|
|
@ -44,6 +44,7 @@ BIOS
|
|||
|
||||
#include "ps2/HwInternal.h"
|
||||
#include "ps2/BiosTools.h"
|
||||
#include "SPU2/spu2.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