SPU2: remove initial plugin references

This commit is contained in:
Gauvain 'GovanifY' Roussel-Tarbouriech 2020-09-24 12:22:57 +02:00 committed by refractionpcsx2
parent cf58a32583
commit b8c3bd4fae
93 changed files with 4 additions and 19831 deletions

View File

@ -36,8 +36,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{2D6F0A62
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcsx2", "pcsx2\windows\VCprojects\pcsx2.vcxproj", "{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Spu2-X", "plugins\spu2-x\src\Windows\Spu2-X.vcxproj", "{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GSdx", "plugins\GSdx\GSdx.vcxproj", "{18E42F6F-3A62-41EE-B42F-79366C4F1E95}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "3rdparty\soundtouch\SoundTouch.vcxproj", "{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}"
@ -116,26 +114,6 @@ Global
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|Win32.Build.0 = Release|Win32
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|x64.ActiveCfg = Release|x64
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|x64.Build.0 = Release|x64
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|Win32.ActiveCfg = Debug|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|Win32.Build.0 = Debug|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|x64.ActiveCfg = Debug|x64
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|x64.Build.0 = Debug|x64
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Devel|Win32.ActiveCfg = Devel|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Devel|Win32.Build.0 = Devel|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Devel|x64.ActiveCfg = Devel|x64
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Devel|x64.Build.0 = Devel|x64
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release AVX2|Win32.ActiveCfg = Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release AVX2|Win32.Build.0 = Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release AVX2|x64.ActiveCfg = Release|x64
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release AVX2|x64.Build.0 = Release|x64
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release SSE4|Win32.ActiveCfg = Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release SSE4|Win32.Build.0 = Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release SSE4|x64.ActiveCfg = Release|x64
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release SSE4|x64.Build.0 = Release|x64
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|Win32.ActiveCfg = Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|Win32.Build.0 = Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|x64.ActiveCfg = Release|x64
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|x64.Build.0 = Release|x64
{18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Debug|Win32.ActiveCfg = Debug|Win32
{18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Debug|Win32.Build.0 = Debug|Win32
{18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Debug|x64.ActiveCfg = Debug|x64
@ -564,7 +542,6 @@ Global
{E1828E40-2FBB-48FE-AE7F-5587755DCE0E} = {703FD00B-D7A0-41E3-BD03-CEC86B385DAF}
{0FADC26C-0E9D-4DD7-84B1-BF4F7754E90C} = {88F517F9-CE1C-4005-9BDF-4481FEB55053}
{62BF822E-6A12-49A8-BE8C-C55A9BCA24DA} = {0FADC26C-0E9D-4DD7-84B1-BF4F7754E90C}
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4} = {703FD00B-D7A0-41E3-BD03-CEC86B385DAF}
{18E42F6F-3A62-41EE-B42F-79366C4F1E95} = {703FD00B-D7A0-41E3-BD03-CEC86B385DAF}
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}

View File

@ -178,35 +178,6 @@ else()
endif()
#---------------------------------------
#---------------------------------------
# SPU2null
#---------------------------------------
if(GTKn_FOUND AND EXTRA_PLUGINS)
set(SPU2null TRUE)
endif()
#---------------------------------------
#---------------------------------------
# spu2-x
#---------------------------------------
# requires: -SoundTouch
# -ALSA
# -SDL
# -common_libs
#
# optional: -Portaudio
#---------------------------------------
if((SOUNDTOUCH_FOUND AND SDLn_FOUND AND common_libs)
AND ((Linux AND ALSA_FOUND) OR (UNIX AND NOT Linux)))
set(spu2-x TRUE)
elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/spu2-x")
set(spu2-x FALSE)
else()
set(spu2-x FALSE)
print_dep("Skip build of spu2-x: missing dependencies" "${msg_dep_spu2x}")
endif()
#---------------------------------------
#---------------------------------------
# USBnull
#---------------------------------------

View File

@ -74,14 +74,13 @@ typedef struct _keyEvent
///////////////////////////////////////////////////////////////////////
#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \
defined(SPU2defs) || defined(DEV9defs) || defined(USBdefs)
defined(DEV9defs) || defined(USBdefs)
#define COMMONdefs
#endif
// PS2EgetLibType returns (may be OR'd)
#define PS2E_LT_GS 0x01
#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=-
#define PS2E_LT_SPU2 0x04
#define PS2E_LT_DEV9 0x10
#define PS2E_LT_USB 0x20
#define PS2E_LT_SIO 0x80
@ -89,7 +88,6 @@ typedef struct _keyEvent
// PS2EgetLibVersion2 (high 16 bits)
#define PS2E_GS_VERSION 0x0006
#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=-
#define PS2E_SPU2_VERSION 0x0005
#define PS2E_DEV9_VERSION 0x0003
#define PS2E_USB_VERSION 0x0003
#define PS2E_SIO_VERSION 0x0001
@ -247,59 +245,6 @@ s32 CALLBACK PADtest();
#endif
/* SPU2 plugin API */
// if this file is included with this define
// the next api will not be skipped by the compiler
#if defined(SPU2defs) || defined(BUILTIN_SPU2_PLUGIN)
// basic funcs
s32 CALLBACK SPU2init();
s32 CALLBACK SPU2open(void *pDsp);
void CALLBACK SPU2close();
void CALLBACK SPU2shutdown();
void CALLBACK SPU2setSettingsDir(const char *dir);
void CALLBACK SPU2setLogDir(const char *dir);
void CALLBACK SPU2reset();
void CALLBACK SPU2ps1reset();
void CALLBACK SPU2write(u32 mem, u16 value);
u16 CALLBACK SPU2read(u32 mem);
void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size);
void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size);
void CALLBACK SPU2interruptDMA4();
void CALLBACK SPU2readDMA7Mem(u16 *pMem, int size);
void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size);
// all addresses passed by dma will be pointers to the array starting at baseaddr
// This function is necessary to successfully save and reload the spu2 state
void CALLBACK SPU2setDMABaseAddr(uptr baseaddr);
void CALLBACK SPU2interruptDMA7();
u32 CALLBACK SPU2ReadMemAddr(int core);
void CALLBACK SPU2WriteMemAddr(int core, u32 value);
void CALLBACK SPU2irqCallback(void (*SPU2callback)(), void (*DMA4callback)(), void (*DMA7callback)());
// 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 CALLBACK SPU2setupRecording(int start, void *pData);
void CALLBACK SPU2setClockPtr(u32 *ptr);
void CALLBACK SPU2setTimeStretcher(short int enable);
void CALLBACK SPU2async(u32 cycles);
s32 CALLBACK SPU2freeze(int mode, freezeData *data);
void CALLBACK SPU2configure();
s32 CALLBACK SPU2test();
#endif
/* DEV9 plugin API */
// if this file is included with this define
@ -430,30 +375,6 @@ typedef s32(CALLBACK *_PADsetSlot)(u8 port, u8 slot);
typedef s32(CALLBACK *_PADqueryMtap)(u8 port);
typedef void(CALLBACK *_PADWriteEvent)(keyEvent &evt);
// SPU2
typedef s32(CALLBACK *_SPU2open)(void *pDsp);
typedef void(CALLBACK *_SPU2reset)();
typedef void (CALLBACK *_SPU2ps1reset)();
typedef void(CALLBACK *_SPU2write)(u32 mem, u16 value);
typedef u16(CALLBACK *_SPU2read)(u32 mem);
typedef void(CALLBACK *_SPU2readDMA4Mem)(u16 *pMem, int size);
typedef void(CALLBACK *_SPU2writeDMA4Mem)(u16 *pMem, int size);
typedef void(CALLBACK *_SPU2interruptDMA4)();
typedef void(CALLBACK *_SPU2readDMA7Mem)(u16 *pMem, int size);
typedef void(CALLBACK *_SPU2writeDMA7Mem)(u16 *pMem, int size);
typedef void(CALLBACK *_SPU2setDMABaseAddr)(uptr baseaddr);
typedef void(CALLBACK *_SPU2interruptDMA7)();
typedef void(CALLBACK *_SPU2irqCallback)(void (*SPU2callback)(), void (*DMA4callback)(), void (*DMA7callback)());
typedef u32(CALLBACK *_SPU2ReadMemAddr)(int core);
typedef void(CALLBACK *_SPU2WriteMemAddr)(int core, u32 value);
typedef int(CALLBACK *_SPU2setupRecording)(int, std::wstring*);
typedef void(CALLBACK *_SPU2setClockPtr)(u32 *ptr);
typedef void(CALLBACK *_SPU2setTimeStretcher)(short int enable);
typedef void(CALLBACK *_SPU2async)(u32 cycles);
// DEV9
// NOTE: The read/write functions CANNOT use XMM/MMX regs
// If you want to use them, need to save and restore current ones

View File

@ -177,7 +177,6 @@ extern "C" {
enum PS2E_ComponentTypes {
PS2E_TYPE_GS = 0,
PS2E_TYPE_PAD,
PS2E_TYPE_SPU2,
PS2E_TYPE_DEV9,
PS2E_TYPE_USB,
PS2E_TYPE_SIO,
@ -187,7 +186,6 @@ enum PS2E_ComponentTypes {
enum PluginLibVersion {
PS2E_VER_GS = 0x1000,
PS2E_VER_PAD = 0x1000,
PS2E_VER_SPU2 = 0x1000,
PS2E_VER_DEV9 = 0x1000,
PS2E_VER_USB = 0x1000,
PS2E_VER_SIO = 0x1000

View File

@ -726,9 +726,6 @@ endif()
if(BUILTIN_PAD)
set(pcsx2FinalLibs "${pcsx2FinalLibs} onepad-1.2.0")
endif()
if(BUILTIN_SPU2)
set(pcsx2FinalLibs "${pcsx2FinalLibs} spu2x-2.0.0")
endif()
if(BUILTIN_USB)
set(pcsx2FinalLibs "${pcsx2FinalLibs} USBnull-0.7.0")
endif()

View File

@ -23,7 +23,6 @@ enum PluginsEnum_t
{
PluginId_GS = 0,
PluginId_PAD,
PluginId_SPU2,
PluginId_USB,
PluginId_DEV9,
PluginId_Count,

View File

@ -81,7 +81,6 @@ const PluginInfo tbl_PluginInfo[] =
{
{ "GS", PluginId_GS, PS2E_LT_GS, PS2E_GS_VERSION },
{ "PAD", PluginId_PAD, PS2E_LT_PAD, PS2E_PAD_VERSION },
{ "SPU2", PluginId_SPU2, PS2E_LT_SPU2, PS2E_SPU2_VERSION },
{ "USB", PluginId_USB, PS2E_LT_USB, PS2E_USB_VERSION },
{ "DEV9", PluginId_DEV9, PS2E_LT_DEV9, PS2E_DEV9_VERSION },
@ -274,32 +273,6 @@ _PADWriteEvent PADWriteEvent;
static void PAD_update( u32 padslot ) { }
// SPU2
#ifndef BUILTIN_SPU2_PLUGIN
_SPU2open SPU2open;
_SPU2write SPU2write;
_SPU2reset SPU2reset;
_SPU2ps1reset SPU2ps1reset;
_SPU2read SPU2read;
_SPU2readDMA4Mem SPU2readDMA4Mem;
_SPU2writeDMA4Mem SPU2writeDMA4Mem;
_SPU2interruptDMA4 SPU2interruptDMA4;
_SPU2readDMA7Mem SPU2readDMA7Mem;
_SPU2writeDMA7Mem SPU2writeDMA7Mem;
_SPU2setDMABaseAddr SPU2setDMABaseAddr;
_SPU2interruptDMA7 SPU2interruptDMA7;
_SPU2ReadMemAddr SPU2ReadMemAddr;
_SPU2WriteMemAddr SPU2WriteMemAddr;
_SPU2setupRecording SPU2setupRecording;
_SPU2irqCallback SPU2irqCallback;
_SPU2setClockPtr SPU2setClockPtr;
_SPU2async SPU2async;
#endif
// DEV9
#ifndef BUILTIN_DEV9_PLUGIN
_DEV9open DEV9open;
@ -437,47 +410,6 @@ static const LegacyApi_OptMethod s_MethMessOpt_PAD[] =
{ NULL },
};
// ----------------------------------------------------------------------------
// SPU2 Mess!
// ----------------------------------------------------------------------------
// manualized reset that writes core reset registers of the SPU2 plugin:
static void CALLBACK SPU2_Reset()
{
SPU2write( 0x1f90019A, 1<<15 ); // core 0
SPU2write( 0x1f90059A, 1<<15 ); // core 1
}
static const LegacyApi_ReqMethod s_MethMessReq_SPU2[] =
{
{ "SPU2open", (vMeth**)&SPU2open, NULL },
{ "SPU2reset", (vMeth**)&SPU2reset, SPU2_Reset },
{ "SPU2ps1reset", (vMeth**)&SPU2ps1reset, SPU2ps1reset},
{ "SPU2write", (vMeth**)&SPU2write, NULL },
{ "SPU2read", (vMeth**)&SPU2read, NULL },
{ "SPU2readDMA4Mem", (vMeth**)&SPU2readDMA4Mem, NULL },
{ "SPU2readDMA7Mem", (vMeth**)&SPU2readDMA7Mem, NULL },
{ "SPU2writeDMA4Mem", (vMeth**)&SPU2writeDMA4Mem, NULL },
{ "SPU2writeDMA7Mem", (vMeth**)&SPU2writeDMA7Mem, NULL },
{ "SPU2interruptDMA4", (vMeth**)&SPU2interruptDMA4,NULL },
{ "SPU2interruptDMA7", (vMeth**)&SPU2interruptDMA7,NULL },
{ "SPU2ReadMemAddr", (vMeth**)&SPU2ReadMemAddr, NULL },
{ "SPU2irqCallback", (vMeth**)&SPU2irqCallback, NULL },
{ NULL }
};
static const LegacyApi_OptMethod s_MethMessOpt_SPU2[] =
{
{ "SPU2setClockPtr", (vMeth**)&SPU2setClockPtr },
{ "SPU2async", (vMeth**)&SPU2async },
{ "SPU2WriteMemAddr", (vMeth**)&SPU2WriteMemAddr },
{ "SPU2setDMABaseAddr", (vMeth**)&SPU2setDMABaseAddr},
{ "SPU2setupRecording", (vMeth**)&SPU2setupRecording},
{ NULL }
};
// ----------------------------------------------------------------------------
// DEV9 Mess!
// ----------------------------------------------------------------------------
@ -532,7 +464,6 @@ static const LegacyApi_ReqMethod* const s_MethMessReq[] =
{
s_MethMessReq_GS,
s_MethMessReq_PAD,
s_MethMessReq_SPU2,
s_MethMessReq_USB,
s_MethMessReq_DEV9
};
@ -541,7 +472,6 @@ static const LegacyApi_OptMethod* const s_MethMessOpt[] =
{
s_MethMessOpt_GS,
s_MethMessOpt_PAD,
s_MethMessOpt_SPU2,
s_MethMessOpt_USB,
s_MethMessOpt_DEV9
};
@ -706,9 +636,6 @@ void* StaticLibrary::GetSymbol(const wxString &name)
#ifdef BUILTIN_PAD_PLUGIN
RETURN_COMMON_SYMBOL(PAD);
#endif
#ifdef BUILTIN_SPU2_PLUGIN
RETURN_COMMON_SYMBOL(SPU2);
#endif
#ifdef BUILTIN_DEV9_PLUGIN
RETURN_COMMON_SYMBOL(DEV9);
#endif
@ -770,9 +697,6 @@ SysCorePlugins::PluginStatus_t::PluginStatus_t( PluginsEnum_t _pid, const wxStri
#ifdef BUILTIN_PAD_PLUGIN
case PluginId_PAD:
#endif
#ifdef BUILTIN_SPU2_PLUGIN
case PluginId_SPU2:
#endif
#ifdef BUILTIN_DEV9_PLUGIN
case PluginId_DEV9:
#endif
@ -1045,16 +969,6 @@ bool SysCorePlugins::OpenPlugin_PAD()
return !PADopen( (void*)pDsp );
}
bool SysCorePlugins::OpenPlugin_SPU2()
{
if( SPU2open((void*)pDsp) ) return false;
SPU2irqCallback( spu2Irq, spu2DMA4Irq, spu2DMA7Irq );
if( SPU2setDMABaseAddr != NULL ) SPU2setDMABaseAddr((uptr)iopMem->Main);
if( SPU2setClockPtr != NULL ) SPU2setClockPtr(&psxRegs.cycle);
return true;
}
bool SysCorePlugins::OpenPlugin_DEV9()
{
dev9Handler = NULL;
@ -1103,7 +1017,6 @@ void SysCorePlugins::Open( PluginsEnum_t pid )
{
case PluginId_GS: result = OpenPlugin_GS(); break;
case PluginId_PAD: result = OpenPlugin_PAD(); break;
case PluginId_SPU2: result = OpenPlugin_SPU2(); break;
case PluginId_USB: result = OpenPlugin_USB(); break;
case PluginId_DEV9: result = OpenPlugin_DEV9(); break;
@ -1177,11 +1090,6 @@ void SysCorePlugins::ClosePlugin_PAD()
_generalclose( PluginId_PAD );
}
void SysCorePlugins::ClosePlugin_SPU2()
{
_generalclose( PluginId_SPU2 );
}
void SysCorePlugins::ClosePlugin_DEV9()
{
_generalclose( PluginId_DEV9 );
@ -1211,7 +1119,6 @@ void SysCorePlugins::Close( PluginsEnum_t pid )
{
case PluginId_GS: ClosePlugin_GS(); break;
case PluginId_PAD: ClosePlugin_PAD(); break;
case PluginId_SPU2: ClosePlugin_SPU2(); break;
case PluginId_USB: ClosePlugin_USB(); break;
case PluginId_DEV9: ClosePlugin_DEV9(); break;
case PluginId_Mcd: ClosePlugin_Mcd(); break;

View File

@ -402,7 +402,6 @@ protected:
virtual bool OpenPlugin_GS();
virtual bool OpenPlugin_PAD();
virtual bool OpenPlugin_SPU2();
virtual bool OpenPlugin_DEV9();
virtual bool OpenPlugin_USB();
virtual bool OpenPlugin_Mcd();
@ -411,7 +410,6 @@ protected:
virtual void ClosePlugin_GS();
virtual void ClosePlugin_PAD();
virtual void ClosePlugin_SPU2();
virtual void ClosePlugin_DEV9();
virtual void ClosePlugin_USB();
virtual void ClosePlugin_Mcd();

View File

@ -291,6 +291,7 @@ void SysCoreThread::OnSuspendInThread()
GetCorePlugins().Close();
DoCDVDclose();
FWclose();
SPU2close();
}
void SysCoreThread::OnResumeInThread( bool isSuspended )
@ -299,6 +300,7 @@ void SysCoreThread::OnResumeInThread( bool isSuspended )
if (isSuspended || !g_GameStarted)
DoCDVDopen();
FWopen();
SPU2open();
}
@ -315,6 +317,7 @@ void SysCoreThread::OnCleanupInThread()
vu1Thread.WaitVU();
DoCDVDclose();
FWclose();
SPU2close();
GetCorePlugins().Close();
GetCorePlugins().Shutdown();

View File

@ -431,7 +431,6 @@ void MainEmuFrame::CreateConfigMenu()
m_menuConfig.AppendSeparator();
m_menuConfig.Append(MenuId_Config_GS, _("&Video (GS)"), m_PluginMenuPacks[PluginId_GS]);
m_menuConfig.Append(MenuId_Config_SPU2, _("&Audio (SPU2)"), m_PluginMenuPacks[PluginId_SPU2]);
m_menuConfig.Append(MenuId_Config_PAD, _("&Controllers (PAD)"),m_PluginMenuPacks[PluginId_PAD]);
m_menuConfig.Append(MenuId_Config_DEV9, _("&Dev9"), m_PluginMenuPacks[PluginId_DEV9]);
m_menuConfig.Append(MenuId_Config_USB, _("&USB"), m_PluginMenuPacks[PluginId_USB]);

View File

@ -263,7 +263,6 @@ static const std::unique_ptr<BaseSavestateEntry> SavestateEntries[] = {
std::unique_ptr<BaseSavestateEntry>(new PluginSavestateEntry( PluginId_GS )),
std::unique_ptr<BaseSavestateEntry>(new PluginSavestateEntry( PluginId_PAD )),
std::unique_ptr<BaseSavestateEntry>(new PluginSavestateEntry( PluginId_SPU2 )),
std::unique_ptr<BaseSavestateEntry>(new PluginSavestateEntry( PluginId_USB )),
std::unique_ptr<BaseSavestateEntry>(new PluginSavestateEntry( PluginId_DEV9 ))
};

View File

@ -38,14 +38,6 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/PadNull" AND PadNull)
add_subdirectory(PadNull)
endif()
if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/SPU2null" AND SPU2null)
add_subdirectory(SPU2null)
endif()
if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/spu2-x" AND spu2-x)
add_subdirectory(spu2-x/src)
endif()
if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/USBnull" AND USBnull)
add_subdirectory(USBnull)
endif()

View File

@ -1,57 +0,0 @@
# Check that people use the good file
if(NOT TOP_CMAKE_WAS_SOURCED)
message(FATAL_ERROR "
You did not 'cmake' the good CMakeLists.txt file. Use the one in the top dir.
It is advice to delete all wrongly generated cmake stuff => CMakeFiles & CMakeCache.txt")
endif()
# plugin name
set(Output SPU2null)
set(SPU2nullFinalFlags
-fvisibility=hidden
-Wall
-Wno-parentheses
)
# SPU2null sources
set(SPU2nullSources
SPU2.cpp)
# SPU2null headers
set(SPU2nullHeaders
SPU2.h)
# SPU2null Linux sources
set(SPU2nullLinuxSources
Linux/Config.cpp)
# SPU2null Linux headers
set(SPU2nullLinuxHeaders
Linux/Config.h)
# SPU2null Windows sources
set(SPU2nullWindowsSources
Windows/Config.cpp
Windows/SPU2null.def
Windows/SPU2null.rc
Windows/Win32.cpp)
# SPU2null Windows headers
set(SPU2nullWindowsHeaders
Windows/resource.h)
set(SPU2nullFinalSources
${SPU2nullSources}
${SPU2nullHeaders}
${SPU2nullLinuxSources}
${SPU2nullLinuxHeaders}
)
set(SPU2nullFinalLibs
${GTK2_LIBRARIES}
)
add_pcsx2_plugin(${Output} "${SPU2nullFinalSources}" "${SPU2nullFinalLibs}" "${SPU2nullFinalFlags}")
target_compile_features(${Output} PRIVATE cxx_std_17)

View File

@ -1,30 +0,0 @@
[ Legend: ]
[ + Added feature ]
[ * Improved/changed feature ]
[ - Bug fixed (we hope) ]
[ ! Attention (Notes) ]
ChangeLog:
v0.5
[+] Added Seperate IRQ Callbacks with AutoDMA check (refraction)
[-] Updated Specs to 0.9 (refraction)
v0.4
[+] added vsnet2005beta1 project files. 64bit dll should work fine now (not tested!!)
v0.2
15/06/03
[*] clear some stuff,made code more readable (shadow)
9/06/03
[+] Added some work on CoRE1_ATTR to get bios work (linuzappz)
9/06/03
[+] Added new SPU2 functions to PS2Edefs.h 0.3.2 version
[+] Added loggin system . IT can be enable in SPU2.H
[*] Update Ps2edefs to 0.3.1 (shadow)

View File

@ -1,342 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -1,67 +0,0 @@
/* SPU2null
* Copyright (C) 2002-2005 SPU2null Team
*
* 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.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "Config.h"
#include "SPU2.h"
#include "null/config.inl"
using namespace std;
extern string s_strIniPath;
PluginConf Ini;
EXPORT_C_(void)
SPU2configure()
{
LoadConfig();
ConfigureLogging();
SaveConfig();
}
EXPORT_C_(void)
SPU2about()
{
//SysMessage("%s %d.%d", libraryName, version, build);
SysMessage("SPU2null: A simple null plugin.");
}
void LoadConfig()
{
const std::string iniFile(s_strIniPath + "/Spu2null.ini");
if (!Ini.Open(iniFile, READ_FILE)) {
g_plugin_log.WriteLn("failed to open %s", iniFile.c_str());
SaveConfig(); //save and return
return;
}
conf.Log = Ini.ReadInt("logging", 0);
Ini.Close();
}
void SaveConfig()
{
const std::string iniFile(s_strIniPath + "/Spu2null.ini");
if (!Ini.Open(iniFile, WRITE_FILE)) {
g_plugin_log.WriteLn("failed to open %s", iniFile.c_str());
return;
}
Ini.WriteInt("logging", conf.Log);
Ini.Close();
}

View File

@ -1,26 +0,0 @@
/* SPU2null
* Copyright (C) 2002-2010 SPU2null Team
*
* 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.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;
extern void SaveConf();
extern void LoadConf();
extern string s_strIniPath;

View File

@ -1,39 +0,0 @@
SPU2null v0.4
-------------
This is an extension to use with play station2 emulators
as PCSX2 (only one right now).
The plugin is free open source code.
Usage:
-----
Place the file "SPU2null.dll" (Windows) or "libSPU2null.so" (Linux)
at the Plugins directory of the Emulator to use it.
Changes:
-------
v0.5
* added debug logging dialog + about dialog
* linuz did some reg fixes
* Added DEVC++ (4.9.9.2) project files for compiling with mingw32
v0.4
* added vsnet2005beta1 project files. 64bit dll should work fine now (not tested!)
* Fixed one more bug in regs stuff
v0.21
* more work on regs
v0.2:
* New functions & regs
v0.1:
* First Release
* Tested with Pcsx2
Authors:
-------
linuzappz <linuzappz@hotmail.com>
shadow <shadowpcsx2@yahoo.gr>

File diff suppressed because it is too large Load Diff

View File

@ -1,294 +0,0 @@
/* SPU2null
* Copyright (C) 2002-2005 SPU2null Team
*
* 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.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __SPU2_H__
#define __SPU2_H__
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <string.h>
extern "C" {
#define SPU2defs
#include "PS2Edefs.h"
}
#include "PS2Eext.h"
#ifdef _MSC_VER
#include <windows.h>
#include <windowsx.h>
#endif
#ifdef _MSC_VER
#define EXPORT_C_(type) extern "C" __declspec(dllexport) type CALLBACK
#else
#define EXPORT_C_(type) extern "C" __attribute__((stdcall, externally_visible, visibility("default"))) type
#endif
extern FILE *spu2Log;
#define SPU2_LOG __Log //debug mode
extern const u8 version;
extern const u8 revision;
extern const u8 build;
extern const u32 minor;
extern const char *libraryName;
typedef struct
{
s32 Log;
} Config;
extern Config conf;
void __Log(const char *fmt, ...);
void SaveConfig();
void LoadConfig();
void SysMessage(char *fmt, ...);
////////////////////
// SPU2 Registers //
////////////////////
#define REG_VP_VOLL 0x0000
#define REG_VP_VOLR 0x0002
#define REG_VP_PITCH 0x0004
#define REG_VP_ADSR1 0x0006
#define REG_VP_ADSR2 0x0008
#define REG_VP_ENVX 0x000A
#define REG_VP_VOLXL 0x000C
#define REG_VP_VOLXR 0x000E
#define REG_C0_FMOD1 0x0180
#define REG_C0_FMOD2 0x0182
#define REG_C1_FMOD1 0x0580
#define REG_C1_FMOD2 0x0582
#define REG_S_NON 0x0184
#define REG_S_VMIXL 0x0188
#define REG_S_VMIXEL 0x018C
#define REG_S_VMIXR 0x0190
#define REG_S_VMIXER 0x0194
#define REG_C0_MMIX 0x0198
#define REG_C1_MMIX 0x0598
#define REG_C0_CTRL 0x019A
#define REG_C0_IRQA_HI 0x019C
#define REG_C0_IRQA_LO 0x019D
#define REG_C1_IRQA_HI 0x059C
#define REG_C1_IRQA_LO 0x059D
#define REG_C0_SPUON1 0x1A0
#define REG_C0_SPUON2 0x1A2
#define REG_C1_SPUON1 0x5A0
#define REG_C1_SPUON2 0x5A2
#define REG_C0_SPUOFF1 0x1A4
#define REG_C0_SPUOFF2 0x1A6
#define REG_C1_SPUOFF1 0x5A4
#define REG_C1_SPUOFF2 0x5A6
#define REG_C0_SPUADDR_HI 0x01A8
#define REG_C0_SPUADDR_LO 0x01AA
#define REG_C1_SPUADDR_HI 0x05A8
#define REG_C1_SPUADDR_LO 0x05AA
#define REG_C0_SPUDATA 0x01AC
#define REG_C1_SPUDATA 0x05AC
#define REG_C0_DMACTRL 0x01AE
#define REG_C1_DMACTRL 0x05AE
#define REG_C0_ADMAS 0x01B0
#define REG_VA_SSA 0x01C0
#define REG_VA_LSAX 0x01C4
#define REG_VA_NAX 0x01C8
#define REG_A_ESA 0x02E0
#define REG_A_EEA 0x033C
#define REG_C0_END1 0x0340
#define REG_C0_END2 0x0342
#define REG_C1_END1 0x0740
#define REG_C1_END2 0x0742
#define REG_C0_SPUSTAT 0x0344 //not sure!
#define REG_C1_CTRL 0x059A
#define REG_C1_ADMAS 0x05B0
#define REG_C1_SPUSTAT 0x0744 //not sure!
#define REG_P_MVOLL 0x0760
#define REG_P_MVOLR 0x0762
#define REG_P_EVOLL 0x0764
#define REG_P_EVOLR 0x0766
#define REG_P_AVOLL 0x0768
#define REG_P_AVOLR 0x076A
#define REG_P_BVOLL 0x076C
#define REG_P_BVOLR 0x076E
#define REG_P_MVOLXL 0x0770
#define REG_P_MVOLXR 0x0772
#define SPDIF_OUT 0x07C0
#define REG_IRQINFO 0x07C2
#define SPDIF_MODE 0x07C6
#define SPDIF_MEDIA 0x07C8
#define spu2Rs16(mem) (*(s16 *)&spu2regs[(mem)&0xffff])
#define spu2Ru16(mem) (*(u16 *)&spu2regs[(mem)&0xffff])
//#define spu2Rs32(mem) (*(s32*)&spu2regs[(mem) & 0xffff])
//#define spu2Ru32(mem) (*(u32*)&spu2regs[(mem) & 0xffff])
#define IRQINFO spu2Ru16(REG_IRQINFO)
#define SPU2_GET32BIT(lo, hi) (((u32)(spu2Ru16(hi) & 0x3f) << 16) | (u32)spu2Ru16(lo))
#define SPU2_SET32BIT(value, lo, hi) \
{ \
spu2Ru16(hi) = ((value) >> 16) & 0x3f; \
spu2Ru16(lo) = (value)&0xffff; \
}
#define C0_IRQA SPU2_GET32BIT(REG_C0_IRQA_LO, REG_C0_IRQA_HI)
#define C1_IRQA SPU2_GET32BIT(REG_C1_IRQA_LO, REG_C1_IRQA_HI)
#define C0_SPUADDR SPU2_GET32BIT(REG_C0_SPUADDR_LO, REG_C0_SPUADDR_HI)
#define C1_SPUADDR SPU2_GET32BIT(REG_C1_SPUADDR_LO, REG_C1_SPUADDR_HI)
#define C0_SPUADDR_SET(value) SPU2_SET32BIT(value, REG_C0_IRQA_LO, REG_C0_IRQA_HI)
#define C1_SPUADDR_SET(value) SPU2_SET32BIT(value, REG_C1_IRQA_LO, REG_C1_IRQA_HI)
#define SPU_NUMBER_VOICES 48
struct SPU_CONTROL_
{
u16 spuon : 1;
u16 spuUnmute : 1;
u16 noiseFreq : 6;
u16 reverb : 1;
u16 irq : 1;
u16 dma : 2; // 1 - no dma, 2 - write, 3 - read
u16 extr : 1; // external reverb
u16 cdreverb : 1;
u16 extAudio : 1;
u16 extCd : 1;
};
// the layout of each voice in wSpuRegs
struct _SPU_VOICE
{
union
{
struct
{
u16 Vol : 14;
u16 Inverted : 1;
u16 Sweep0 : 1;
} vol;
struct
{
u16 Vol : 7;
u16 res1 : 5;
u16 Inverted : 1;
u16 Decrease : 1; // if 0, increase
u16 ExpSlope : 1; // if 0, linear slope
u16 Sweep1 : 1; // always one
} sweep;
u16 word;
} left, right;
u16 pitch : 14; // 1000 - no pitch, 2000 - pitch + 1, etc
u16 res0 : 2;
u16 SustainLvl : 4;
u16 DecayRate : 4;
u16 AttackRate : 7;
u16 AttackExp : 1; // if 0, linear
u16 ReleaseRate : 5;
u16 ReleaseExp : 1; // if 0, linear
u16 SustainRate : 7;
u16 res1 : 1;
u16 SustainDec : 1; // if 0, inc
u16 SustainExp : 1; // if 0, linear
u16 AdsrVol;
u16 Address; // add / 8
u16 RepeatAddr; // gets reset when sample starts
};
// ADSR INFOS PER CHANNEL
struct ADSRInfoEx
{
s32 State;
s32 AttackModeExp;
s32 AttackRate;
s32 DecayRate;
s32 SustainLevel;
s32 SustainModeExp;
s32 SustainIncrease;
s32 SustainRate;
s32 ReleaseModeExp;
s32 ReleaseRate;
s32 EnvelopeVol;
s32 lVolume;
};
#define NSSIZE 48 // ~ 1 ms of data
#define NSFRAMES 16 // gather at least NSFRAMES of NSSIZE before submitting
#define NSPACKETS 4
#define SPU_VOICE_STATE_SIZE (sizeof(VOICE_PROCESSED) - 4 * sizeof(void *))
struct VOICE_PROCESSED
{
VOICE_PROCESSED()
{
memset(this, 0, sizeof(VOICE_PROCESSED));
}
~VOICE_PROCESSED()
{
}
void SetVolume(int right);
void StartSound();
void VoiceChangeFrequency();
void FModChangeFrequency(int ns);
void Stop();
SPU_CONTROL_ *GetCtrl();
// start save state
s32 iSBPos; // mixing stuff
s32 spos;
s32 sinc;
s32 iActFreq; // current psx pitch
s32 iUsedFreq; // current pc pitch
s32 iStartAddr, iLoopAddr, iNextAddr;
ADSRInfoEx ADSRX; // next ADSR settings (will be moved to active on sample start)
bool bIgnoreLoop, bNew, bNoise, bReverb, bOn, bStop, bVolChanged;
s32 memoffset; // if first core, 0, if second, 0x400
// end save state
///////////////////
// Sound Buffers //
///////////////////
u8 *pStart; // start and end addresses
u8 *pLoop, *pCurr;
_SPU_VOICE *pvoice;
};
struct ADMA
{
u16 *MemAddr;
s32 IntPointer;
s32 Index;
s32 AmountLeft;
s32 Enabled;
};
#endif /* __SPU2_H__ */

View File

@ -1,65 +0,0 @@
/* SPU2null
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 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.
*
* PCSX2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include "SPU2.h"
extern HINSTANCE hInst;
void SaveConfig()
{
Config *Conf1 = &conf;
char *szTemp;
char szIniFile[256], szValue[256];
GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256);
szTemp = strrchr(szIniFile, '\\');
if (!szTemp)
return;
strcpy(szTemp, "\\inis\\spu2null.ini");
sprintf(szValue, "%u", Conf1->Log);
WritePrivateProfileString("Interface", "Logging", szValue, szIniFile);
}
void LoadConfig()
{
FILE *fp;
Config *Conf1 = &conf;
char *szTemp;
char szIniFile[256], szValue[256];
GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256);
szTemp = strrchr(szIniFile, '\\');
if (!szTemp)
return;
strcpy(szTemp, "\\inis\\spu2null.ini");
fp = fopen("inis\\usbnull.ini", "rt"); //check if usbnull.ini really exists
if (!fp) {
CreateDirectory("inis", NULL);
memset(&conf, 0, sizeof(conf));
conf.Log = 0; //default value
SaveConfig(); //save and return
return;
}
fclose(fp);
GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile);
Conf1->Log = strtoul(szValue, NULL, 10);
return;
}

View File

@ -1,31 +0,0 @@
; SPU2null.def : Declares the module parameters for the DLL.
LIBRARY "SPU2null"
DESCRIPTION 'SPU2 Null Driver'
EXPORTS
; Explicit exports can go here
PS2EgetLibType @2
PS2EgetLibName @3
PS2EgetLibVersion2 @4
SPU2init @5
SPU2shutdown @6
SPU2open @7
SPU2close @8
SPU2write @9
SPU2read @10
SPU2readDMA4Mem @11
SPU2writeDMA4Mem @12
SPU2readDMA7Mem @13
SPU2writeDMA7Mem @14
SPU2async @15
SPU2interruptDMA4 @16
SPU2interruptDMA7 @17
SPU2freeze @18
SPU2configure @21
SPU2test @22
SPU2about @23
SPU2ReadMemAddr @24
SPU2WriteMemAddr @25
SPU2irqCallback @26

View File

@ -1,127 +0,0 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxresmw.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxresmw.h""\r\0"
END
3 TEXTINCLUDE
BEGIN
"\r\0"
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Greek resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ELL)
#ifdef _WIN32
LANGUAGE LANG_GREEK, SUBLANG_DEFAULT
#pragma code_page(1253)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_CONFIG DIALOGEX 0, 0, 203, 81
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "SPU2configure"
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
DEFPUSHBUTTON "OK",IDOK,48,60,50,14
PUSHBUTTON "Cancel",IDCANCEL,113,60,50,14
CONTROL "Enable logging(for develop use only)",IDC_LOGGING,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,159,15
END
IDD_ABOUT DIALOGEX 0, 0, 181, 82
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About SPU2 Null..."
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
DEFPUSHBUTTON "OK",IDOK,65,54,50,14
LTEXT "SPU2 Null Driver v0.7.1",IDC_NAME,53,7,76,8
LTEXT "Authors: Shadow (shadowpcsx2@yahoo.gr) Linuzappz",IDC_STATIC,7,24,146,24
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_CONFIG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 196
TOPMARGIN, 7
BOTTOMMARGIN, 74
END
IDD_ABOUT, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 174
TOPMARGIN, 7
BOTTOMMARGIN, 75
END
END
#endif // APSTUDIO_INVOKED
#endif // Greek resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -1,102 +0,0 @@
/* SPU2null
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 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.
*
* PCSX2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <windows.h>
#include <windowsx.h>
#include "SPU2.h"
#include "resource.h"
HINSTANCE hInst;
void SysMessage(char *fmt, ...)
{
va_list list;
char tmp[512];
va_start(list, fmt);
vsprintf(tmp, fmt, list);
va_end(list);
MessageBox(0, tmp, "SPU2NULL Msg", 0);
}
BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_INITDIALOG:
LoadConfig();
if (conf.Log)
CheckDlgButton(hW, IDC_LOGGING, TRUE);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDCANCEL:
EndDialog(hW, TRUE);
return TRUE;
case IDOK:
if (IsDlgButtonChecked(hW, IDC_LOGGING))
conf.Log = 1;
else
conf.Log = 0;
SaveConfig();
EndDialog(hW, FALSE);
return TRUE;
}
}
return FALSE;
}
BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
EndDialog(hW, FALSE);
return TRUE;
}
}
return FALSE;
}
void CALLBACK SPU2configure()
{
DialogBox(hInst,
MAKEINTRESOURCE(IDD_CONFIG),
GetActiveWindow(),
(DLGPROC)ConfigureDlgProc);
}
void CALLBACK SPU2about()
{
DialogBox(hInst,
MAKEINTRESOURCE(IDD_ABOUT),
GetActiveWindow(),
(DLGPROC)AboutDlgProc);
}
BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT
DWORD dwReason,
LPVOID lpReserved)
{
hInst = (HINSTANCE)hModule;
return TRUE; // very quick :)
}

View File

@ -1,21 +0,0 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by SPU2null.rc
//
#define IDD_CONFDLG 101
#define IDD_CONFIG 101
#define IDD_ABOUT 103
#define IDC_NAME 1000
#define IDC_CHECK1 1007
#define IDC_LOGGING 1007
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -1,164 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the Library.

View File

@ -1,21 +0,0 @@
[This file contains the template for the SPU2-X code rights license. For the full
rant-like preamble of the LGPL, see GPL.txt and LGPL.txt -- both lisences apply,
with the LGPL as a subset extension of the GPL.]
/* 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/>.
*/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

View File

@ -1,207 +0,0 @@
/* 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"
static const s32 ADSR_MAX_VOL = 0x7fffffff;
static const int InvExpOffsets[] = {0, 4, 6, 8, 9, 10, 11, 12};
static u32 PsxRates[160];
void InitADSR() // INIT ADSR
{
for (int i = 0; i < (32 + 128); i++) {
int shift = (i - 32) >> 2;
s64 rate = (i & 3) + 4;
if (shift < 0)
rate >>= -shift;
else
rate <<= shift;
PsxRates[i] = (int)std::min(rate, (s64)0x3fffffffLL);
}
}
bool V_ADSR::Calculate()
{
pxAssume(Phase != 0);
if (Releasing && (Phase < 5))
Phase = 5;
switch (Phase) {
case 1: // attack
if (Value == ADSR_MAX_VOL) {
// Already maxed out. Progress phase and nothing more:
Phase++;
break;
}
// Case 1 below is for pseudo exponential below 75%.
// Pseudo Exp > 75% and Linear are the same.
if (AttackMode && (Value >= 0x60000000))
Value += PsxRates[(AttackRate ^ 0x7f) - 0x18 + 32];
else
Value += PsxRates[(AttackRate ^ 0x7f) - 0x10 + 32];
if (Value < 0) {
// We hit the ceiling.
Phase++;
Value = ADSR_MAX_VOL;
}
break;
case 2: // decay
{
u32 off = InvExpOffsets[(Value >> 28) & 7];
Value -= PsxRates[((DecayRate ^ 0x1f) * 4) - 0x18 + off + 32];
// calculate sustain level as a factor of the ADSR maximum volume.
s32 suslev = ((0x80000000 / 0x10) * (SustainLevel + 1)) - 1;
if (Value <= suslev) {
if (Value < 0)
Value = 0;
Phase++;
}
} break;
case 3: // sustain
{
// 0x7f disables sustain (infinite sustain)
if (SustainRate == 0x7f)
return true;
if (SustainMode & 2) // decreasing
{
if (SustainMode & 4) // exponential
{
u32 off = InvExpOffsets[(Value >> 28) & 7];
Value -= PsxRates[(SustainRate ^ 0x7f) - 0x1b + off + 32];
} else // linear
Value -= PsxRates[(SustainRate ^ 0x7f) - 0xf + 32];
if (Value <= 0) {
Value = 0;
Phase++;
}
} else { // increasing
if ((SustainMode & 4) && (Value >= 0x60000000))
Value += PsxRates[(SustainRate ^ 0x7f) - 0x18 + 32];
else
// linear / Pseudo below 75% (they're the same)
Value += PsxRates[(SustainRate ^ 0x7f) - 0x10 + 32];
if (Value < 0) {
Value = ADSR_MAX_VOL;
Phase++;
}
}
} break;
case 4: // sustain end
Value = (SustainMode & 2) ? 0 : ADSR_MAX_VOL;
if (Value == 0)
Phase = 6;
break;
case 5: // release
if (ReleaseMode) // exponential
{
u32 off = InvExpOffsets[(Value >> 28) & 7];
Value -= PsxRates[((ReleaseRate ^ 0x1f) * 4) - 0x18 + off + 32];
} else { // linear
//Value-=PsxRates[((ReleaseRate^0x1f)*4)-0xc+32];
if (ReleaseRate != 0x1f)
Value -= (1 << (0x1f - ReleaseRate));
}
if (Value <= 0) {
Value = 0;
Phase++;
}
break;
case 6: // release end
Value = 0;
break;
jNO_DEFAULT
}
// returns true if the voice is active, or false if it's stopping.
return Phase != 6;
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// //
#define VOLFLAG_REVERSE_PHASE (1ul << 0)
#define VOLFLAG_DECREMENT (1ul << 1)
#define VOLFLAG_EXPONENTIAL (1ul << 2)
#define VOLFLAG_SLIDE_ENABLE (1ul << 3)
void V_VolumeSlide::Update()
{
if (!(Mode & VOLFLAG_SLIDE_ENABLE))
return;
// Volume slides use the same basic logic as ADSR, but simplified (single-stage
// instead of multi-stage)
if (Increment == 0x7f)
return;
s32 value = abs(Value);
if (Mode & VOLFLAG_DECREMENT) {
// Decrement
if (Mode & VOLFLAG_EXPONENTIAL) {
u32 off = InvExpOffsets[(value >> 28) & 7];
value -= PsxRates[(Increment ^ 0x7f) - 0x1b + off + 32];
} else
value -= PsxRates[(Increment ^ 0x7f) - 0xf + 32];
if (value < 0) {
value = 0;
Mode = 0; // disable slide
}
} else {
// Increment
// Pseudo-exponential increments, as done by the SPU2 (really!)
// Above 75% slides slow, below 75% slides fast. It's exponential, pseudo'ly speaking.
if ((Mode & VOLFLAG_EXPONENTIAL) && (value >= 0x60000000))
value += PsxRates[(Increment ^ 0x7f) - 0x18 + 32];
else
// linear / Pseudo below 75% (they're the same)
value += PsxRates[(Increment ^ 0x7f) - 0x10 + 32];
if (value < 0) // wrapped around the "top"?
{
value = 0x7fffffff;
Mode = 0; // disable slide
}
}
Value = (Value < 0) ? -value : value;
}

View File

@ -1,160 +0,0 @@
if (openSUSE)
# openSUSE don't install wx in a standard library system
# path. Let's bypass the dynamic linker and hardcode the path.
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON)
endif()
# Check that people use the good file
if(NOT TOP_CMAKE_WAS_SOURCED)
message(FATAL_ERROR "
You did not 'cmake' the good CMakeLists.txt file. Use the one in the top dir.
It is advice to delete all wrongly generated cmake stuff => CMakeFiles & CMakeCache.txt")
endif()
set(CommonFlags
-fvisibility=hidden
-Wall
-Wno-parentheses
)
# plugin name
set(Output spu2x-2.0.0)
if (UNIX)
if (SDL2_API)
set(spu2xFinalFlags "-DSPU2X_SDL2" ${CommonFlags})
else()
set(spu2xFinalFlags "-DSPU2X_SDL" ${CommonFlags})
endif()
else()
set(spu2xFinalFlags ${CommonFlags})
endif()
# spu2x sources
set(spu2xSources
ADSR.cpp
Debug.cpp
DplIIdecoder.cpp
Dma.cpp
Lowpass.cpp
Mixer.cpp
PrecompiledHeader.cpp
PS2E-spu2.cpp
ReadInput.cpp
RegLog.cpp
RegTable.cpp
Reverb.cpp
SndOut.cpp
SndOut_SDL.cpp
spu2freeze.cpp
Spu2replay.cpp
spu2sys.cpp
Timestretcher.cpp
Wavedump_wav.cpp
WavFile.cpp
)
# spu2x headers
set(spu2xHeaders
Config.h
Debug.h
defs.h
Dma.h
Global.h
Lowpass.h
Mixer.h
PS2E-spu2.h
regs.h
SndOut.h
spdif.h
Spu2replay.h
WavFile.h
)
if(Windows)
LIST(APPEND spu2xSources
Windows/SndOut_waveOut.cpp
Windows/SndOut_DSound.cpp
Windows/SndOut_XAudio2.cpp
Windows/UIHelpers.cpp
Windows/RealtimeDebugger.cpp
Windows/dsp.cpp
Windows/ConfigSoundtouch.cpp
)
LIST(APPEND spu2xHeaders
Windows/resource.h
Windows/WinConfig.h
Windows/dsp.h
)
include_directories("Windows")
else()
LIST(APPEND spu2xSources
Linux/Alsa.cpp
Linux/CfgHelpers.cpp
Linux/Config.cpp
Linux/ConfigDebug.cpp
Linux/ConfigSoundTouch.cpp
Linux/Dialogs.cpp
wx/wxConfig.cpp
)
LIST(APPEND spu2xHeaders
Linux/Alsa.h
Linux/Config.h
Linux/Dialogs.h
wx/wxConfig.h
)
include_directories(Linux)
endif()
set(spu2xFinalSources
${spu2xSources}
${spu2xHeaders}
${spu2xLinuxHeaders}
)
set(spu2xFinalLibs
Utilities_NO_TLS
${ALSA_LIBRARIES}
${GTK2_LIBRARIES}
${SOUNDTOUCH_LIBRARIES}
)
if (PORTAUDIO_FOUND)
set(spu2xFinalFlags
${spu2xFinalFlags}
"-DSPU2X_PORTAUDIO"
)
LIST(APPEND spu2xFinalSources
SndOut_Portaudio.cpp
)
set(spu2xFinalLibs
${spu2xFinalLibs}
${PORTAUDIO_LIBRARIES}
)
endif()
if (SDL2_API)
set(spu2xFinalLibs
${spu2xFinalLibs}
${SDL2_LIBRARIES}
)
else()
set(spu2xFinalLibs
${spu2xFinalLibs}
${SDL_LIBRARY}
)
endif()
if(BUILTIN_SPU2)
add_pcsx2_lib(${Output} "${spu2xFinalSources}" "${spu2xFinalLibs}" "${spu2xFinalFlags}")
else()
add_pcsx2_plugin(${Output} "${spu2xFinalSources}" "${spu2xFinalLibs}" "${spu2xFinalFlags}")
endif()
target_compile_features(${Output} PRIVATE cxx_std_17)

View File

@ -1,102 +0,0 @@
/* 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
extern bool DebugEnabled;
extern bool _MsgToConsole;
extern bool _MsgKeyOnOff;
extern bool _MsgVoiceOff;
extern bool _MsgDMA;
extern bool _MsgAutoDMA;
extern bool _MsgOverruns;
extern bool _MsgCache;
extern bool _AccessLog;
extern bool _DMALog;
extern bool _WaveLog;
extern bool _CoresDump;
extern bool _MemDump;
extern bool _RegDump;
extern bool _visual_debug_enabled;
static __forceinline bool MsgToConsole() { return _MsgToConsole & DebugEnabled; }
static __forceinline bool MsgKeyOnOff() { return _MsgKeyOnOff & MsgToConsole(); }
static __forceinline bool MsgVoiceOff() { return _MsgVoiceOff & MsgToConsole(); }
static __forceinline bool MsgDMA() { return _MsgDMA & MsgToConsole(); }
static __forceinline bool MsgAutoDMA() { return _MsgAutoDMA & MsgToConsole(); }
static __forceinline bool MsgOverruns() { return _MsgOverruns & MsgToConsole(); }
static __forceinline bool MsgCache() { return _MsgCache & MsgToConsole(); }
static __forceinline bool AccessLog() { return _AccessLog & DebugEnabled; }
static __forceinline bool DMALog() { return _DMALog & DebugEnabled; }
static __forceinline bool WaveLog() { return _WaveLog & DebugEnabled; }
static __forceinline bool CoresDump() { return _CoresDump & DebugEnabled; }
static __forceinline bool MemDump() { return _MemDump & DebugEnabled; }
static __forceinline bool RegDump() { return _RegDump & DebugEnabled; }
static __forceinline bool VisualDebug() { return _visual_debug_enabled & DebugEnabled; }
extern wxString AccessLogFileName;
extern wxString DMA4LogFileName;
extern wxString DMA7LogFileName;
extern wxString CoresDumpFileName;
extern wxString MemDumpFileName;
extern wxString RegDumpFileName;
extern int Interpolation;
extern int numSpeakers;
extern bool EffectsDisabled;
extern float FinalVolume; // Global / pre-scale
extern bool AdvancedVolumeControl;
extern float VolumeAdjustFLdb;
extern float VolumeAdjustCdb;
extern float VolumeAdjustFRdb;
extern float VolumeAdjustBLdb;
extern float VolumeAdjustBRdb;
extern float VolumeAdjustSLdb;
extern float VolumeAdjustSRdb;
extern float VolumeAdjustLFEdb;
extern bool postprocess_filter_enabled;
extern bool postprocess_filter_dealias;
extern int dplLevel;
extern u32 OutputModule;
extern int SndOutLatencyMS;
extern int SynchMode;
#ifndef __POSIX__
extern wchar_t dspPlugin[];
extern int dspPluginModule;
extern bool dspPluginEnabled;
#endif
namespace SoundtouchCfg
{
extern void ApplySettings(soundtouch::SoundTouch &sndtouch);
}
//////
extern void ReadSettings();
extern void WriteSettings();
extern void configure();

View File

@ -1,258 +0,0 @@
/* 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"
int crazy_debug = 0;
char s[4096];
FILE *spu2Log = NULL;
void FileLog(const char *fmt, ...)
{
#ifdef SPU2_LOG
va_list list;
if (!AccessLog())
return;
if (!spu2Log)
return;
va_start(list, fmt);
vsprintf(s, fmt, list);
va_end(list);
fputs(s, spu2Log);
fflush(spu2Log);
#if 0
if(crazy_debug)
{
fputs(s,stderr);
fflush(stderr);
}
#endif
#endif
}
//Note to developer on the usage of ConLog:
// while ConLog doesn't print anything if messages to console are disabled at the GUI,
// it's still better to outright not call it on tight loop scenarios, by testing MsgToConsole() (which is inline and very quick).
// Else, there's some (small) overhead in calling and returning from ConLog.
void ConLog(const char *fmt, ...)
{
if (!MsgToConsole())
return;
va_list list;
va_start(list, fmt);
vsprintf(s, fmt, list);
va_end(list);
fputs(s, stderr);
fflush(stderr);
if (spu2Log) {
fputs(s, spu2Log);
fflush(spu2Log);
}
}
void V_VolumeSlide::DebugDump(FILE *dump, const char *title, const char *nameLR)
{
fprintf(dump, "%s Volume for %s Channel:\t%x\n"
" - Value: %x\n"
" - Mode: %x\n"
" - Increment: %x\n",
title, nameLR, Reg_VOL, Value, Mode, Increment);
}
void V_VolumeSlideLR::DebugDump(FILE *dump, const char *title)
{
Left.DebugDump(dump, title, "Left");
Right.DebugDump(dump, title, "Right");
}
void V_VolumeLR::DebugDump(FILE *dump, const char *title)
{
fprintf(dump, "Volume for %s (%s Channel):\t%x\n", title, "Left", Left);
fprintf(dump, "Volume for %s (%s Channel):\t%x\n", title, "Right", Right);
}
void DoFullDump()
{
#ifdef _MSC_VER
#ifdef SPU2_LOG
FILE *dump;
u8 c = 0, v = 0;
if (MemDump()) {
dump = fopen(wxString(MemDumpFileName).ToUTF8(), "wb");
if (dump) {
fwrite(_spu2mem, 0x200000, 1, dump);
fclose(dump);
}
}
if (RegDump()) {
dump = fopen(wxString(RegDumpFileName).ToUTF8(), "wb");
if (dump) {
fwrite(spu2regs, 0x2000, 1, dump);
fclose(dump);
}
}
if (!CoresDump())
return;
dump = fopen(wxString(CoresDumpFileName).ToUTF8(), "wt");
if (dump) {
for (c = 0; c < 2; c++) {
fprintf(dump, "#### CORE %d DUMP.\n", c);
Cores[c].MasterVol.DebugDump(dump, "Master");
Cores[c].ExtVol.DebugDump(dump, "External Data Input");
Cores[c].InpVol.DebugDump(dump, "Voice Data Input [dry]");
Cores[c].FxVol.DebugDump(dump, "Effects/Reverb [wet]");
fprintf(dump, "Interrupt Address: %x\n", Cores[c].IRQA);
fprintf(dump, "DMA Transfer Start Address: %x\n", Cores[c].TSA);
fprintf(dump, "External Input to Direct Output (Left): %s\n", Cores[c].DryGate.ExtL ? "Yes" : "No");
fprintf(dump, "External Input to Direct Output (Right): %s\n", Cores[c].DryGate.ExtR ? "Yes" : "No");
fprintf(dump, "External Input to Effects (Left): %s\n", Cores[c].WetGate.ExtL ? "Yes" : "No");
fprintf(dump, "External Input to Effects (Right): %s\n", Cores[c].WetGate.ExtR ? "Yes" : "No");
fprintf(dump, "Sound Data Input to Direct Output (Left): %s\n", Cores[c].DryGate.SndL ? "Yes" : "No");
fprintf(dump, "Sound Data Input to Direct Output (Right): %s\n", Cores[c].DryGate.SndR ? "Yes" : "No");
fprintf(dump, "Sound Data Input to Effects (Left): %s\n", Cores[c].WetGate.SndL ? "Yes" : "No");
fprintf(dump, "Sound Data Input to Effects (Right): %s\n", Cores[c].WetGate.SndR ? "Yes" : "No");
fprintf(dump, "Voice Data Input to Direct Output (Left): %s\n", Cores[c].DryGate.InpL ? "Yes" : "No");
fprintf(dump, "Voice Data Input to Direct Output (Right): %s\n", Cores[c].DryGate.InpR ? "Yes" : "No");
fprintf(dump, "Voice Data Input to Effects (Left): %s\n", Cores[c].WetGate.InpL ? "Yes" : "No");
fprintf(dump, "Voice Data Input to Effects (Right): %s\n", Cores[c].WetGate.InpR ? "Yes" : "No");
fprintf(dump, "IRQ Enabled: %s\n", Cores[c].IRQEnable ? "Yes" : "No");
fprintf(dump, "Effects Enabled: %s\n", Cores[c].FxEnable ? "Yes" : "No");
fprintf(dump, "Mute Enabled: %s\n", Cores[c].Mute ? "Yes" : "No");
fprintf(dump, "Noise Clock: %d\n", Cores[c].NoiseClk);
fprintf(dump, "DMA Bits: %d\n", Cores[c].DMABits);
fprintf(dump, "Effects Start: %x\n", Cores[c].EffectsStartA);
fprintf(dump, "Effects End: %x\n", Cores[c].EffectsEndA);
fprintf(dump, "Registers:\n");
fprintf(dump, " - PMON: %x\n", Cores[c].Regs.PMON);
fprintf(dump, " - NON: %x\n", Cores[c].Regs.NON);
fprintf(dump, " - VMIXL: %x\n", Cores[c].Regs.VMIXL);
fprintf(dump, " - VMIXR: %x\n", Cores[c].Regs.VMIXR);
fprintf(dump, " - VMIXEL: %x\n", Cores[c].Regs.VMIXEL);
fprintf(dump, " - VMIXER: %x\n", Cores[c].Regs.VMIXER);
fprintf(dump, " - MMIX: %x\n", Cores[c].Regs.VMIXEL);
fprintf(dump, " - ENDX: %x\n", Cores[c].Regs.VMIXER);
fprintf(dump, " - STATX: %x\n", Cores[c].Regs.VMIXEL);
fprintf(dump, " - ATTR: %x\n", Cores[c].Regs.VMIXER);
for (v = 0; v < 24; v++) {
fprintf(dump, "Voice %d:\n", v);
Cores[c].Voices[v].Volume.DebugDump(dump, "");
fprintf(dump, " - ADSR Envelope: %x & %x\n"
" - Ar: %x\n"
" - Am: %x\n"
" - Dr: %x\n"
" - Sl: %x\n"
" - Sr: %x\n"
" - Sm: %x\n"
" - Rr: %x\n"
" - Rm: %x\n"
" - Phase: %x\n"
" - Value: %x\n",
Cores[c].Voices[v].ADSR.regADSR1,
Cores[c].Voices[v].ADSR.regADSR2,
Cores[c].Voices[v].ADSR.AttackRate,
Cores[c].Voices[v].ADSR.AttackMode,
Cores[c].Voices[v].ADSR.DecayRate,
Cores[c].Voices[v].ADSR.SustainLevel,
Cores[c].Voices[v].ADSR.SustainRate,
Cores[c].Voices[v].ADSR.SustainMode,
Cores[c].Voices[v].ADSR.ReleaseRate,
Cores[c].Voices[v].ADSR.ReleaseMode,
Cores[c].Voices[v].ADSR.Phase,
Cores[c].Voices[v].ADSR.Value);
fprintf(dump, " - Pitch: %x\n", Cores[c].Voices[v].Pitch);
fprintf(dump, " - Modulated: %s\n", Cores[c].Voices[v].Modulated ? "Yes" : "No");
fprintf(dump, " - Source: %s\n", Cores[c].Voices[v].Noise ? "Noise" : "Wave");
fprintf(dump, " - Direct Output for Left Channel: %s\n", Cores[c].VoiceGates[v].DryL ? "Yes" : "No");
fprintf(dump, " - Direct Output for Right Channel: %s\n", Cores[c].VoiceGates[v].DryR ? "Yes" : "No");
fprintf(dump, " - Effects Output for Left Channel: %s\n", Cores[c].VoiceGates[v].WetL ? "Yes" : "No");
fprintf(dump, " - Effects Output for Right Channel: %s\n", Cores[c].VoiceGates[v].WetR ? "Yes" : "No");
fprintf(dump, " - Loop Start Address: %x\n", Cores[c].Voices[v].LoopStartA);
fprintf(dump, " - Sound Start Address: %x\n", Cores[c].Voices[v].StartA);
fprintf(dump, " - Next Data Address: %x\n", Cores[c].Voices[v].NextA);
fprintf(dump, " - Play Start Cycle: %d\n", Cores[c].Voices[v].PlayCycle);
fprintf(dump, " - Play Status: %s\n", (Cores[c].Voices[v].ADSR.Phase > 0) ? "Playing" : "Not Playing");
fprintf(dump, " - Block Sample: %d\n", Cores[c].Voices[v].SCurrent);
}
fprintf(dump, "#### END OF DUMP.\n\n");
}
fclose(dump);
}
dump = fopen("logs/effects.txt", "wt");
if (dump) {
for (c = 0; c < 2; c++) {
fprintf(dump, "#### CORE %d EFFECTS PROCESSOR DUMP.\n", c);
fprintf(dump, " - IN_COEF_L: %x\n", Cores[c].Revb.IN_COEF_R);
fprintf(dump, " - IN_COEF_R: %x\n", Cores[c].Revb.IN_COEF_L);
fprintf(dump, " - APF1_VOL: %x\n", Cores[c].Revb.APF1_VOL);
fprintf(dump, " - APF2_VOL: %x\n", Cores[c].Revb.APF2_VOL);
fprintf(dump, " - APF1_SIZE: %x\n", Cores[c].Revb.APF1_SIZE);
fprintf(dump, " - APF2_SIZE: %x\n", Cores[c].Revb.APF2_SIZE);
fprintf(dump, " - IIR_VOL: %x\n", Cores[c].Revb.IIR_VOL);
fprintf(dump, " - WALL_VOL: %x\n", Cores[c].Revb.WALL_VOL);
fprintf(dump, " - SAME_L_SRC: %x\n", Cores[c].Revb.SAME_L_SRC);
fprintf(dump, " - SAME_R_SRC: %x\n", Cores[c].Revb.SAME_R_SRC);
fprintf(dump, " - DIFF_L_SRC: %x\n", Cores[c].Revb.DIFF_L_SRC);
fprintf(dump, " - DIFF_R_SRC: %x\n", Cores[c].Revb.DIFF_R_SRC);
fprintf(dump, " - SAME_L_DST: %x\n", Cores[c].Revb.SAME_L_DST);
fprintf(dump, " - SAME_R_DST: %x\n", Cores[c].Revb.SAME_R_DST);
fprintf(dump, " - DIFF_L_DST: %x\n", Cores[c].Revb.DIFF_L_DST);
fprintf(dump, " - DIFF_R_DST: %x\n", Cores[c].Revb.DIFF_R_DST);
fprintf(dump, " - COMB1_VOL: %x\n", Cores[c].Revb.COMB1_VOL);
fprintf(dump, " - COMB2_VOL: %x\n", Cores[c].Revb.COMB2_VOL);
fprintf(dump, " - COMB3_VOL: %x\n", Cores[c].Revb.COMB3_VOL);
fprintf(dump, " - COMB4_VOL: %x\n", Cores[c].Revb.COMB4_VOL);
fprintf(dump, " - COMB1_L_SRC: %x\n", Cores[c].Revb.COMB1_L_SRC);
fprintf(dump, " - COMB1_R_SRC: %x\n", Cores[c].Revb.COMB1_R_SRC);
fprintf(dump, " - COMB2_L_SRC: %x\n", Cores[c].Revb.COMB2_L_SRC);
fprintf(dump, " - COMB2_R_SRC: %x\n", Cores[c].Revb.COMB2_R_SRC);
fprintf(dump, " - COMB3_L_SRC: %x\n", Cores[c].Revb.COMB3_L_SRC);
fprintf(dump, " - COMB3_R_SRC: %x\n", Cores[c].Revb.COMB3_R_SRC);
fprintf(dump, " - COMB4_L_SRC: %x\n", Cores[c].Revb.COMB4_L_SRC);
fprintf(dump, " - COMB4_R_SRC: %x\n", Cores[c].Revb.COMB4_R_SRC);
fprintf(dump, " - APF1_L_DST: %x\n", Cores[c].Revb.APF1_L_DST);
fprintf(dump, " - APF1_R_DST: %x\n", Cores[c].Revb.APF1_R_DST);
fprintf(dump, " - APF2_L_DST: %x\n", Cores[c].Revb.APF2_L_DST);
fprintf(dump, " - APF2_R_DST: %x\n", Cores[c].Revb.APF2_R_DST);
fprintf(dump, "#### END OF DUMP.\n\n");
}
fclose(dump);
}
#endif
#endif
}

View File

@ -1,71 +0,0 @@
//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
//
#ifndef DEBUG_H_INCLUDED
#define DEBUG_H_INCLUDED
extern FILE *spu2Log;
extern void FileLog(const char *fmt, ...);
extern void ConLog(const char *fmt, ...);
extern void DoFullDump();
extern FILE *OpenBinaryLog(const wxString &logfile);
extern FILE *OpenLog(const wxString &logfile);
extern FILE *OpenDump(const wxString &logfile);
namespace WaveDump
{
enum CoreSourceType {
// Core's input stream, usually pulled from ADMA streams.
CoreSrc_Input = 0,
// Output of the actual 24 input voices which have dry output enabled.
CoreSrc_DryVoiceMix,
// Output of the actual 24 input voices that have wet output enabled.
CoreSrc_WetVoiceMix,
// Wet mix including inputs and externals, prior to the application of reverb.
CoreSrc_PreReverb,
// Wet mix after reverb has turned it into a pile of garbly gook.
CoreSrc_PostReverb,
// Final output of the core. For core 0, it's the feed into Core1.
// For Core1, it's the feed into SndOut.
CoreSrc_External,
CoreSrc_Count
};
extern void Open();
extern void Close();
extern void WriteCore(uint coreidx, CoreSourceType src, s16 left, s16 right);
extern void WriteCore(uint coreidx, CoreSourceType src, const StereoOut16 &sample);
}
using WaveDump::CoreSrc_Input;
using WaveDump::CoreSrc_DryVoiceMix;
using WaveDump::CoreSrc_WetVoiceMix;
using WaveDump::CoreSrc_PreReverb;
using WaveDump::CoreSrc_PostReverb;
using WaveDump::CoreSrc_External;
#endif // DEBUG_H_INCLUDED //

View File

@ -1,416 +0,0 @@
/* 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 "Dma.h"
#include "PS2E-spu2.h" // temporary until I resolve cyclePtr/TimeUpdate dependencies.
extern u8 callirq;
static FILE *DMA4LogFile = NULL;
static FILE *DMA7LogFile = NULL;
static FILE *ADMA4LogFile = NULL;
static FILE *ADMA7LogFile = NULL;
static FILE *ADMAOutLogFile = NULL;
static FILE *REGWRTLogFile[2] = {0, 0};
void DMALogOpen()
{
if (!DMALog())
return;
DMA4LogFile = OpenBinaryLog(DMA4LogFileName);
DMA7LogFile = OpenBinaryLog(DMA7LogFileName);
ADMA4LogFile = OpenBinaryLog(L"adma4.raw");
ADMA7LogFile = OpenBinaryLog(L"adma7.raw");
ADMAOutLogFile = OpenBinaryLog(L"admaOut.raw");
}
void DMA4LogWrite(void *lpData, u32 ulSize)
{
if (!DMALog())
return;
if (!DMA4LogFile)
return;
fwrite(lpData, ulSize, 1, DMA4LogFile);
}
void DMA7LogWrite(void *lpData, u32 ulSize)
{
if (!DMALog())
return;
if (!DMA7LogFile)
return;
fwrite(lpData, ulSize, 1, DMA7LogFile);
}
void ADMAOutLogWrite(void *lpData, u32 ulSize)
{
if (!DMALog())
return;
if (!ADMAOutLogFile)
return;
fwrite(lpData, ulSize, 1, ADMAOutLogFile);
}
void RegWriteLog(u32 core, u16 value)
{
if (!DMALog())
return;
if (!REGWRTLogFile[core])
return;
fwrite(&value, 2, 1, REGWRTLogFile[core]);
}
void DMALogClose()
{
safe_fclose(DMA4LogFile);
safe_fclose(DMA7LogFile);
safe_fclose(REGWRTLogFile[0]);
safe_fclose(REGWRTLogFile[1]);
safe_fclose(ADMA4LogFile);
safe_fclose(ADMA7LogFile);
safe_fclose(ADMAOutLogFile);
}
void V_Core::LogAutoDMA(FILE *fp)
{
if (!DMALog() || !fp || !DMAPtr)
return;
fwrite(DMAPtr + InputDataProgress, 0x400, 1, fp);
}
void V_Core::AutoDMAReadBuffer(int mode) //mode: 0= split stereo; 1 = do not split stereo
{
int spos = ((InputPosRead + 0xff) & 0x100); //starting position of the free buffer
LogAutoDMA(Index ? ADMA7LogFile : ADMA4LogFile);
// HACKFIX!! DMAPtr can be invalid after a savestate load, so the savestate just forces it
// to NULL and we ignore it here. (used to work in old VM editions of PCSX2 with fixed
// addressing, but new PCSX2s have dynamic memory addressing).
if (mode) {
if (DMAPtr != NULL)
//memcpy((ADMATempBuffer+(spos<<1)),DMAPtr+InputDataProgress,0x400);
memcpy(GetMemPtr(0x2000 + (Index << 10) + spos), DMAPtr + InputDataProgress, 0x400);
MADR += 0x400;
InputDataLeft -= 0x200;
InputDataProgress += 0x200;
} else {
if (DMAPtr != NULL)
//memcpy((ADMATempBuffer+spos),DMAPtr+InputDataProgress,0x200);
memcpy(GetMemPtr(0x2000 + (Index << 10) + spos), DMAPtr + InputDataProgress, 0x200);
MADR += 0x200;
InputDataLeft -= 0x100;
InputDataProgress += 0x100;
if (DMAPtr != NULL)
//memcpy((ADMATempBuffer+spos+0x200),DMAPtr+InputDataProgress,0x200);
memcpy(GetMemPtr(0x2200 + (Index << 10) + spos), DMAPtr + InputDataProgress, 0x200);
MADR += 0x200;
InputDataLeft -= 0x100;
InputDataProgress += 0x100;
}
// See ReadInput at mixer.cpp for explanation on the commented out lines
//
}
void V_Core::StartADMAWrite(u16 *pMem, u32 sz)
{
int size = (sz) & (~511);
if (MsgAutoDMA())
ConLog("* SPU2-X: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n",
GetDmaIndexChar(), size << 1, TSA, DMABits, AutoDMACtrl, (~Regs.ATTR) & 0x7fff);
InputDataProgress = 0;
if ((AutoDMACtrl & (Index + 1)) == 0) {
TSA = 0x2000 + (Index << 10);
DMAICounter = size;
} else if (size >= 512) {
InputDataLeft = size;
if (AdmaInProgress == 0) {
#ifdef PCM24_S1_INTERLEAVE
if ((Index == 1) && ((PlayMode & 8) == 8)) {
AutoDMAReadBuffer(Index, 1);
} else {
AutoDMAReadBuffer(Index, 0);
}
#else
if (((PlayMode & 4) == 4) && (Index == 0))
Cores[0].InputPosRead = 0;
AutoDMAReadBuffer(0);
#endif
// Klonoa 2
if (size == 512)
DMAICounter = size;
}
AdmaInProgress = 1;
} else {
InputDataLeft = 0;
DMAICounter = 1;
}
TADR = MADR + (size << 1);
}
// HACKFIX: The BIOS breaks if we check the IRQA for both cores when issuing DMA writes. The
// breakage is a null psxRegs.pc being loaded form some memory address (haven't traced it deeper
// yet). We get around it by only checking the current core's IRQA, instead of doing the
// *correct* thing and checking both. This might break some games, but having a working BIOS
// is more important for now, until a proper fix can be uncovered.
//
// This problem might be caused by bad DMA timings in the IOP or a lack of proper IRQ
// handling by the Effects Processor. After those are implemented, let's hope it gets
// magically fixed?
//
// Note: This appears to affect DMA Writes only, so DMA Read DMAs are left intact (both core
// IRQAs are tested). Very few games use DMA reads tho, so it could just be a case of "works
// by the grace of not being used."
//
// Update: This hack is no longer needed when we don't do a core reset. Guess the null pc was in spu2 memory?
#define NO_BIOS_HACKFIX 1 // set to 1 to disable the hackfix
void V_Core::PlainDMAWrite(u16 *pMem, u32 size)
{
// Perform an alignment check.
// Not really important. Everything should work regardless,
// but it could be indicative of an emulation foopah elsewhere.
if (MsgToConsole()) {
// Don't need this anymore. Target may still be good to know though.
/*if((uptr)pMem & 15)
{
ConLog("* SPU2 DMA Write > Misaligned source. Core: %d IOP: %p TSA: 0x%x Size: 0x%x\n", Index, (void*)pMem, TSA, size);
}*/
if (TSA & 7) {
ConLog("* SPU2 DMA Write > Misaligned target. Core: %d IOP: %p TSA: 0x%x Size: 0x%x\n", Index, (void *)pMem, TSA, size);
}
}
if (Index == 0)
DMA4LogWrite(pMem, size << 1);
else
DMA7LogWrite(pMem, size << 1);
TSA &= 0xfffff;
u32 buff1end = TSA + size;
u32 buff2end = 0;
if (buff1end > 0x100000) {
buff2end = buff1end - 0x100000;
buff1end = 0x100000;
}
const int cacheIdxStart = TSA / pcm_WordsPerBlock;
const int cacheIdxEnd = (buff1end + pcm_WordsPerBlock - 1) / pcm_WordsPerBlock;
PcmCacheEntry *cacheLine = &pcm_cache_data[cacheIdxStart];
PcmCacheEntry &cacheEnd = pcm_cache_data[cacheIdxEnd];
do {
cacheLine->Validated = false;
cacheLine++;
} while (cacheLine != &cacheEnd);
//ConLog( "* SPU2-X: Cache Clear Range! TSA=0x%x, TDA=0x%x (low8=0x%x, high8=0x%x, len=0x%x)\n",
// TSA, buff1end, flagTSA, flagTDA, clearLen );
// First Branch needs cleared:
// It starts at TSA and goes to buff1end.
const u32 buff1size = (buff1end - TSA);
memcpy(GetMemPtr(TSA), pMem, buff1size * 2);
u32 TDA;
if (buff2end > 0) {
// second branch needs copied:
// It starts at the beginning of memory and moves forward to buff2end
// endpoint cache should be irrelevant, since it's almost certainly dynamic
// memory below 0x2800 (registers and such)
//const u32 endpt2 = (buff2end + roundUp) / indexer_scalar;
//memset( pcm_cache_flags, 0, endpt2 );
// Emulation Grayarea: Should addresses wrap around to zero, or wrap around to
// 0x2800? Hard to know for sure (almost no games depend on this)
memcpy(GetMemPtr(0), &pMem[buff1size], buff2end * 2);
TDA = (buff2end + 1) & 0xfffff;
// Flag interrupt? If IRQA occurs between start and dest, flag it.
// Important: Test both core IRQ settings for either DMA!
// Note: Because this buffer wraps, we use || instead of &&
#if NO_BIOS_HACKFIX
for (int i = 0; i < 2; i++) {
// Start is exclusive and end is inclusive... maybe? The end is documented to be inclusive,
// which suggests that memory access doesn't trigger interrupts, incrementing registers does
// (which would mean that if TSA=IRQA an interrupt doesn't fire... I guess?)
// Chaos Legion uses interrupt addresses set to the beginning of the two buffers in a double
// buffer scheme and sets LSA of one of the voices to the start of the opposite buffer.
// However it transfers to the same address right after setting IRQA, which by our previous
// understanding would trigger the interrupt early causing it to switch buffers again immediately
// and an interrupt never fires again, leaving the voices looping the same samples forever.
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA || Cores[i].IRQA <= TDA)) {
//ConLog("DMAwrite Core %d: IRQ Called (IRQ passed). IRQA = %x Cycles = %d\n", i, Cores[i].IRQA, Cycles );
SetIrqCall(i);
}
}
#else
if ((IRQEnable && (IRQA > TSA || IRQA <= TDA))
{
SetIrqCall(Index);
}
#endif
} else {
// Buffer doesn't wrap/overflow!
// Just set the TDA and check for an IRQ...
TDA = (buff1end + 1) & 0xfffff;
// Flag interrupt? If IRQA occurs between start and dest, flag it.
// Important: Test both core IRQ settings for either DMA!
#if NO_BIOS_HACKFIX
for (int i = 0; i < 2; i++) {
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA && Cores[i].IRQA <= TDA)) {
//ConLog("DMAwrite Core %d: IRQ Called (IRQ passed). IRQA = %x Cycles = %d\n", i, Cores[i].IRQA, Cycles );
SetIrqCall(i);
}
}
#else
if (IRQEnable && (IRQA > TSA) && (IRQA <= TDA)) {
SetIrqCall(Index);
}
#endif
}
TSA = TDA;
DMAICounter = size;
TADR = MADR + (size << 1);
}
void V_Core::DoDMAread(u16 *pMem, u32 size)
{
TSA &= 0xfffff;
u32 buff1end = TSA + size;
u32 buff2end = 0;
if (buff1end > 0x100000) {
buff2end = buff1end - 0x100000;
buff1end = 0x100000;
}
const u32 buff1size = (buff1end - TSA);
memcpy(pMem, GetMemPtr(TSA), buff1size * 2);
// Note on TSA's position after our copy finishes:
// IRQA should be measured by the end of the writepos+0x20. But the TDA
// should be written back at the precise endpoint of the xfer.
u32 TDA;
if (buff2end > 0) {
// second branch needs cleared:
// It starts at the beginning of memory and moves forward to buff2end
memcpy(&pMem[buff1size], GetMemPtr(0), buff2end * 2);
TDA = (buff2end + 0x20) & 0xfffff;
// Flag interrupt? If IRQA occurs between start and dest, flag it.
// Important: Test both core IRQ settings for either DMA!
// Note: Because this buffer wraps, we use || instead of &&
for (int i = 0; i < 2; i++) {
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA || Cores[i].IRQA <= TDA)) {
SetIrqCall(i);
}
}
} else {
// Buffer doesn't wrap/overflow!
// Just set the TDA and check for an IRQ...
TDA = (buff1end + 0x20) & 0xfffff;
// Flag interrupt? If IRQA occurs between start and dest, flag it.
// Important: Test both core IRQ settings for either DMA!
for (int i = 0; i < 2; i++) {
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA && Cores[i].IRQA <= TDA)) {
SetIrqCall(i);
}
}
}
TSA = TDA;
DMAICounter = size;
Regs.STATX &= ~0x80;
//Regs.ATTR |= 0x30;
TADR = MADR + (size << 1);
}
void V_Core::DoDMAwrite(u16 *pMem, u32 size)
{
DMAPtr = pMem;
if (size < 2) {
//if(dma7callback) dma7callback();
Regs.STATX &= ~0x80;
//Regs.ATTR |= 0x30;
DMAICounter = 1;
return;
}
if (IsDevBuild) {
DebugCores[Index].lastsize = size;
DebugCores[Index].dmaFlag = 2;
}
if (MsgToConsole()) {
if (TSA > 0xfffff) {
ConLog("* SPU2-X: Transfer Start Address out of bounds. TSA is %x\n", TSA);
}
}
TSA &= 0xfffff;
bool adma_enable = ((AutoDMACtrl & (Index + 1)) == (Index + 1));
if (adma_enable) {
TSA &= 0x1fff;
StartADMAWrite(pMem, size);
} else {
if (MsgDMA())
ConLog("* SPU2-X: DMA%c Transfer of %d bytes to %x (%02x %x %04x). IRQE = %d IRQA = %x \n",
GetDmaIndexChar(), size << 1, TSA, DMABits, AutoDMACtrl, (~Regs.ATTR) & 0x7fff,
Cores[0].IRQEnable, Cores[0].IRQA);
PlainDMAWrite(pMem, size);
}
Regs.STATX &= ~0x80;
//Regs.ATTR |= 0x30;
}

View File

@ -1,23 +0,0 @@
/* 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
extern void DMALogOpen();
extern void DMA4LogWrite(void *lpData, u32 ulSize);
extern void DMA7LogWrite(void *lpData, u32 ulSize);
extern void DMALogClose();

View File

@ -1,175 +0,0 @@
/* 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]
*
* 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
* 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"
// FIXME Not yet used so let's comment it out.
/*static const u8 sLogTable[256] = {
0x00, 0x3C, 0x60, 0x78, 0x8C, 0x9C, 0xA8, 0xB4, 0xBE, 0xC8, 0xD0, 0xD8, 0xDE, 0xE4, 0xEA, 0xF0,
0xF6, 0xFA, 0xFE, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x16, 0x1A, 0x1E, 0x20, 0x24, 0x26, 0x2A, 0x2C,
0x2E, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3E, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x50,
0x50, 0x52, 0x54, 0x56, 0x58, 0x5A, 0x5A, 0x5C, 0x5E, 0x60, 0x60, 0x62, 0x64, 0x66, 0x66, 0x68,
0x6A, 0x6A, 0x6C, 0x6E, 0x6E, 0x70, 0x70, 0x72, 0x74, 0x74, 0x76, 0x76, 0x78, 0x7A, 0x7A, 0x7C,
0x7C, 0x7E, 0x7E, 0x80, 0x80, 0x82, 0x82, 0x84, 0x84, 0x86, 0x86, 0x88, 0x88, 0x8A, 0x8A, 0x8C,
0x8C, 0x8C, 0x8E, 0x8E, 0x90, 0x90, 0x92, 0x92, 0x92, 0x94, 0x94, 0x96, 0x96, 0x96, 0x98, 0x98,
0x9A, 0x9A, 0x9A, 0x9C, 0x9C, 0x9C, 0x9E, 0x9E, 0xA0, 0xA0, 0xA0, 0xA2, 0xA2, 0xA2, 0xA4, 0xA4,
0xA4, 0xA6, 0xA6, 0xA6, 0xA8, 0xA8, 0xA8, 0xAA, 0xAA, 0xAA, 0xAC, 0xAC, 0xAC, 0xAC, 0xAE, 0xAE,
0xAE, 0xB0, 0xB0, 0xB0, 0xB2, 0xB2, 0xB2, 0xB2, 0xB4, 0xB4, 0xB4, 0xB6, 0xB6, 0xB6, 0xB6, 0xB8,
0xB8, 0xB8, 0xB8, 0xBA, 0xBA, 0xBA, 0xBC, 0xBC, 0xBC, 0xBC, 0xBE, 0xBE, 0xBE, 0xBE, 0xC0, 0xC0,
0xC0, 0xC0, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC4, 0xC4, 0xC4, 0xC4, 0xC6, 0xC6, 0xC6, 0xC6, 0xC8,
0xC8, 0xC8, 0xC8, 0xC8, 0xCA, 0xCA, 0xCA, 0xCA, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0xCE, 0xCE,
0xCE, 0xCE, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD4, 0xD4, 0xD4, 0xD4,
0xD4, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xDA, 0xDA, 0xDA, 0xDA,
0xDA, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xE0, 0xE0, 0xE0,
};*/
static float Gfl = 0, Gfr = 0;
static float LMax = 0, RMax = 0;
static float AccL = 0;
static float AccR = 0;
const float Scale = 4294967296.0f; // tweak this value to change the overall output volume
const float GainL = 0.80f * Scale;
const float GainR = 0.80f * Scale;
const float GainC = 0.75f * Scale;
const float GainSL = 0.90f * Scale;
const float GainSR = 0.90f * Scale;
const float GainLFE = 0.90f * Scale;
const float AddCLR = 0.20f * Scale; // Stereo expansion
extern void ResetDplIIDecoder()
{
Gfl = 0;
Gfr = 0;
LMax = 0;
RMax = 0;
AccL = 0;
AccR = 0;
}
void ProcessDplIISample32(const StereoOut32 &src, Stereo51Out32DplII *s)
{
float IL = src.Left / (float)(1 << (SndOutVolumeShift + 16));
float IR = src.Right / (float)(1 << (SndOutVolumeShift + 16));
// Calculate center channel and LFE
float C = (IL + IR) * 0.5f;
float SUB = C; // no need to lowpass, the speaker amplifier should take care of it
float L = IL - C; // Effective L/R data
float R = IR - C;
// Peak L/R
float PL = std::abs(L);
float PR = std::abs(R);
AccL += (PL - AccL) * 0.1f;
AccR += (PR - AccR) * 0.1f;
// Calculate power balance
float Balance = (AccR - AccL); // -1 .. 1
// If the power levels are different, then the audio is meant for the front speakers
float Frontness = std::abs(Balance);
float Rearness = 1 - Frontness; // And the other way around
// Equalize the power levels for L/R
float B = std::min(0.9f, std::max(-0.9f, Balance));
float VL = L / (1 - B); // if B>0, it means R>L, so increase L, else decrease L
float VR = R / (1 + B); // vice-versa
// 1.73+1.22 = 2.94; 2.94 = 0.34 = 0.9996; Close enough.
// The range for VL/VR is approximately 0..1,
// But in the cases where VL/VR are > 0.5, Rearness is 0 so it should never overflow.
const float RearScale = 0.34f * 2;
float SL = (VR * 1.73f - VL * 1.22f) * RearScale * Rearness;
float SR = (VR * 1.22f - VL * 1.73f) * RearScale * Rearness;
// Possible experiment: Play with stereo expension levels on rear
// Adjust the volume of the front speakers based on what we calculated above
L *= Frontness;
R *= Frontness;
s32 CX = (s32)(C * AddCLR);
s->Left = (s32)(L * GainL) + CX;
s->Right = (s32)(R * GainR) + CX;
s->Center = (s32)(C * GainC);
s->LFE = (s32)(SUB * GainLFE);
s->LeftBack = (s32)(SL * GainSL);
s->RightBack = (s32)(SR * GainSR);
}
void ProcessDplIISample16(const StereoOut32 &src, Stereo51Out16DplII *s)
{
Stereo51Out32DplII ss;
ProcessDplIISample32(src, &ss);
s->Left = ss.Left >> 16;
s->Right = ss.Right >> 16;
s->Center = ss.Center >> 16;
s->LFE = ss.LFE >> 16;
s->LeftBack = ss.LeftBack >> 16;
s->RightBack = ss.RightBack >> 16;
}
void ProcessDplSample32(const StereoOut32 &src, Stereo51Out32Dpl *s)
{
float ValL = src.Left / (float)(1 << (SndOutVolumeShift + 16));
float ValR = src.Right / (float)(1 << (SndOutVolumeShift + 16));
float C = (ValL + ValR) * 0.5f; //+15.8
float S = (ValL - ValR) * 0.5f;
float L = ValL - C; //+15.8
float R = ValR - C;
float SUB = C;
s32 CX = (s32)(C * AddCLR); // +15.16
s->Left = (s32)(L * GainL) + CX; // +15.16 = +31, can grow to +32 if (GainL + AddCLR)>255
s->Right = (s32)(R * GainR) + CX;
s->Center = (s32)(C * GainC); // +15.16 = +31
s->LFE = (s32)(SUB * GainLFE);
s->LeftBack = (s32)(S * GainSL);
s->RightBack = (s32)(S * GainSR);
}
void ProcessDplSample16(const StereoOut32 &src, Stereo51Out16Dpl *s)
{
Stereo51Out32Dpl ss;
ProcessDplSample32(src, &ss);
s->Left = ss.Left >> 16;
s->Right = ss.Right >> 16;
s->Center = ss.Center >> 16;
s->LFE = ss.LFE >> 16;
s->LeftBack = ss.LeftBack >> 16;
s->RightBack = ss.RightBack >> 16;
}

View File

@ -1,108 +0,0 @@
/* 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/>.
*/
#ifndef _SPU2X_GLOBAL_H_
#define _SPU2X_GLOBAL_H_
#define NOMINMAX
extern bool psxmode;
struct StereoOut16;
struct StereoOut32;
struct StereoOutFloat;
struct V_Core;
namespace soundtouch
{
class SoundTouch;
}
#include <assert.h>
#include <cstdlib>
#include <cstdio>
#include <cstdarg>
#include <cmath>
#include <ctime>
#include <stdexcept>
#include "Utilities/Dependencies.h"
#include "Pcsx2Defs.h"
#include "Pcsx2Types.h"
namespace VersionInfo
{
static const u8 Release = 2;
static const u8 Revision = 0; // increase that with each version
}
//////////////////////////////////////////////////////////////////////////
// Override Win32 min/max macros with the STL's type safe and macro
// free varieties (much safer!)
#undef min
#undef max
template <typename T>
static __forceinline void Clampify(T &src, T min, T max)
{
src = std::min(std::max(src, min), max);
}
template <typename T>
static __forceinline T GetClamped(T src, T min, T max)
{
return std::min(std::max(src, min), max);
}
#ifdef __WXMAC__
#include "PS2Eext.h"
#else
extern void SysMessage(const char *fmt, ...);
#endif
extern void SysMessage(const wchar_t *fmt, ...);
//////////////////////////////////////////////////////////////
// Dev / Debug conditionals --
// Consts for using if() statements instead of uglier #ifdef macros.
// Abbreviated macros for dev/debug only consoles and msgboxes.
#ifdef PCSX2_DEVBUILD
#define DevMsg MsgBox
#else
#define DevMsg
#endif
#ifdef PCSX2_DEVBUILD
#define SPU2_LOG
#endif
// Uncomment to enable debug keys on numpad (0 to 5)
//#define DEBUG_KEYS
#include "Utilities/Exceptions.h"
#include "Utilities/SafeArray.h"
#include "defs.h"
#include "regs.h"
#include "Config.h"
#include "Debug.h"
#include "SndOut.h"
#endif

View File

@ -1,254 +0,0 @@
/* 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/>.
*/
// Adapted from ZeroSPU2 code by Zerofrog. Heavily modified by Arcum42.
#ifdef __linux__
#include <alsa/asoundlib.h>
#include "Global.h"
#include "Alsa.h"
#include "SndOut.h"
// Does not work, except as effectively a null plugin.
class AlsaMod : public SndOutModule
{
protected:
static const int PacketsPerBuffer = 1; // increase this if ALSA can't keep up with 512-sample packets
static const int MAX_BUFFER_COUNT = 4;
static const int NumBuffers = 4; // TODO: this should be configurable someday -- lower values reduce latency.
unsigned int pspeed;
snd_pcm_t *handle;
snd_pcm_uframes_t buffer_size;
snd_async_handler_t *pcm_callback;
uint period_time;
uint buffer_time;
protected:
// Invoked by the static ExternalCallback method below.
void _InternalCallback()
{
snd_pcm_sframes_t avail;
fprintf(stderr, "* SPU2-X:Iz in your internal callback.\n");
avail = snd_pcm_avail_update(handle);
while (avail >= (int)period_time) {
StereoOut16 buff[PacketsPerBuffer * SndOutPacketSize];
StereoOut16 *p1 = buff;
for (int p = 0; p < PacketsPerBuffer; p++, p1 += SndOutPacketSize)
SndBuffer::ReadSamples(p1);
snd_pcm_writei(handle, buff, period_time);
avail = snd_pcm_avail_update(handle);
}
}
// Preps and invokes the _InternalCallback above. This provides a cdecl-compliant
// entry point for our C++ified object state. :)
static void ExternalCallback(snd_async_handler_t *pcm_call)
{
fprintf(stderr, "* SPU2-X:Iz in your external callback.\n");
AlsaMod *data = (AlsaMod *)snd_async_handler_get_callback_private(pcm_call);
pxAssume(data != NULL);
//pxAssume( data->handle == snd_async_handler_get_pcm(pcm_call) );
// Not sure if we just need an assert, or something like this:
if (data->handle != snd_async_handler_get_pcm(pcm_call)) {
fprintf(stderr, "* SPU2-X: Failed to handle sound.\n");
return;
}
data->_InternalCallback();
}
public:
s32 Init()
{
//fprintf(stderr,"* SPU2-X: Initing Alsa\n");
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
snd_pcm_status_t *status;
int pchannels = 2;
snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
handle = NULL;
pcm_callback = NULL;
pspeed = SAMPLE_RATE;
// buffer time and period time are in microseconds...
// (don't simplify the equation below -- it'll just cause integer rounding errors.
period_time = (SndOutPacketSize * 1000) / (SampleRate / 1000);
buffer_time = period_time * NumBuffers;
int err;
err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC /*| SND_PCM_NONBLOCK*/);
if (err < 0) {
fprintf(stderr, "Audio open error: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_nonblock(handle, 0);
if (err < 0) {
fprintf(stderr, "Can't set blocking mode: %s\n", snd_strerror(err));
return -1;
}
snd_pcm_hw_params_alloca(&hwparams);
snd_pcm_sw_params_alloca(&swparams);
err = snd_pcm_hw_params_any(handle, hwparams);
if (err < 0) {
fprintf(stderr, "Broken configuration for this PCM: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
if (err < 0) {
fprintf(stderr, "Access type not available: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_format(handle, hwparams, format);
if (err < 0) {
fprintf(stderr, "Sample format not available: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_channels(handle, hwparams, pchannels);
if (err < 0) {
fprintf(stderr, "Channels count not available: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0);
if (err < 0) {
fprintf(stderr, "Rate not available: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0);
if (err < 0) {
fprintf(stderr, "Buffer time error: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0);
if (err < 0) {
fprintf(stderr, "Period time error: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params(handle, hwparams);
if (err < 0) {
fprintf(stderr, "Unable to install hw params: %s\n", snd_strerror(err));
return -1;
}
snd_pcm_status_alloca(&status);
err = snd_pcm_status(handle, status);
if (err < 0) {
fprintf(stderr, "Unable to get status: %s\n", snd_strerror(err));
return -1;
}
// Bind our asynchronous callback magic:
if (handle == NULL)
fprintf(stderr, "No handle.");
//fprintf(stderr,"* SPU2-X:Iz setting your internal callback.\n");
// The external handler never seems to get called after this.
snd_async_add_pcm_handler(&pcm_callback, handle, ExternalCallback, this);
err = snd_pcm_start(handle);
if (err < 0) {
fprintf(stderr, "Pcm start failed: %s\n", snd_strerror(err));
return -1;
}
// Diagnostic code:
//buffer_size = snd_pcm_status_get_avail(status);
//fprintf(stderr,"All set up.\n");
return 0;
}
void Close()
{
//fprintf(stderr,"* SPU2-X: Closing Alsa\n");
if (handle == NULL)
return;
snd_pcm_drop(handle);
snd_pcm_close(handle);
handle = NULL;
}
virtual void Configure(uptr parent)
{
}
virtual bool Is51Out() const { return false; }
s32 Test() const
{
return 0;
}
int GetEmptySampleCount()
{
if (handle == NULL) {
fprintf(stderr, "Handle is NULL!\n");
return 0;
}
// Returns the amount of free buffer space, in samples.
int l = snd_pcm_avail_update(handle);
if (l < 0)
return 0;
return (l / 1000) * (SampleRate / 1000);
}
const wchar_t *GetIdent() const
{
return L"Alsa";
}
const wchar_t *GetLongName() const
{
return L"Alsa";
}
void ReadSettings()
{
}
void SetApiSettings(wxString api)
{
}
void WriteSettings() const
{
}
} static Alsa;
SndOutModule *AlsaOut = &Alsa;
#endif

View File

@ -1,42 +0,0 @@
/* 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/>.
*/
#ifndef __LINUX_H__
#define __LINUX_H__
#include <assert.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/soundcard.h>
#include <unistd.h>
#define SAMPLE_RATE 48000L
// Pull in from Alsa.cpp
extern int AlsaSetupSound();
extern void AlsaRemoveSound();
extern int AlsaSoundGetBytesBuffered();
extern void AlsaSoundFeedVoiceData(unsigned char *pSound, long lBytes);
extern int SetupSound();
extern void RemoveSound();
extern int SoundGetBytesBuffered();
extern void SoundFeedVoiceData(unsigned char *pSound, long lBytes);
#endif // __LINUX_H__

View File

@ -1,108 +0,0 @@
/* 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 "Dialogs.h"
#include <wx/fileconf.h>
wxFileConfig *spuConfig = nullptr;
wxString path(L"~/.pcsx2/inis/spu2-x.ini");
bool pathSet = false;
void initIni()
{
if (spuConfig == nullptr)
spuConfig = new wxFileConfig(L"", L"", path, L"", wxCONFIG_USE_LOCAL_FILE);
}
void setIni(const wchar_t *Section)
{
initIni();
spuConfig->SetPath(wxsFormat(L"/%s", Section));
}
void CfgSetSettingsDir(const char *dir)
{
FileLog("CfgSetSettingsDir(%s)\n", dir);
path = wxString::FromUTF8(dir) + L"/spu2-x.ini";
pathSet = true;
}
void CfgWriteBool(const wchar_t *Section, const wchar_t *Name, bool Value)
{
setIni(Section);
spuConfig->Write(Name, Value);
}
void CfgWriteInt(const wchar_t *Section, const wchar_t *Name, int Value)
{
setIni(Section);
spuConfig->Write(Name, Value);
}
void CfgWriteFloat(const wchar_t *Section, const wchar_t *Name, float Value)
{
setIni(Section);
spuConfig->Write(Name, (double)Value);
}
void CfgWriteStr(const wchar_t *Section, const wchar_t *Name, const wxString &Data)
{
setIni(Section);
spuConfig->Write(Name, Data);
}
bool CfgReadBool(const wchar_t *Section, const wchar_t *Name, bool Default)
{
bool ret;
setIni(Section);
spuConfig->Read(Name, &ret, Default);
return ret;
}
int CfgReadInt(const wchar_t *Section, const wchar_t *Name, int Default)
{
int ret;
setIni(Section);
spuConfig->Read(Name, &ret, Default);
return ret;
}
float CfgReadFloat(const wchar_t *Section, const wchar_t *Name, float Default)
{
double ret;
setIni(Section);
spuConfig->Read(Name, &ret, (double)Default);
return (float)ret;
}
void CfgReadStr(const wchar_t *Section, const wchar_t *Name, wchar_t *Data, int DataSize, const wchar_t *Default)
{
setIni(Section);
wcscpy(Data, spuConfig->Read(Name, Default).wc_str());
}
void CfgReadStr(const wchar_t *Section, const wchar_t *Name, wxString &Data, const wchar_t *Default)
{
setIni(Section);
Data = spuConfig->Read(Name, Default);
}

View File

@ -1,233 +0,0 @@
/* 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 "Dialogs.h"
#include "Config.h"
#if defined(__unix__) || defined(__APPLE__)
#include <SDL.h>
#include <SDL_audio.h>
#include "wx/wxConfig.h"
#endif
int AutoDMAPlayRate[2] = {0, 0};
// Default settings.
// MIXING
int Interpolation = 4;
/* values:
0: no interpolation (use nearest)
1. linear interpolation
2. cubic interpolation
3. hermite interpolation
4. catmull-rom interpolation
*/
bool EffectsDisabled = false;
float FinalVolume; // global
bool AdvancedVolumeControl;
float VolumeAdjustFLdb; // decibels settings, cos audiophiles love that
float VolumeAdjustCdb;
float VolumeAdjustFRdb;
float VolumeAdjustBLdb;
float VolumeAdjustBRdb;
float VolumeAdjustSLdb;
float VolumeAdjustSRdb;
float VolumeAdjustLFEdb;
float VolumeAdjustFL; // linear coefs calculated from decibels,
float VolumeAdjustC;
float VolumeAdjustFR;
float VolumeAdjustBL;
float VolumeAdjustBR;
float VolumeAdjustSL;
float VolumeAdjustSR;
float VolumeAdjustLFE;
unsigned int delayCycles;
bool postprocess_filter_enabled = true;
bool postprocess_filter_dealias = false;
bool _visual_debug_enabled = false; // windows only feature
// OUTPUT
u32 OutputModule = 0;
int SndOutLatencyMS = 300;
int SynchMode = 0; // Time Stretch, Async or Disabled
#ifdef SPU2X_PORTAUDIO
u32 OutputAPI = 0;
#endif
u32 SdlOutputAPI = 0;
int numSpeakers = 0;
int dplLevel = 0;
bool temp_debug_state;
/*****************************************************************************/
void ReadSettings()
{
// For some reason this can be called before we know what ini file we're writing to.
// Lets not try to read it if that happens.
if (!pathSet) {
FileLog("Read called without the path set.\n");
return;
}
Interpolation = CfgReadInt(L"MIXING", L"Interpolation", 4);
EffectsDisabled = CfgReadBool(L"MIXING", L"Disable_Effects", false);
postprocess_filter_dealias = CfgReadBool(L"MIXING", L"DealiasFilter", false);
FinalVolume = ((float)CfgReadInt(L"MIXING", L"FinalVolume", 100)) / 100;
if (FinalVolume > 1.0f)
FinalVolume = 1.0f;
AdvancedVolumeControl = CfgReadBool(L"MIXING", L"AdvancedVolumeControl", false);
VolumeAdjustCdb = CfgReadFloat(L"MIXING", L"VolumeAdjustC(dB)", 0);
VolumeAdjustFLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustFL(dB)", 0);
VolumeAdjustFRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustFR(dB)", 0);
VolumeAdjustBLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustBL(dB)", 0);
VolumeAdjustBRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustBR(dB)", 0);
VolumeAdjustSLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustSL(dB)", 0);
VolumeAdjustSRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustSR(dB)", 0);
VolumeAdjustLFEdb = CfgReadFloat(L"MIXING", L"VolumeAdjustLFE(dB)", 0);
VolumeAdjustC = powf(10, VolumeAdjustCdb / 10);
VolumeAdjustFL = powf(10, VolumeAdjustFLdb / 10);
VolumeAdjustFR = powf(10, VolumeAdjustFRdb / 10);
VolumeAdjustBL = powf(10, VolumeAdjustBLdb / 10);
VolumeAdjustBR = powf(10, VolumeAdjustBRdb / 10);
VolumeAdjustSL = powf(10, VolumeAdjustSLdb / 10);
VolumeAdjustSR = powf(10, VolumeAdjustSRdb / 10);
VolumeAdjustLFE = powf(10, VolumeAdjustLFEdb / 10);
delayCycles = CfgReadInt(L"DEBUG", L"DelayCycles", 4);
wxString temp;
#if SDL_MAJOR_VERSION >= 2 || !defined(SPU2X_PORTAUDIO)
CfgReadStr(L"OUTPUT", L"Output_Module", temp, SDLOut->GetIdent());
#else
CfgReadStr(L"OUTPUT", L"Output_Module", temp, PortaudioOut->GetIdent());
#endif
OutputModule = FindOutputModuleById(temp.c_str()); // find the driver index of this module
// find current API
#ifdef SPU2X_PORTAUDIO
#ifdef __linux__
CfgReadStr(L"PORTAUDIO", L"HostApi", temp, L"ALSA");
if (temp == L"OSS")
OutputAPI = 1;
else if (temp == L"JACK")
OutputAPI = 2;
else // L"ALSA"
OutputAPI = 0;
#else
CfgReadStr(L"PORTAUDIO", L"HostApi", temp, L"OSS");
OutputAPI = 0; // L"OSS"
#endif
#endif
#if defined(__unix__) || defined(__APPLE__)
CfgReadStr(L"SDL", L"HostApi", temp, L"pulseaudio");
SdlOutputAPI = 0;
#if SDL_MAJOR_VERSION >= 2
// YES It sucks ...
for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
if (!temp.Cmp(wxString(SDL_GetAudioDriver(i), wxConvUTF8)))
SdlOutputAPI = i;
}
#endif
#endif
SndOutLatencyMS = CfgReadInt(L"OUTPUT", L"Latency", 300);
SynchMode = CfgReadInt(L"OUTPUT", L"Synch_Mode", 0);
numSpeakers = CfgReadInt(L"OUTPUT", L"SpeakerConfiguration", 0);
#ifdef SPU2X_PORTAUDIO
PortaudioOut->ReadSettings();
#endif
#if defined(__unix__) || defined(__APPLE__)
SDLOut->ReadSettings();
#endif
SoundtouchCfg::ReadSettings();
DebugConfig::ReadSettings();
// Sanity Checks
// -------------
Clampify(SndOutLatencyMS, LATENCY_MIN, LATENCY_MAX);
if (mods[OutputModule] == nullptr) {
fwprintf(stderr, L"* SPU2-X: Unknown output module '%s' specified in configuration file.\n", temp.wc_str());
fprintf(stderr, "* SPU2-X: Defaulting to SDL (%S).\n", SDLOut->GetIdent());
OutputModule = FindOutputModuleById(SDLOut->GetIdent());
}
WriteSettings();
spuConfig->Flush();
}
/*****************************************************************************/
void WriteSettings()
{
if (!pathSet) {
FileLog("Write called without the path set.\n");
return;
}
CfgWriteInt(L"MIXING", L"Interpolation", Interpolation);
CfgWriteBool(L"MIXING", L"Disable_Effects", EffectsDisabled);
CfgWriteBool(L"MIXING", L"DealiasFilter", postprocess_filter_dealias);
CfgWriteInt(L"MIXING", L"FinalVolume", (int)(FinalVolume * 100 + 0.5f));
CfgWriteBool(L"MIXING", L"AdvancedVolumeControl", AdvancedVolumeControl);
CfgWriteFloat(L"MIXING", L"VolumeAdjustC(dB)", VolumeAdjustCdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustFL(dB)", VolumeAdjustFLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustFR(dB)", VolumeAdjustFRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustBL(dB)", VolumeAdjustBLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustBR(dB)", VolumeAdjustBRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustSL(dB)", VolumeAdjustSLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustSR(dB)", VolumeAdjustSRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustLFE(dB)", VolumeAdjustLFEdb);
CfgWriteStr(L"OUTPUT", L"Output_Module", mods[OutputModule]->GetIdent());
CfgWriteInt(L"OUTPUT", L"Latency", SndOutLatencyMS);
CfgWriteInt(L"OUTPUT", L"Synch_Mode", SynchMode);
CfgWriteInt(L"OUTPUT", L"SpeakerConfiguration", numSpeakers);
CfgWriteInt(L"DEBUG", L"DelayCycles", delayCycles);
#ifdef SPU2X_PORTAUDIO
PortaudioOut->WriteSettings();
#endif
#if defined(__unix__) || defined(__APPLE__)
SDLOut->WriteSettings();
#endif
SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings();
}
void configure()
{
auto *dialog = new Dialog;
initIni();
ReadSettings();
dialog->Display();
WriteSettings();
delete spuConfig;
spuConfig = nullptr;
wxDELETE(dialog);
}

View File

@ -1,127 +0,0 @@
/* 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/>.
*/
#ifndef CONFIG_H_INCLUDED
#define CONFIG_H_INCLUDED
#include <string>
#include <wx/fileconf.h>
extern bool DebugEnabled;
extern bool _MsgToConsole;
extern bool _MsgKeyOnOff;
extern bool _MsgVoiceOff;
extern bool _MsgDMA;
extern bool _MsgAutoDMA;
extern bool _MsgOverruns;
extern bool _MsgCache;
extern bool _AccessLog;
extern bool _DMALog;
extern bool _WaveLog;
extern bool _CoresDump;
extern bool _MemDump;
extern bool _RegDump;
extern bool _visual_debug_enabled;
/*static __forceinline bool MsgToConsole() { return _MsgToConsole & DebugEnabled; }
static __forceinline bool MsgKeyOnOff() { return _MsgKeyOnOff & MsgToConsole(); }
static __forceinline bool MsgVoiceOff() { return _MsgVoiceOff & MsgToConsole(); }
static __forceinline bool MsgDMA() { return _MsgDMA & MsgToConsole(); }
static __forceinline bool MsgAutoDMA() { return _MsgAutoDMA & MsgDMA(); }
static __forceinline bool MsgOverruns() { return _MsgOverruns & MsgToConsole(); }
static __forceinline bool MsgCache() { return _MsgCache & MsgToConsole(); }
static __forceinline bool AccessLog() { return _AccessLog & DebugEnabled; }
static __forceinline bool DMALog() { return _DMALog & DebugEnabled; }
static __forceinline bool WaveLog() { return _WaveLog & DebugEnabled; }
static __forceinline bool CoresDump() { return _CoresDump & DebugEnabled; }
static __forceinline bool MemDump() { return _MemDump & DebugEnabled; }
static __forceinline bool RegDump() { return _RegDump & DebugEnabled; }*/
//extern wchar_t AccessLogFileName[255];
//extern wchar_t WaveLogFileName[255];
//extern wchar_t DMA4LogFileName[255];
//extern wchar_t DMA7LogFileName[255];
//extern wchar_t CoresDumpFileName[255];
//extern wchar_t MemDumpFileName[255];
//extern wchar_t RegDumpFileName[255];
extern int Interpolation;
extern bool EffectsDisabled;
extern float FinalVolume;
extern bool postprocess_filter_enabled;
extern bool postprocess_filter_dealias;
extern int AutoDMAPlayRate[2];
extern u32 OutputModule;
extern int SndOutLatencyMS;
extern wchar_t dspPlugin[];
extern int dspPluginModule;
extern bool dspPluginEnabled;
extern int SynchMode;
#ifdef SPU2X_PORTAUDIO
extern u32 OutputAPI;
#endif
extern u32 SdlOutputAPI;
#ifdef PCSX2_DEVBUILD
const int LATENCY_MAX = 3000;
#else
const int LATENCY_MAX = 750;
#endif
const int LATENCY_MIN = 3;
const int LATENCY_MIN_TIMESTRETCH = 15;
namespace SoundtouchCfg
{
extern const int SequenceLen_Min;
extern const int SequenceLen_Max;
extern const int SeekWindow_Min;
extern const int SeekWindow_Max;
extern const int Overlap_Min;
extern const int Overlap_Max;
extern int SequenceLenMS;
extern int SeekWindowMS;
extern int OverlapMS;
void ReadSettings();
void WriteSettings();
}; // namespace SoundtouchCfg
void ReadSettings();
void WriteSettings();
void DisplayDialog();
void configure();
extern wxFileConfig *spuConfig;
extern bool pathSet;
extern void initIni();
#endif // CONFIG_H_INCLUDED

View File

@ -1,157 +0,0 @@
/* 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 "Dialogs.h"
#include "Config.h"
#include "Utilities/Path.h"
bool DebugEnabled = false;
bool _MsgToConsole = false;
bool _MsgKeyOnOff = false;
bool _MsgVoiceOff = false;
bool _MsgDMA = false;
bool _MsgAutoDMA = false;
bool _MsgOverruns = false;
bool _MsgCache = false;
bool _AccessLog = false;
bool _DMALog = false;
bool _WaveLog = false;
bool _CoresDump = false;
bool _MemDump = false;
bool _RegDump = false;
// this is set true if PCSX2 invokes the SetLogDir callback, which tells SPU2-X to use that over
// the configured crap in the ini file.
static bool LogLocationSetByPcsx2 = false;
static wxDirName LogsFolder;
static wxDirName DumpsFolder;
wxString AccessLogFileName;
wxString WaveLogFileName;
wxString DMA4LogFileName;
wxString DMA7LogFileName;
wxString CoresDumpFileName;
wxString MemDumpFileName;
wxString RegDumpFileName;
void CfgSetLogDir(const char *dir)
{
LogsFolder = (dir == NULL) ? wxString(L"logs") : fromUTF8(dir);
DumpsFolder = (dir == NULL) ? wxString(L"logs") : fromUTF8(dir);
LogLocationSetByPcsx2 = (dir != NULL);
}
FILE *OpenBinaryLog(const wxString &logfile)
{
return wxFopen(Path::Combine(LogsFolder, logfile), L"wb");
}
FILE *OpenLog(const wxString &logfile)
{
return wxFopen(Path::Combine(LogsFolder, logfile), L"w");
}
FILE *OpenDump(const wxString &logfile)
{
return wxFopen(Path::Combine(DumpsFolder, logfile), L"w");
}
namespace DebugConfig
{
static const wchar_t *Section = L"DEBUG";
static void set_default_filenames()
{
AccessLogFileName = L"SPU2Log.txt";
WaveLogFileName = L"SPU2log.wav";
DMA4LogFileName = L"SPU2dma4.dat";
DMA7LogFileName = L"SPU2dma7.dat";
CoresDumpFileName = L"SPU2Cores.txt";
MemDumpFileName = L"SPU2mem.dat";
RegDumpFileName = L"SPU2regs.dat";
}
void ReadSettings()
{
DebugEnabled = CfgReadBool(Section, L"Global_Enable", 0);
_MsgToConsole = CfgReadBool(Section, L"Show_Messages", 0);
_MsgKeyOnOff = CfgReadBool(Section, L"Show_Messages_Key_On_Off", 0);
_MsgVoiceOff = CfgReadBool(Section, L"Show_Messages_Voice_Off", 0);
_MsgDMA = CfgReadBool(Section, L"Show_Messages_DMA_Transfer", 0);
_MsgAutoDMA = CfgReadBool(Section, L"Show_Messages_AutoDMA", 0);
_MsgOverruns = CfgReadBool(Section, L"Show_Messages_Overruns", 0);
_MsgCache = CfgReadBool(Section, L"Show_Messages_CacheStats", 0);
_AccessLog = CfgReadBool(Section, L"Log_Register_Access", 0);
_DMALog = CfgReadBool(Section, L"Log_DMA_Transfers", 0);
_WaveLog = CfgReadBool(Section, L"Log_WAVE_Output", 0);
_CoresDump = CfgReadBool(Section, L"Dump_Info", 0);
_MemDump = CfgReadBool(Section, L"Dump_Memory", 0);
_RegDump = CfgReadBool(Section, L"Dump_Regs", 0);
set_default_filenames();
CfgReadStr(Section, L"Access_Log_Filename", AccessLogFileName, L"logs/SPU2Log.txt");
CfgReadStr(Section, L"WaveLog_Filename", WaveLogFileName, L"logs/SPU2log.wav");
CfgReadStr(Section, L"DMA4Log_Filename", DMA4LogFileName, L"logs/SPU2dma4.dat");
CfgReadStr(Section, L"DMA7Log_Filename", DMA7LogFileName, L"logs/SPU2dma7.dat");
CfgReadStr(Section, L"Info_Dump_Filename", CoresDumpFileName, L"logs/SPU2Cores.txt");
CfgReadStr(Section, L"Mem_Dump_Filename", MemDumpFileName, L"logs/SPU2mem.dat");
CfgReadStr(Section, L"Reg_Dump_Filename", RegDumpFileName, L"logs/SPU2regs.dat");
}
void WriteSettings()
{
CfgWriteBool(Section, L"Global_Enable", DebugEnabled);
CfgWriteBool(Section, L"Show_Messages", _MsgToConsole);
CfgWriteBool(Section, L"Show_Messages_Key_On_Off", _MsgKeyOnOff);
CfgWriteBool(Section, L"Show_Messages_Voice_Off", _MsgVoiceOff);
CfgWriteBool(Section, L"Show_Messages_DMA_Transfer", _MsgDMA);
CfgWriteBool(Section, L"Show_Messages_AutoDMA", _MsgAutoDMA);
CfgWriteBool(Section, L"Show_Messages_Overruns", _MsgOverruns);
CfgWriteBool(Section, L"Show_Messages_CacheStats", _MsgCache);
CfgWriteBool(Section, L"Log_Register_Access", _AccessLog);
CfgWriteBool(Section, L"Log_DMA_Transfers", _DMALog);
CfgWriteBool(Section, L"Log_WAVE_Output", _WaveLog);
CfgWriteBool(Section, L"Dump_Info", _CoresDump);
CfgWriteBool(Section, L"Dump_Memory", _MemDump);
CfgWriteBool(Section, L"Dump_Regs", _RegDump);
set_default_filenames();
CfgWriteStr(Section, L"Access_Log_Filename", AccessLogFileName);
CfgWriteStr(Section, L"WaveLog_Filename", WaveLogFileName);
CfgWriteStr(Section, L"DMA4Log_Filename", DMA4LogFileName);
CfgWriteStr(Section, L"DMA7Log_Filename", DMA7LogFileName);
CfgWriteStr(Section, L"Info_Dump_Filename", CoresDumpFileName);
CfgWriteStr(Section, L"Mem_Dump_Filename", MemDumpFileName);
CfgWriteStr(Section, L"Reg_Dump_Filename", RegDumpFileName);
}
} // namespace DebugConfig

View File

@ -1,74 +0,0 @@
/* 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]
*
* 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
* 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 "Dialogs.h"
#include "Config.h"
#include "soundtouch/SoundTouch.h"
namespace SoundtouchCfg
{
// Timestretch Slider Bounds, Min/Max
const int SequenceLen_Min = 20;
const int SequenceLen_Max = 100;
const int SeekWindow_Min = 10;
const int SeekWindow_Max = 30;
const int Overlap_Min = 5;
const int Overlap_Max = 15;
int SequenceLenMS = 30;
int SeekWindowMS = 20;
int OverlapMS = 10;
static void ClampValues()
{
Clampify(SequenceLenMS, SequenceLen_Min, SequenceLen_Max);
Clampify(SeekWindowMS, SeekWindow_Min, SeekWindow_Max);
Clampify(OverlapMS, Overlap_Min, Overlap_Max);
}
void ApplySettings(soundtouch::SoundTouch &sndtouch)
{
sndtouch.setSetting(SETTING_SEQUENCE_MS, SequenceLenMS);
sndtouch.setSetting(SETTING_SEEKWINDOW_MS, SeekWindowMS);
sndtouch.setSetting(SETTING_OVERLAP_MS, OverlapMS);
}
void ReadSettings()
{
SequenceLenMS = CfgReadInt(L"SOUNDTOUCH", L"SequenceLengthMS", 30);
SeekWindowMS = CfgReadInt(L"SOUNDTOUCH", L"SeekWindowMS", 20);
OverlapMS = CfgReadInt(L"SOUNDTOUCH", L"OverlapMS", 10);
ClampValues();
WriteSettings();
}
void WriteSettings()
{
CfgWriteInt(L"SOUNDTOUCH", L"SequenceLengthMS", SequenceLenMS);
CfgWriteInt(L"SOUNDTOUCH", L"SeekWindowMS", SeekWindowMS);
CfgWriteInt(L"SOUNDTOUCH", L"OverlapMS", OverlapMS);
}
} // namespace SoundtouchCfg

View File

@ -1,62 +0,0 @@
/* 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/>.
*/
// To be continued...
#include "Dialogs.h"
#include <cstring>
#if defined(__unix__)
#include <wx/wx.h>
void SysMessage(const char *fmt, ...)
{
va_list list;
char msg[512];
va_start(list, fmt);
vsprintf(msg, fmt, list);
va_end(list);
if (msg[strlen(msg) - 1] == '\n')
msg[strlen(msg) - 1] = 0;
wxMessageDialog dialog(nullptr, msg, "Info", wxOK);
dialog.ShowModal();
}
void SysMessage(const wchar_t *fmt, ...)
{
va_list list;
va_start(list, fmt);
wxString msg;
msg.PrintfV(fmt, list);
va_end(list);
wxMessageDialog dialog(nullptr, msg, "Info", wxOK);
dialog.ShowModal();
}
#endif
void DspUpdate()
{
}
s32 DspLoadLibrary(wchar_t *fileName, int modnum)
{
return 0;
}

View File

@ -1,44 +0,0 @@
/* 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/>.
*/
#ifndef DIALOG_H_INCLUDED
#define DIALOG_H_INCLUDED
#include "../Global.h"
#include "../Config.h"
namespace DebugConfig
{
extern void ReadSettings();
extern void WriteSettings();
} // namespace DebugConfig
extern void CfgSetSettingsDir(const char *dir);
extern void CfgSetLogDir(const char *dir);
extern void CfgWriteBool(const wchar_t *Section, const wchar_t *Name, bool Value);
extern void CfgWriteInt(const wchar_t *Section, const wchar_t *Name, int Value);
extern void CfgWriteFloat(const wchar_t *Section, const wchar_t *Name, float Value);
extern void CfgWriteStr(const wchar_t *Section, const wchar_t *Name, const wxString &Data);
extern bool CfgReadBool(const wchar_t *Section, const wchar_t *Name, bool Default);
extern void CfgReadStr(const wchar_t *Section, const wchar_t *Name, wxString &Data, const wchar_t *Default);
//extern void CfgReadStr(const wchar_t* Section, const wchar_t* Name, wchar_t* Data, int DataSize, const wchar_t* Default);
extern int CfgReadInt(const wchar_t *Section, const wchar_t *Name, int Default);
extern float CfgReadFloat(const wchar_t *Section, const wchar_t *Name, float Default);
#endif

View File

@ -1,94 +0,0 @@
/* 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 "Lowpass.h"
#include <math.h>
#include <float.h>
template <typename FloatType>
__forceinline LowPassFilter<FloatType>::LowPassFilter(FloatType freq, FloatType srate)
{
typedef FloatType FT;
FloatType omega = (FT)2.0 * freq / srate;
static const FloatType g = (FT)1.0;
// calculating coefficients:
FloatType k, p, q, a;
FloatType a0, a1, a2, a3, a4;
k = ((FT)4.0 * g - (FT)3.0) / (g + (FT)1.0);
p = (FT)1.0 - (FT)0.25 * k;
p *= p;
// LP:
a = (FT)1.0 / (tan((FT)0.5 * omega) * ((FT)1.0 + p));
p = (FT)1.0 + a;
q = (FT)1.0 - a;
a0 = (FT)1.0 / (k + p * p * p * p);
a1 = (FT)4.0 * (k + p * p * p * q);
a2 = (FT)6.0 * (k + p * p * q * q);
a3 = (FT)4.0 * (k + p * q * q * q);
a4 = (k + q * q * q * q);
p = a0 * (k + (FT)1.0);
coef[0] = p;
coef[1] = (FT)4.0 * p;
coef[2] = (FT)6.0 * p;
coef[3] = (FT)4.0 * p;
coef[4] = p;
coef[5] = -a1 * a0;
coef[6] = -a2 * a0;
coef[7] = -a3 * a0;
coef[8] = -a4 * a0;
}
// Processes a single sample into the LPF.
template <typename FloatType>
__forceinline FloatType LowPassFilter<FloatType>::sample(FloatType inval)
{
const FloatType out = (coef[0] * inval) + d[0];
d[0] = (coef[1] * inval) + (coef[5] * out) + d[1];
d[1] = (coef[2] * inval) + (coef[6] * out) + d[2];
d[2] = (coef[3] * inval) + (coef[7] * out) + d[3];
d[3] = (coef[4] * inval) + (coef[8] * out);
return out;
}
LowPassFilter32::LowPassFilter32(float freq, float srate)
: impl_lpf(freq, srate)
{
}
LowPassFilter64::LowPassFilter64(double freq, double srate)
: impl_lpf(freq, srate)
{
}
float LowPassFilter32::sample(float inval)
{
return impl_lpf.sample(inval);
}
double LowPassFilter64::sample(double inval)
{
return impl_lpf.sample(inval);
}

View File

@ -1,44 +0,0 @@
/* 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
template <typename FloatType>
struct LowPassFilter
{
FloatType coef[9];
FloatType d[4];
LowPassFilter(FloatType freq, FloatType srate);
FloatType sample(FloatType inval);
};
struct LowPassFilter32
{
LowPassFilter<float> impl_lpf;
LowPassFilter32(float freq, float srate);
float sample(float inval);
};
struct LowPassFilter64
{
LowPassFilter<double> impl_lpf;
LowPassFilter64(double freq, double srate);
double sample(double inval);
};

View File

@ -1,880 +0,0 @@
/* 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"
// Games have turned out to be surprisingly sensitive to whether a parked, silent voice is being fully emulated.
// With Silent Hill: Shattered Memories requiring full processing for no obvious reason, we've decided to
// disable the optimisation until we can tie it to the game database.
#define NEVER_SKIP_VOICES 1
void ADMAOutLogWrite(void *lpData, u32 ulSize);
static const s32 tbl_XA_Factor[16][2] =
{
{0, 0},
{60, 0},
{115, -52},
{98, -55},
{122, -60}};
// Performs a 64-bit multiplication between two values and returns the
// high 32 bits as a result (discarding the fractional 32 bits).
// The combined fractional bits of both inputs must be 32 bits for this
// to work properly.
//
// This is meant to be a drop-in replacement for times when the 'div' part
// of a MulDiv is a constant. (example: 1<<8, or 4096, etc)
//
// [Air] Performance breakdown: This is over 10 times faster than MulDiv in
// a *worst case* scenario. It's also more accurate since it forces the
// caller to extend the inputs so that they make use of all 32 bits of
// precision.
//
static __forceinline s32 MulShr32(s32 srcval, s32 mulval)
{
return (s64)srcval * mulval >> 32;
}
__forceinline s32 clamp_mix(s32 x, u8 bitshift)
{
assert(bitshift <= 15);
return GetClamped(x, -(0x8000 << bitshift), 0x7fff << bitshift);
}
#if _MSC_VER
__forceinline
// Without the keyword static, gcc compilation fails on the inlining...
// Unfortunately the function is also used in Reverb.cpp. In order to keep the code
// clean we just disable it.
// We will need link-time code generation / Whole Program optimization to do a clean
// inline. Gcc 4.5 has the experimental options -flto, -fwhopr and -fwhole-program to
// do it but it still experimental...
#endif
StereoOut32
clamp_mix(const StereoOut32 &sample, u8 bitshift)
{
// We should clampify between -0x8000 and 0x7fff, however some audio output
// modules or sound drivers could (will :p) overshoot with that. So giving it a small safety.
return StereoOut32(
GetClamped(sample.Left, -(0x7f00 << bitshift), 0x7f00 << bitshift),
GetClamped(sample.Right, -(0x7f00 << bitshift), 0x7f00 << bitshift));
}
static void __forceinline XA_decode_block(s16 *buffer, const s16 *block, s32 &prev1, s32 &prev2)
{
const s32 header = *block;
const s32 shift = (header & 0xF) + 16;
const int id = header >> 4 & 0xF;
if (id > 4 && MsgToConsole())
ConLog("* SPU2-X: Unknown ADPCM coefficients table id %d\n", id);
const s32 pred1 = tbl_XA_Factor[id][0];
const s32 pred2 = tbl_XA_Factor[id][1];
const s8 *blockbytes = (s8 *)&block[1];
const s8 *blockend = &blockbytes[13];
for (; blockbytes <= blockend; ++blockbytes) {
s32 data = ((*blockbytes) << 28) & 0xF0000000;
s32 pcm = (data >> shift) + (((pred1 * prev1) + (pred2 * prev2) + 32) >> 6);
Clampify(pcm, -0x8000, 0x7fff);
*(buffer++) = pcm;
data = ((*blockbytes) << 24) & 0xF0000000;
s32 pcm2 = (data >> shift) + (((pred1 * pcm) + (pred2 * prev1) + 32) >> 6);
Clampify(pcm2, -0x8000, 0x7fff);
*(buffer++) = pcm2;
prev2 = pcm;
prev1 = pcm2;
}
}
static void __forceinline IncrementNextA(V_Core &thiscore, uint voiceidx)
{
V_Voice &vc(thiscore.Voices[voiceidx]);
// Important! Both cores signal IRQ when an address is read, regardless of
// which core actually reads the address.
for (int i = 0; i < 2; i++) {
if (Cores[i].IRQEnable && (vc.NextA == Cores[i].IRQA)) {
//if( IsDevBuild )
// ConLog(" * SPU2 Core %d: IRQ Requested (IRQA (%05X) passed; voice %d).\n", i, Cores[i].IRQA, thiscore.Index * 24 + voiceidx);
SetIrqCall(i);
}
}
vc.NextA++;
vc.NextA &= 0xFFFFF;
}
// decoded pcm data, used to cache the decoded data so that it needn't be decoded
// multiple times. Cache chunks are decoded when the mixer requests the blocks, and
// invalided when DMA transfers and memory writes are performed.
PcmCacheEntry *pcm_cache_data = NULL;
int g_counter_cache_hits = 0;
int g_counter_cache_misses = 0;
int g_counter_cache_ignores = 0;
// LOOP/END sets the ENDX bit and sets NAX to LSA, and the voice is muted if LOOP is not set
// LOOP seems to only have any effect on the block with LOOP/END set, where it prevents muting the voice
// (the documented requirement that every block in a loop has the LOOP bit set is nonsense according to tests)
// LOOP/START sets LSA to NAX unless LSA was written manually since sound generation started
// (see LoopMode, the method by which this is achieved on the real SPU2 is unknown)
#define XAFLAG_LOOP_END (1ul << 0)
#define XAFLAG_LOOP (1ul << 1)
#define XAFLAG_LOOP_START (1ul << 2)
static __forceinline s32 GetNextDataBuffered(V_Core &thiscore, uint voiceidx)
{
V_Voice &vc(thiscore.Voices[voiceidx]);
if ((vc.SCurrent & 3) == 0) {
IncrementNextA(thiscore, voiceidx);
if ((vc.NextA & 7) == 0) // vc.SCurrent == 24 equivalent
{
if (vc.LoopFlags & XAFLAG_LOOP_END) {
thiscore.Regs.ENDX |= (1 << voiceidx);
vc.NextA = vc.LoopStartA | 1;
if (!(vc.LoopFlags & XAFLAG_LOOP)) {
vc.Stop();
if (IsDevBuild) {
if (MsgVoiceOff())
ConLog("* SPU2-X: Voice Off by EndPoint: %d \n", voiceidx);
}
}
} else
vc.NextA++; // no, don't IncrementNextA here. We haven't read the header yet.
}
}
if (vc.SCurrent == 28) {
vc.SCurrent = 0;
// We'll need the loop flags and buffer pointers regardless of cache status:
for (int i = 0; i < 2; i++)
if (Cores[i].IRQEnable && Cores[i].IRQA == (vc.NextA & 0xFFFF8))
SetIrqCall(i);
s16 *memptr = GetMemPtr(vc.NextA & 0xFFFF8);
vc.LoopFlags = *memptr >> 8; // grab loop flags from the upper byte.
if ((vc.LoopFlags & XAFLAG_LOOP_START) && !vc.LoopMode)
vc.LoopStartA = vc.NextA & 0xFFFF8;
const int cacheIdx = vc.NextA / pcm_WordsPerBlock;
PcmCacheEntry &cacheLine = pcm_cache_data[cacheIdx];
vc.SBuffer = cacheLine.Sampledata;
if (cacheLine.Validated) {
// Cached block! Read from the cache directly.
// Make sure to propagate the prev1/prev2 ADPCM:
vc.Prev1 = vc.SBuffer[27];
vc.Prev2 = vc.SBuffer[26];
//ConLog( "* SPU2-X: Cache Hit! NextA=0x%x, cacheIdx=0x%x\n", vc.NextA, cacheIdx );
if (IsDevBuild)
g_counter_cache_hits++;
} else {
// Only flag the cache if it's a non-dynamic memory range.
if (vc.NextA >= SPU2_DYN_MEMLINE)
cacheLine.Validated = true;
if (IsDevBuild) {
if (vc.NextA < SPU2_DYN_MEMLINE)
g_counter_cache_ignores++;
else
g_counter_cache_misses++;
}
XA_decode_block(vc.SBuffer, memptr, vc.Prev1, vc.Prev2);
}
}
return vc.SBuffer[vc.SCurrent++];
}
static __forceinline void GetNextDataDummy(V_Core &thiscore, uint voiceidx)
{
V_Voice &vc(thiscore.Voices[voiceidx]);
IncrementNextA(thiscore, voiceidx);
if ((vc.NextA & 7) == 0) // vc.SCurrent == 24 equivalent
{
if (vc.LoopFlags & XAFLAG_LOOP_END) {
thiscore.Regs.ENDX |= (1 << voiceidx);
vc.NextA = vc.LoopStartA | 1;
} else
vc.NextA++; // no, don't IncrementNextA here. We haven't read the header yet.
}
if (vc.SCurrent == 28) {
for (int i = 0; i < 2; i++)
if (Cores[i].IRQEnable && Cores[i].IRQA == (vc.NextA & 0xFFFF8))
SetIrqCall(i);
vc.LoopFlags = *GetMemPtr(vc.NextA & 0xFFFF8) >> 8; // grab loop flags from the upper byte.
if ((vc.LoopFlags & XAFLAG_LOOP_START) && !vc.LoopMode)
vc.LoopStartA = vc.NextA & 0xFFFF8;
vc.SCurrent = 0;
}
vc.SP -= 4096 * (4 - (vc.SCurrent & 3));
vc.SCurrent += 4 - (vc.SCurrent & 3);
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
static s32 __forceinline GetNoiseValues()
{
static u16 lfsr = 0xC0FEu;
u16 bit = lfsr ^ (lfsr << 3) ^ (lfsr << 4) ^ (lfsr << 5);
lfsr = (lfsr << 1) | (bit >> 15);
return (s16)lfsr;
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// //
// Data is expected to be 16 bit signed (typical stuff!).
// volume is expected to be 32 bit signed (31 bits with reverse phase)
// Data is shifted up by 1 bit to give the output an effective 16 bit range.
static __forceinline s32 ApplyVolume(s32 data, s32 volume)
{
//return (volume * data) >> 15;
return MulShr32(data << 1, volume);
}
static __forceinline StereoOut32 ApplyVolume(const StereoOut32 &data, const V_VolumeLR &volume)
{
return StereoOut32(
ApplyVolume(data.Left, volume.Left),
ApplyVolume(data.Right, volume.Right));
}
static __forceinline StereoOut32 ApplyVolume(const StereoOut32 &data, const V_VolumeSlideLR &volume)
{
return StereoOut32(
ApplyVolume(data.Left, volume.Left.Value),
ApplyVolume(data.Right, volume.Right.Value));
}
static void __forceinline UpdatePitch(uint coreidx, uint voiceidx)
{
V_Voice &vc(Cores[coreidx].Voices[voiceidx]);
s32 pitch;
// [Air] : re-ordered comparisons: Modulated is much more likely to be zero than voice,
// and so the way it was before it's have to check both voice and modulated values
// most of the time. Now it'll just check Modulated and short-circuit past the voice
// check (not that it amounts to much, but eh every little bit helps).
if ((vc.Modulated == 0) || (voiceidx == 0))
pitch = vc.Pitch;
else
pitch = GetClamped((vc.Pitch * (32768 + Cores[coreidx].Voices[voiceidx - 1].OutX)) >> 15, 0, 0x3fff);
vc.SP += pitch;
}
static __forceinline void CalculateADSR(V_Core &thiscore, uint voiceidx)
{
V_Voice &vc(thiscore.Voices[voiceidx]);
if (vc.ADSR.Phase == 0) {
vc.ADSR.Value = 0;
return;
}
if (!vc.ADSR.Calculate()) {
if (IsDevBuild) {
if (MsgVoiceOff())
ConLog("* SPU2-X: Voice Off by ADSR: %d \n", voiceidx);
}
vc.Stop();
}
pxAssume(vc.ADSR.Value >= 0); // ADSR should never be negative...
}
/*
Tension: 65535 is high, 32768 is normal, 0 is low
*/
template <s32 i_tension>
__forceinline static s32 HermiteInterpolate(
s32 y0, // 16.0
s32 y1, // 16.0
s32 y2, // 16.0
s32 y3, // 16.0
s32 mu // 0.12
)
{
s32 m00 = ((y1 - y0) * i_tension) >> 16; // 16.0
s32 m01 = ((y2 - y1) * i_tension) >> 16; // 16.0
s32 m0 = m00 + m01;
s32 m10 = ((y2 - y1) * i_tension) >> 16; // 16.0
s32 m11 = ((y3 - y2) * i_tension) >> 16; // 16.0
s32 m1 = m10 + m11;
s32 val = ((2 * y1 + m0 + m1 - 2 * y2) * mu) >> 12; // 16.0
val = ((val - 3 * y1 - 2 * m0 - m1 + 3 * y2) * mu) >> 12; // 16.0
val = ((val + m0) * mu) >> 11; // 16.0
return (val + (y1 << 1));
}
__forceinline static s32 CatmullRomInterpolate(
s32 y0, // 16.0
s32 y1, // 16.0
s32 y2, // 16.0
s32 y3, // 16.0
s32 mu // 0.12
)
{
//q(t) = 0.5 *( (2 * P1) +
// (-P0 + P2) * t +
// (2*P0 - 5*P1 + 4*P2 - P3) * t2 +
// (-P0 + 3*P1- 3*P2 + P3) * t3)
s32 a3 = (-y0 + 3 * y1 - 3 * y2 + y3);
s32 a2 = (2 * y0 - 5 * y1 + 4 * y2 - y3);
s32 a1 = (-y0 + y2);
s32 a0 = (2 * y1);
s32 val = ((a3)*mu) >> 12;
val = ((a2 + val) * mu) >> 12;
val = ((a1 + val) * mu) >> 12;
return (a0 + val);
}
__forceinline static s32 CubicInterpolate(
s32 y0, // 16.0
s32 y1, // 16.0
s32 y2, // 16.0
s32 y3, // 16.0
s32 mu // 0.12
)
{
const s32 a0 = y3 - y2 - y0 + y1;
const s32 a1 = y0 - y1 - a0;
const s32 a2 = y2 - y0;
s32 val = ((a0)*mu) >> 12;
val = ((val + a1) * mu) >> 12;
val = ((val + a2) * mu) >> 11;
return (val + (y1 << 1));
}
// Returns a 16 bit result in Value.
// Uses standard template-style optimization techniques to statically generate five different
// versions of this function (one for each type of interpolation).
template <int InterpType>
static __forceinline s32 GetVoiceValues(V_Core &thiscore, uint voiceidx)
{
V_Voice &vc(thiscore.Voices[voiceidx]);
while (vc.SP > 0) {
if (InterpType >= 2) {
vc.PV4 = vc.PV3;
vc.PV3 = vc.PV2;
}
vc.PV2 = vc.PV1;
vc.PV1 = GetNextDataBuffered(thiscore, voiceidx);
vc.SP -= 4096;
}
const s32 mu = vc.SP + 4096;
switch (InterpType) {
case 0:
return vc.PV1 << 1;
case 1:
return (vc.PV1 << 1) - (((vc.PV2 - vc.PV1) * vc.SP) >> 11);
case 2:
return CubicInterpolate(vc.PV4, vc.PV3, vc.PV2, vc.PV1, mu);
case 3:
return HermiteInterpolate<16384>(vc.PV4, vc.PV3, vc.PV2, vc.PV1, mu);
case 4:
return CatmullRomInterpolate(vc.PV4, vc.PV3, vc.PV2, vc.PV1, mu);
jNO_DEFAULT;
}
return 0; // technically unreachable!
}
// Noise values need to be mixed without going through interpolation, since it
// can wreak havoc on the noise (causing muffling or popping). Not that this noise
// generator is accurate in its own right.. but eh, ah well :)
static __forceinline s32 GetNoiseValues(V_Core &thiscore, uint voiceidx)
{
// V_Voice &vc(thiscore.Voices[voiceidx]);
s32 retval = GetNoiseValues();
/*while(vc.SP>=4096)
{
retval = GetNoiseValues();
vc.SP-=4096;
}*/
// GetNoiseValues can't set the phase zero on us unexpectedly
// like GetVoiceValues can. Better assert just in case though..
// pxAssume(vc.ADSR.Phase != 0);
return retval;
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// //
// writes a signed value to the SPU2 ram
// Performs no cache invalidation -- use only for dynamic memory ranges
// of the SPU2 (between 0x0000 and SPU2_DYN_MEMLINE)
static __forceinline void spu2M_WriteFast(u32 addr, s16 value)
{
// Fixes some of the oldest hangs in pcsx2's history! :p
for (int i = 0; i < 2; i++) {
if (Cores[i].IRQEnable && Cores[i].IRQA == addr) {
//printf("Core %d special write IRQ Called (IRQ passed). IRQA = %x\n",i,addr);
SetIrqCall(i);
}
}
// throw an assertion if the memory range is invalid:
#ifndef DEBUG_FAST
pxAssume(addr < SPU2_DYN_MEMLINE);
#endif
*GetMemPtr(addr) = value;
}
static __forceinline StereoOut32 MixVoice(uint coreidx, uint voiceidx)
{
V_Core &thiscore(Cores[coreidx]);
V_Voice &vc(thiscore.Voices[voiceidx]);
// If this assertion fails, it mans SCurrent is being corrupted somewhere, or is not initialized
// properly. Invalid values in SCurrent will cause errant IRQs and corrupted audio.
pxAssertMsg((vc.SCurrent <= 28) && (vc.SCurrent != 0), "Current sample should always range from 1->28");
// Most games don't use much volume slide effects. So only call the UpdateVolume
// methods when needed by checking the flag outside the method here...
// (Note: Ys 6 : Ark of Nephistm uses these effects)
vc.Volume.Update();
// SPU2 Note: The spu2 continues to process voices for eternity, always, so we
// have to run through all the motions of updating the voice regardless of it's
// audible status. Otherwise IRQs might not trigger and emulation might fail.
if (vc.ADSR.Phase > 0) {
UpdatePitch(coreidx, voiceidx);
s32 Value = 0;
if (vc.Noise)
Value = GetNoiseValues(thiscore, voiceidx);
else {
// Optimization : Forceinline'd Templated Dispatch Table. Any halfwit compiler will
// turn this into a clever jump dispatch table (no call/rets, no compares, uber-efficient!)
switch (Interpolation) {
case 0:
Value = GetVoiceValues<0>(thiscore, voiceidx);
break;
case 1:
Value = GetVoiceValues<1>(thiscore, voiceidx);
break;
case 2:
Value = GetVoiceValues<2>(thiscore, voiceidx);
break;
case 3:
Value = GetVoiceValues<3>(thiscore, voiceidx);
break;
case 4:
Value = GetVoiceValues<4>(thiscore, voiceidx);
break;
jNO_DEFAULT;
}
}
// Update and Apply ADSR (applies to normal and noise sources)
//
// Note! It's very important that ADSR stay as accurate as possible. By the way
// it is used, various sound effects can end prematurely if we truncate more than
// one or two bits. Best result comes from no truncation at all, which is why we
// use a full 64-bit multiply/result here.
CalculateADSR(thiscore, voiceidx);
Value = MulShr32(Value, vc.ADSR.Value);
// Store Value for eventual modulation later
// Pseudonym's Crest calculation idea. Actually calculates a crest, unlike the old code which was just peak.
if (vc.PV1 < vc.NextCrest) {
vc.OutX = MulShr32(vc.NextCrest, vc.ADSR.Value);
vc.NextCrest = -0x8000;
}
if (vc.PV1 > vc.PV2) {
vc.NextCrest = vc.PV1;
}
if (IsDevBuild)
DebugCores[coreidx].Voices[voiceidx].displayPeak = std::max(DebugCores[coreidx].Voices[voiceidx].displayPeak, (s32)vc.OutX);
// Write-back of raw voice data (post ADSR applied)
if (voiceidx == 1)
spu2M_WriteFast(((0 == coreidx) ? 0x400 : 0xc00) + OutPos, vc.OutX);
else if (voiceidx == 3)
spu2M_WriteFast(((0 == coreidx) ? 0x600 : 0xe00) + OutPos, vc.OutX);
return ApplyVolume(StereoOut32(Value, Value), vc.Volume);
} else {
// Continue processing voice, even if it's "off". Or else we miss interrupts! (Fatal Frame engine died because of this.)
if (NEVER_SKIP_VOICES || (*GetMemPtr(vc.NextA & 0xFFFF8) >> 8 & 3) != 3 || vc.LoopStartA != (vc.NextA & ~7) // not in a tight loop
|| (Cores[0].IRQEnable && (Cores[0].IRQA & ~7) == vc.LoopStartA) // or should be interrupting regularly
|| (Cores[1].IRQEnable && (Cores[1].IRQA & ~7) == vc.LoopStartA) || !(thiscore.Regs.ENDX & 1 << voiceidx)) // or isn't currently flagged as having passed the endpoint
{
UpdatePitch(coreidx, voiceidx);
while (vc.SP > 0)
GetNextDataDummy(thiscore, voiceidx); // Dummy is enough
}
// Write-back of raw voice data (some zeros since the voice is "dead")
if (voiceidx == 1)
spu2M_WriteFast(((0 == coreidx) ? 0x400 : 0xc00) + OutPos, 0);
else if (voiceidx == 3)
spu2M_WriteFast(((0 == coreidx) ? 0x600 : 0xe00) + OutPos, 0);
return StereoOut32(0, 0);
}
}
const VoiceMixSet VoiceMixSet::Empty((StereoOut32()), (StereoOut32())); // Don't use SteroOut32::Empty because C++ doesn't make any dep/order checks on global initializers.
static __forceinline void MixCoreVoices(VoiceMixSet &dest, const uint coreidx)
{
V_Core &thiscore(Cores[coreidx]);
for (uint voiceidx = 0; voiceidx < V_Core::NumVoices; ++voiceidx) {
StereoOut32 VVal(MixVoice(coreidx, voiceidx));
// Note: Results from MixVoice are ranged at 16 bits.
dest.Dry.Left += VVal.Left & thiscore.VoiceGates[voiceidx].DryL;
dest.Dry.Right += VVal.Right & thiscore.VoiceGates[voiceidx].DryR;
dest.Wet.Left += VVal.Left & thiscore.VoiceGates[voiceidx].WetL;
dest.Wet.Right += VVal.Right & thiscore.VoiceGates[voiceidx].WetR;
}
}
StereoOut32 V_Core::Mix(const VoiceMixSet &inVoices, const StereoOut32 &Input, const StereoOut32 &Ext)
{
MasterVol.Update();
// Saturate final result to standard 16 bit range.
const VoiceMixSet Voices(clamp_mix(inVoices.Dry), clamp_mix(inVoices.Wet));
// Write Mixed results To Output Area
spu2M_WriteFast(((0 == Index) ? 0x1000 : 0x1800) + OutPos, Voices.Dry.Left);
spu2M_WriteFast(((0 == Index) ? 0x1200 : 0x1A00) + OutPos, Voices.Dry.Right);
spu2M_WriteFast(((0 == Index) ? 0x1400 : 0x1C00) + OutPos, Voices.Wet.Left);
spu2M_WriteFast(((0 == Index) ? 0x1600 : 0x1E00) + OutPos, Voices.Wet.Right);
// Write mixed results to logfile (if enabled)
WaveDump::WriteCore(Index, CoreSrc_DryVoiceMix, Voices.Dry);
WaveDump::WriteCore(Index, CoreSrc_WetVoiceMix, Voices.Wet);
// Mix in the Input data
StereoOut32 TD(
Input.Left & DryGate.InpL,
Input.Right & DryGate.InpR);
// Mix in the Voice data
TD.Left += Voices.Dry.Left & DryGate.SndL;
TD.Right += Voices.Dry.Right & DryGate.SndR;
// Mix in the External (nothing/core0) data
TD.Left += Ext.Left & DryGate.ExtL;
TD.Right += Ext.Right & DryGate.ExtR;
// User-level Effects disabling. Nice speedup but breaks games that depend on
// reverb IRQs (very few -- if you find one name it here!).
if (EffectsDisabled)
return TD;
// ----------------------------------------------------------------------------
// Reverberation Effects Processing
// ----------------------------------------------------------------------------
// SPU2 has an FxEnable bit which seems to disable all reverb processing *and*
// output, but does *not* disable the advancing buffers. IRQs are not triggered
// and reverb is rendered silent.
//
// Technically we should advance the buffers even when fx are disabled. However
// there are two things that make this very unlikely to matter:
//
// 1. Any SPU2 app wanting to avoid noise or pops needs to clear the reverb buffers
// when adjusting settings anyway; so the read/write positions in the reverb
// buffer after FxEnabled is set back to 1 doesn't really matter.
//
// 2. Writes to ESA (and possibly EEA) reset the buffer pointers to 0.
//
// On the other hand, updating the buffer is cheap and easy, so might as well. ;)
Reverb_AdvanceBuffer(); // Updates the reverb work area as well, if needed.
// ToDo:
// Bad EndA causes memory corruption. Bad for us, unknown on PS2!
// According to no$psx, effects always run but don't always write back, so the FxEnable check may be wrong
if (!FxEnable || EffectsEndA >= 0x100000)
return TD;
StereoOut32 TW;
// Mix Input, Voice, and External data:
TW.Left = Input.Left & WetGate.InpL;
TW.Right = Input.Right & WetGate.InpR;
TW.Left += Voices.Wet.Left & WetGate.SndL;
TW.Right += Voices.Wet.Right & WetGate.SndR;
TW.Left += Ext.Left & WetGate.ExtL;
TW.Right += Ext.Right & WetGate.ExtR;
WaveDump::WriteCore(Index, CoreSrc_PreReverb, TW);
StereoOut32 RV = DoReverb(TW);
WaveDump::WriteCore(Index, CoreSrc_PostReverb, RV);
// Mix Dry + Wet
// (master volume is applied later to the result of both outputs added together).
return TD + ApplyVolume(RV, FxVol);
}
// Filters that work on the final output to de-alias and equlize it.
// Taken from http://nenolod.net/projects/upse/
#define OVERALL_SCALE (0.87f)
StereoOut32 Apply_Frequency_Response_Filter(StereoOut32 &SoundStream)
{
static FrequencyResponseFilter FRF = FrequencyResponseFilter();
s32 in, out;
s32 l, r;
s32 mid, side;
l = SoundStream.Left;
r = SoundStream.Right;
mid = l + r;
side = l - r;
in = mid;
out = FRF.la0 * in + FRF.la1 * FRF.lx1 + FRF.la2 * FRF.lx2 - FRF.lb1 * FRF.ly1 - FRF.lb2 * FRF.ly2;
FRF.lx2 = FRF.lx1;
FRF.lx1 = in;
FRF.ly2 = FRF.ly1;
FRF.ly1 = out;
mid = out;
l = ((0.5) * (OVERALL_SCALE)) * (mid + side);
r = ((0.5) * (OVERALL_SCALE)) * (mid - side);
in = l;
out = FRF.ha0 * in + FRF.ha1 * FRF.History_One_In.Left + FRF.ha2 * FRF.History_Two_In.Left - FRF.hb1 * FRF.History_One_Out.Left - FRF.hb2 * FRF.History_Two_Out.Left;
FRF.History_Two_In.Left = FRF.History_One_In.Left;
FRF.History_One_In.Left = in;
FRF.History_Two_Out.Left = FRF.History_One_Out.Left;
FRF.History_One_Out.Left = out;
l = out;
in = r;
out = FRF.ha0 * in + FRF.ha1 * FRF.History_One_In.Right + FRF.ha2 * FRF.History_Two_In.Right - FRF.hb1 * FRF.History_One_Out.Right - FRF.hb2 * FRF.History_Two_Out.Right;
FRF.History_Two_In.Right = FRF.History_One_In.Right;
FRF.History_One_In.Right = in;
FRF.History_Two_Out.Right = FRF.History_One_Out.Right;
FRF.History_One_Out.Right = out;
r = out;
//clamp_mix(l);
//clamp_mix(r);
SoundStream.Left = l;
SoundStream.Right = r;
return SoundStream;
}
StereoOut32 Apply_Dealias_Filter(StereoOut32 &SoundStream)
{
static StereoOut32 Old = StereoOut32::Empty;
s32 l, r;
l = SoundStream.Left;
r = SoundStream.Right;
l += (l - Old.Left);
r += (r - Old.Right);
Old.Left = SoundStream.Left;
Old.Right = SoundStream.Right;
SoundStream.Left = l;
SoundStream.Right = r;
return SoundStream;
}
// used to throttle the output rate of cache stat reports
static int p_cachestat_counter = 0;
// Gcc does not want to inline it when lto is enabled because some functions growth too much.
// The function is big enought to see any speed impact. -- Gregory
#ifndef __POSIX__
__forceinline
#endif
void
Mix()
{
// Note: Playmode 4 is SPDIF, which overrides other inputs.
StereoOut32 InputData[2] =
{
// SPDIF is on Core 0:
// Fixme:
// 1. We do not have an AC3 decoder for the bitstream.
// 2. Games usually provide a normal ADMA stream as well and want to see it getting read!
/*(PlayMode&4) ? StereoOut32::Empty : */ ApplyVolume(Cores[0].ReadInput(), Cores[0].InpVol),
// CDDA is on Core 1:
(PlayMode & 8) ? StereoOut32::Empty : ApplyVolume(Cores[1].ReadInput(), Cores[1].InpVol)};
WaveDump::WriteCore(0, CoreSrc_Input, InputData[0]);
WaveDump::WriteCore(1, CoreSrc_Input, InputData[1]);
// Todo: Replace me with memzero initializer!
VoiceMixSet VoiceData[2] = {VoiceMixSet::Empty, VoiceMixSet::Empty}; // mixed voice data for each core.
MixCoreVoices(VoiceData[0], 0);
MixCoreVoices(VoiceData[1], 1);
StereoOut32 Ext(Cores[0].Mix(VoiceData[0], InputData[0], StereoOut32::Empty));
if ((PlayMode & 4) || (Cores[0].Mute != 0))
Ext = StereoOut32::Empty;
else {
Ext = clamp_mix(ApplyVolume(Ext, Cores[0].MasterVol));
}
// Commit Core 0 output to ram before mixing Core 1:
spu2M_WriteFast(0x800 + OutPos, Ext.Left);
spu2M_WriteFast(0xA00 + OutPos, Ext.Right);
WaveDump::WriteCore(0, CoreSrc_External, Ext);
Ext = ApplyVolume(Ext, Cores[1].ExtVol);
StereoOut32 Out(Cores[1].Mix(VoiceData[1], InputData[1], Ext));
if (PlayMode & 8) {
// Experimental CDDA support
// The CDDA overrides all other mixer output. It's a direct feed!
Out = Cores[1].ReadInput_HiFi();
//WaveLog::WriteCore( 1, "CDDA-32", OutL, OutR );
} else {
Out.Left = MulShr32(Out.Left << (SndOutVolumeShift + 1), Cores[1].MasterVol.Left.Value);
Out.Right = MulShr32(Out.Right << (SndOutVolumeShift + 1), Cores[1].MasterVol.Right.Value);
#ifdef DEBUG_KEYS
if (postprocess_filter_enabled)
#endif
{
if (postprocess_filter_dealias) {
// Dealias filter emphasizes the highs too much.
Out = Apply_Dealias_Filter(Out);
}
Out = Apply_Frequency_Response_Filter(Out);
}
// Final Clamp!
// Like any good audio system, the PS2 pumps the volume and incurs some distortion in its
// output, giving us a nice thumpy sound at times. So we add 1 above (2x volume pump) and
// then clamp it all here.
// Edit: I'm sorry Jake, but I know of no good audio system that arbitrary distorts and clips
// output by design.
// Good thing though that this code gets the volume exactly right, as per tests :)
Out = clamp_mix(Out, SndOutVolumeShift);
}
// Configurable output volume
Out.Left *= FinalVolume;
Out.Right *= FinalVolume;
SndBuffer::Write(Out);
// Update AutoDMA output positioning
OutPos++;
if (OutPos >= 0x200)
OutPos = 0;
if (IsDevBuild) {
p_cachestat_counter++;
if (p_cachestat_counter > (48000 * 10)) {
p_cachestat_counter = 0;
if (MsgCache())
ConLog(" * SPU2 > CacheStats > Hits: %d Misses: %d Ignores: %d\n",
g_counter_cache_hits,
g_counter_cache_misses,
g_counter_cache_ignores);
g_counter_cache_hits =
g_counter_cache_misses =
g_counter_cache_ignores = 0;
}
}
}

View File

@ -1,135 +0,0 @@
/* 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
// Implemented in Config.cpp
extern float VolumeAdjustFL;
extern float VolumeAdjustFR;
struct StereoOut32
{
static StereoOut32 Empty;
s32 Left;
s32 Right;
StereoOut32()
: Left(0)
, Right(0)
{
}
StereoOut32(s32 left, s32 right)
: Left(left)
, Right(right)
{
}
StereoOut32(const StereoOut16 &src);
explicit StereoOut32(const StereoOutFloat &src);
StereoOut16 DownSample() const;
StereoOut32 operator*(const int &factor) const
{
return StereoOut32(
Left * factor,
Right * factor);
}
StereoOut32 &operator*=(const int &factor)
{
Left *= factor;
Right *= factor;
return *this;
}
StereoOut32 operator+(const StereoOut32 &right) const
{
return StereoOut32(
Left + right.Left,
Right + right.Right);
}
StereoOut32 operator/(int src) const
{
return StereoOut32(Left / src, Right / src);
}
void ResampleFrom(const StereoOut32 &src)
{
this->Left = src.Left << 2;
this->Right = src.Right << 2;
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s32)(Left * VolumeAdjustFL);
Right = (s32)(Right * VolumeAdjustFR);
}
};
struct FrequencyResponseFilter
{
static FrequencyResponseFilter Empty;
StereoOut32 History_One_In;
StereoOut32 History_One_Out;
StereoOut32 History_Two_In;
StereoOut32 History_Two_Out;
s32 lx1;
s32 lx2;
s32 ly1;
s32 ly2;
float la0, la1, la2, lb1, lb2;
float ha0, ha1, ha2, hb1, hb2;
FrequencyResponseFilter()
: History_One_In(0, 0)
, History_One_Out(0, 0)
, History_Two_In(0, 0)
, History_Two_Out(0, 0)
, lx1(0)
, lx2(0)
, ly1(0)
, ly2(0)
, la0(1.00320890889339290000f)
, la1(-1.97516434134506300000f)
, la2(0.97243484967313087000f)
, lb1(-1.97525280404731810000f)
, lb2(0.97555529586426892000f)
, ha0(1.52690772687271160000f)
, ha1(-1.62653918974914990000f) //-1.72 = "common equilizer curve" --____--
, ha2(0.57997976029249387000f)
, hb1(-0.80955590379048203000f)
, hb2(0.28990420120653748000f)
{
}
};
extern void Mix();
extern s32 clamp_mix(s32 x, u8 bitshift = 0);
extern StereoOut32 clamp_mix(const StereoOut32 &sample, u8 bitshift = 0);

View File

@ -1,723 +0,0 @@
/* 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 "PS2E-spu2.h"
#include "Dma.h"
#include "Dialogs.h"
#ifdef __APPLE__
#include "PS2Eext.h"
#endif
#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;
#ifdef _MSC_VER
HINSTANCE hInstance;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
if (dwReason == DLL_PROCESS_ATTACH) {
hInstance = hinstDLL;
} else if (dwReason == DLL_PROCESS_DETACH) {
// TODO : perform shutdown procedure, just in case PCSX2 itself failed
// to for some reason..
}
return TRUE;
}
#endif
static void InitLibraryName()
{
#ifdef SPU2X_PUBLIC_RELEASE
// Public Release!
// Output a simplified string that's just our name:
strcpy(libraryName, "SPU2-X");
#else
#ifdef SVN_REV_UNKNOWN
// Unknown revision.
// Output a name that includes devbuild status but not
// subversion revision tags:
strcpy(libraryName, "SPU2-X"
#ifdef DEBUG_FAST
"-Debug"
#elif defined(PCSX2_DEBUG)
"-Debug/Strict" // strict debugging is slow!
#elif defined(PCSX2_DEVBUILD)
"-Dev"
#else
""
#endif
);
#else
// Use TortoiseSVN's SubWCRev utility's output
// to label the specific revision:
snprintf(libraryName, 255, "SPU2-X %lld%s"
#ifdef DEBUG_FAST
"-Debug"
#elif defined(PCSX2_DEBUG)
"-Debug/Strict" // strict debugging is slow!
#elif defined(PCSX2_DEVBUILD)
"-Dev"
#else
""
#endif
,
SVN_REV, SVN_MODS ? "m" : "");
#endif
#endif
}
//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
}
EXPORT_C_(u32)
PS2EgetLibType()
{
return PS2E_LT_SPU2;
}
EXPORT_C_(char *)
PS2EgetLibName()
{
InitLibraryName();
return libraryName;
}
EXPORT_C_(u32)
PS2EgetLibVersion2(u32 type)
{
return (PS2E_SPU2_VERSION << 16) | (VersionInfo::Release << 8) | VersionInfo::Revision;
}
EXPORT_C_(void)
SPU2configure()
{
if (!CheckSSE())
return;
configure();
}
EXPORT_C_(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)();
EXPORT_C_(u32)
CALLBACK SPU2ReadMemAddr(int core)
{
return Cores[core].MADR;
}
EXPORT_C_(void)
CALLBACK SPU2WriteMemAddr(int core, u32 value)
{
Cores[core].MADR = value;
}
EXPORT_C_(void)
CALLBACK SPU2setDMABaseAddr(uptr baseaddr)
{
DMABaseAddr = (u16 *)baseaddr;
}
EXPORT_C_(void)
CALLBACK SPU2setSettingsDir(const char *dir)
{
CfgSetSettingsDir(dir);
}
EXPORT_C_(void)
CALLBACK SPU2setLogDir(const char *dir)
{
CfgSetLogDir(dir);
}
EXPORT_C_(void)
SPU2irqCallback(void (*SPU2callback)(), void (*DMA4callback)(), void (*DMA7callback)())
{
_irqcallback = SPU2callback;
dma4callback = DMA4callback;
dma7callback = DMA7callback;
}
EXPORT_C_(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);
}
EXPORT_C_(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);
}
EXPORT_C_(void)
CALLBACK SPU2interruptDMA4()
{
FileLog("[%10d] SPU2 interruptDMA4\n", Cycles);
Cores[0].Regs.STATX |= 0x80;
//Cores[0].Regs.ATTR &= ~0x30;
}
EXPORT_C_(void)
CALLBACK SPU2interruptDMA7()
{
FileLog("[%10d] SPU2 interruptDMA7\n", Cycles);
Cores[1].Regs.STATX |= 0x80;
//Cores[1].Regs.ATTR &= ~0x30;
}
EXPORT_C_(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);
}
EXPORT_C_(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);
}
EXPORT_C_(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;
}
EXPORT_C_(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;
}
EXPORT_C_(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;
EXPORT_C_(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;
}
EXPORT_C_(void)
SPU2close()
{
if (!IsOpened)
return;
IsOpened = false;
FileLog("[%10d] SPU2 Close\n", Cycles);
#ifndef __POSIX__
DspCloseLibrary();
#endif
SndBuffer::Cleanup();
}
EXPORT_C_(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
}
EXPORT_C_(void)
SPU2setClockPtr(u32 *ptr)
{
cyclePtr = ptr;
}
#ifdef DEBUG_KEYS
static u32 lastTicks;
static bool lState[6];
#endif
EXPORT_C_(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
}
EXPORT_C_(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;
}
EXPORT_C_(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
EXPORT_C_(int)
SPU2setupRecording(int start, std::wstring* filename)
{
if (start == 0)
RecordStop();
else if (start == 1)
RecordStart(filename);
return 0;
}
EXPORT_C_(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;
}

View File

@ -1,124 +0,0 @@
/* 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"
#include "PS2Edefs.h"
#ifdef __POSIX__
//Until I get around to putting in Linux svn code, this is an unknown svn version.
#define SVN_REV_UNKNOWN
#endif
#ifdef _MSC_VER
#define EXPORT_C_(type) extern "C" type CALLBACK
#else
#define EXPORT_C_(type) extern "C" __attribute__((stdcall, externally_visible, visibility("default"))) type
#endif
// We have our own versions that have the DLLExport attribute configured:
EXPORT_C_(s32)
SPU2init();
EXPORT_C_(s32)
SPU2reset();
EXPORT_C_(s32)
SPU2ps1reset();
EXPORT_C_(s32)
SPU2open(void *pDsp);
EXPORT_C_(void)
SPU2close();
EXPORT_C_(void)
SPU2shutdown();
EXPORT_C_(void)
SPU2write(u32 mem, u16 value);
EXPORT_C_(u16)
SPU2read(u32 mem);
// These defines are useless and gcc-4.6 complain about redefinition
// so we remove them on linux
#ifndef __POSIX__
EXPORT_C_(void)
SPU2readDMA4Mem(u16 *pMem, u32 size);
EXPORT_C_(void)
SPU2writeDMA4Mem(u16 *pMem, u32 size);
EXPORT_C_(void)
SPU2interruptDMA4();
EXPORT_C_(void)
SPU2readDMA7Mem(u16 *pMem, u32 size);
EXPORT_C_(void)
SPU2writeDMA7Mem(u16 *pMem, u32 size);
EXPORT_C_(void)
SPU2interruptDMA7();
// all addresses passed by dma will be pointers to the array starting at baseaddr
// This function is necessary to successfully save and reload the spu2 state
EXPORT_C_(u32)
SPU2ReadMemAddr(int core);
EXPORT_C_(void)
SPU2WriteMemAddr(int core, u32 value);
EXPORT_C_(void)
SPU2irqCallback(void (*SPU2callback)(), void (*DMA4callback)(), void (*DMA7callback)());
#endif
// 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
EXPORT_C_(int)
SPU2setupRecording(int start, std::wstring* filename);
EXPORT_C_(void)
SPU2setClockPtr(u32 *ptr);
EXPORT_C_(void)
SPU2async(u32 cycles);
EXPORT_C_(s32)
SPU2freeze(int mode, freezeData *data);
EXPORT_C_(void)
SPU2configure();
EXPORT_C_(void)
SPU2about();
EXPORT_C_(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

View File

@ -1,18 +0,0 @@
/* 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"

View File

@ -1,167 +0,0 @@
/* 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 "Dma.h"
#include "PS2E-spu2.h" // required for ENABLE_NEW_IOPDMA_SPU2 define
// Core 0 Input is "SPDIF mode" - Source audio is AC3 compressed.
// Core 1 Input is "CDDA mode" - Source audio data is 32 bits.
// PS2 note: Very! few PS2 games use this mode. Some PSX games used it, however no
// *known* PS2 game does since it was likely only available if the game was recorded to CD
// media (ie, not available in DVD mode, which almost all PS2 games use). Plus PS2 games
// generally prefer to use ADPCM streaming audio since they need as much storage space as
// possible for FMVs and high-def textures.
//
StereoOut32 V_Core::ReadInput_HiFi()
{
if (psxmode)
ConLog("ReadInput_HiFi!!!!!\n");
InputPosRead &= ~1;
//
//#ifdef PCM24_S1_INTERLEAVE
// StereoOut32 retval(
// *((s32*)(ADMATempBuffer+(InputPosRead<<1))),
// *((s32*)(ADMATempBuffer+(InputPosRead<<1)+2))
// );
//#else
// StereoOut32 retval(
// (s32&)(ADMATempBuffer[InputPosRead]),
// (s32&)(ADMATempBuffer[InputPosRead+0x200])
// );
//#endif
StereoOut32 retval(
(s32 &)(*GetMemPtr(0x2000 + (Index << 10) + InputPosRead)),
(s32 &)(*GetMemPtr(0x2200 + (Index << 10) + InputPosRead)));
if (Index == 1) {
// CDDA Mode:
// give 30 bit data (SndOut downsamples the rest of the way)
// HACKFIX: 28 bits seems better according to rama. I should take some time and do some
// bitcounting on this one. --air
retval.Left >>= 4;
retval.Right >>= 4;
}
InputPosRead += 2;
// Why does CDDA mode check for InputPos == 0x100? In the old code, SPDIF mode did not but CDDA did.
// One of these seems wrong, they should be the same. Since standard ADMA checks too I'm assuming that as default. -- air
if ((InputPosRead == 0x100) || (InputPosRead >= 0x200)) {
AdmaInProgress = 0;
if (InputDataLeft >= 0x200) {
#ifdef PCM24_S1_INTERLEAVE
AutoDMAReadBuffer(1);
#else
AutoDMAReadBuffer(0);
#endif
AdmaInProgress = 1;
TSA = (Index << 10) + InputPosRead;
if (InputDataLeft < 0x200) {
FileLog("[%10d] %s AutoDMA%c block end.\n", (Index == 1) ? "CDDA" : "SPDIF", Cycles, GetDmaIndexChar());
if (IsDevBuild) {
if (InputDataLeft > 0) {
if (MsgAutoDMA())
ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
}
InputDataLeft = 0;
// Hack, kinda. We call the interrupt early here, since PCSX2 doesn't like them delayed.
//DMAICounter = 1;
if (Index == 0) {
if (dma4callback)
dma4callback();
} else {
if (dma7callback)
dma7callback();
}
}
}
InputPosRead &= 0x1ff;
}
return retval;
}
StereoOut32 V_Core::ReadInput()
{
StereoOut32 retval;
if ((Index != 1) || ((PlayMode & 2) == 0)) {
for (int i = 0; i < 2; i++)
if (Cores[i].IRQEnable && 0x2000 + (Index << 10) + InputPosRead == (Cores[i].IRQA & 0xfffffdff))
SetIrqCall(i);
//retval = StereoOut32(
// (s32)ADMATempBuffer[InputPosRead],
// (s32)ADMATempBuffer[InputPosRead+0x200]
//);
retval = StereoOut32(
(s32)(*GetMemPtr(0x2000 + (Index << 10) + InputPosRead)),
(s32)(*GetMemPtr(0x2200 + (Index << 10) + InputPosRead)));
}
#ifdef PCSX2_DEVBUILD
DebugCores[Index].admaWaveformL[InputPosRead % 0x100] = retval.Left;
DebugCores[Index].admaWaveformR[InputPosRead % 0x100] = retval.Right;
#endif
InputPosRead++;
if (AutoDMACtrl & (Index + 1) && (InputPosRead == 0x100 || InputPosRead == 0x200)) {
AdmaInProgress = 0;
if (InputDataLeft >= 0x200) {
//u8 k=InputDataLeft>=InputDataProgress;
AutoDMAReadBuffer(0);
AdmaInProgress = 1;
TSA = (Index << 10) + InputPosRead;
if (InputDataLeft < 0x200) {
AutoDMACtrl |= ~3;
if (IsDevBuild) {
FileLog("[%10d] AutoDMA%c block end.\n", Cycles, GetDmaIndexChar());
if (InputDataLeft > 0) {
if (MsgAutoDMA())
ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
}
InputDataLeft = 0;
// Hack, kinda. We call the interrupt early here, since PCSX2 doesn't like them delayed.
//DMAICounter = 1;
if (Index == 0) {
if (dma4callback)
dma4callback();
} else {
if (dma7callback)
dma7callback();
}
}
}
}
InputPosRead &= 0x1ff;
return retval;
}

View File

@ -1,297 +0,0 @@
/* 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"
const char *ParamNames[8] = {"VOLL", "VOLR", "PITCH", "ADSR1", "ADSR2", "ENVX", "VOLXL", "VOLXR"};
const char *AddressNames[6] = {"SSAH", "SSAL", "LSAH", "LSAL", "NAXH", "NAXL"};
__forceinline void _RegLog_(const char *action, int level, const char *RName, u32 mem, u32 core, u16 value)
{
if (level > 1)
FileLog("[%10d] SPU2 %s mem %08x (core %d, register %s) value %04x\n",
Cycles, action, mem, core, RName, value);
}
#define RegLog(lev, rname, mem, core, val) _RegLog_(action, lev, rname, mem, core, val)
void SPU2writeLog(const char *action, u32 rmem, u16 value)
{
if (!IsDevBuild)
return;
//u32 vx=0, vc=0;
u32 core = 0, omem, mem;
omem = mem = rmem & 0x7FF; //FFFF;
if (mem & 0x400) {
omem ^= 0x400;
core = 1;
}
if (omem < 0x0180) // Voice Params (VP)
{
const u32 voice = (omem & 0x1F0) >> 4;
const u32 param = (omem & 0xF) >> 1;
char dest[192];
sprintf(dest, "Voice %d %s", voice, ParamNames[param]);
RegLog(2, dest, rmem, core, value);
} else if ((omem >= 0x01C0) && (omem < 0x02E0)) // Voice Addressing Params (VA)
{
const u32 voice = ((omem - 0x01C0) / 12);
const u32 address = ((omem - 0x01C0) % 12) >> 1;
char dest[192];
sprintf(dest, "Voice %d %s", voice, AddressNames[address]);
RegLog(2, dest, rmem, core, value);
} else if ((mem >= 0x0760) && (mem < 0x07b0)) {
omem = mem;
core = 0;
if (mem >= 0x0788) {
omem -= 0x28;
core = 1;
}
switch (omem) {
case REG_P_EVOLL:
RegLog(2, "EVOLL", rmem, core, value);
break;
case REG_P_EVOLR:
RegLog(2, "EVOLR", rmem, core, value);
break;
case REG_P_AVOLL:
if (core) {
RegLog(2, "AVOLL", rmem, core, value);
}
break;
case REG_P_AVOLR:
if (core) {
RegLog(2, "AVOLR", rmem, core, value);
}
break;
case REG_P_BVOLL:
RegLog(2, "BVOLL", rmem, core, value);
break;
case REG_P_BVOLR:
RegLog(2, "BVOLR", rmem, core, value);
break;
case REG_P_MVOLXL:
RegLog(2, "MVOLXL", rmem, core, value);
break;
case REG_P_MVOLXR:
RegLog(2, "MVOLXR", rmem, core, value);
break;
case R_IIR_VOL:
RegLog(2, "IIR_VOL", rmem, core, value);
break;
case R_COMB1_VOL:
RegLog(2, "COMB1_VOL", rmem, core, value);
break;
case R_COMB2_VOL:
RegLog(2, "COMB2_VOL", rmem, core, value);
break;
case R_COMB3_VOL:
RegLog(2, "COMB3_VOL", rmem, core, value);
break;
case R_COMB4_VOL:
RegLog(2, "COMB4_VOL", rmem, core, value);
break;
case R_WALL_VOL:
RegLog(2, "WALL_VOL", rmem, core, value);
break;
case R_APF1_VOL:
RegLog(2, "APF1_VOL", rmem, core, value);
break;
case R_APF2_VOL:
RegLog(2, "APF2_VOL", rmem, core, value);
break;
case R_IN_COEF_L:
RegLog(2, "IN_COEF_L", rmem, core, value);
break;
case R_IN_COEF_R:
RegLog(2, "IN_COEF_R", rmem, core, value);
break;
}
} else if ((mem >= 0x07C0) && (mem < 0x07CE)) {
switch (mem) {
case SPDIF_OUT:
RegLog(2, "SPDIF_OUT", rmem, -1, value);
break;
case SPDIF_IRQINFO:
RegLog(2, "SPDIF_IRQINFO", rmem, -1, value);
break;
case 0x7c4:
if (Spdif.Unknown1 != value)
ConLog("* SPU2-X: SPDIF Unknown Register 1 set to %04x\n", value);
RegLog(2, "SPDIF_UNKNOWN1", rmem, -1, value);
break;
case SPDIF_MODE:
if (Spdif.Mode != value)
ConLog("* SPU2-X: SPDIF Mode set to %04x\n", value);
RegLog(2, "SPDIF_MODE", rmem, -1, value);
break;
case SPDIF_MEDIA:
if (Spdif.Media != value)
ConLog("* SPU2-X: SPDIF Media set to %04x\n", value);
RegLog(2, "SPDIF_MEDIA", rmem, -1, value);
break;
case 0x7ca:
if (Spdif.Unknown2 != value)
ConLog("* SPU2-X: SPDIF Unknown Register 2 set to %04x\n", value);
RegLog(2, "SPDIF_UNKNOWN2", rmem, -1, value);
break;
case SPDIF_PROTECT:
if (Spdif.Protection != value)
ConLog("* SPU2-X: SPDIF Copy set to %04x\n", value);
RegLog(2, "SPDIF_PROTECT", rmem, -1, value);
break;
}
UpdateSpdifMode();
} else {
switch (omem) {
case REG_C_ATTR:
RegLog(4, "ATTR", rmem, core, value);
break;
case REG_S_PMON:
RegLog(1, "PMON0", rmem, core, value);
break;
case (REG_S_PMON + 2):
RegLog(1, "PMON1", rmem, core, value);
break;
case REG_S_NON:
RegLog(1, "NON0", rmem, core, value);
break;
case (REG_S_NON + 2):
RegLog(1, "NON1", rmem, core, value);
break;
case REG_S_VMIXL:
RegLog(1, "VMIXL0", rmem, core, value);
break;
case (REG_S_VMIXL + 2):
RegLog(1, "VMIXL1", rmem, core, value);
break;
case REG_S_VMIXEL:
RegLog(1, "VMIXEL0", rmem, core, value);
break;
case (REG_S_VMIXEL + 2):
RegLog(1, "VMIXEL1", rmem, core, value);
break;
case REG_S_VMIXR:
RegLog(1, "VMIXR0", rmem, core, value);
break;
case (REG_S_VMIXR + 2):
RegLog(1, "VMIXR1", rmem, core, value);
break;
case REG_S_VMIXER:
RegLog(1, "VMIXER0", rmem, core, value);
break;
case (REG_S_VMIXER + 2):
RegLog(1, "VMIXER1", rmem, core, value);
break;
case REG_P_MMIX:
RegLog(1, "MMIX", rmem, core, value);
break;
case REG_A_IRQA:
RegLog(2, "IRQAH", rmem, core, value);
break;
case (REG_A_IRQA + 2):
RegLog(2, "IRQAL", rmem, core, value);
break;
case (REG_S_KON + 2):
RegLog(1, "KON1", rmem, core, value);
break;
case REG_S_KON:
RegLog(1, "KON0", rmem, core, value);
break;
case (REG_S_KOFF + 2):
RegLog(1, "KOFF1", rmem, core, value);
break;
case REG_S_KOFF:
RegLog(1, "KOFF0", rmem, core, value);
break;
case REG_A_TSA:
RegLog(2, "TSAH", rmem, core, value);
break;
case (REG_A_TSA + 2):
RegLog(2, "TSAL", rmem, core, value);
break;
case REG_S_ENDX:
//ConLog("* SPU2-X: Core %d ENDX cleared!\n",core);
RegLog(2, "ENDX0", rmem, core, value);
break;
case (REG_S_ENDX + 2):
//ConLog("* SPU2-X: Core %d ENDX cleared!\n",core);
RegLog(2, "ENDX1", rmem, core, value);
break;
case REG_P_MVOLL:
RegLog(1, "MVOLL", rmem, core, value);
break;
case REG_P_MVOLR:
RegLog(1, "MVOLR", rmem, core, value);
break;
case REG_S_ADMAS:
RegLog(3, "ADMAS", rmem, core, value);
//ConLog("* SPU2-X: Core %d AutoDMAControl set to %d\n",core,value);
break;
case REG_P_STATX:
RegLog(3, "STATX", rmem, core, value);
break;
case REG_A_ESA:
RegLog(2, "ESAH", rmem, core, value);
break;
case (REG_A_ESA + 2):
RegLog(2, "ESAL", rmem, core, value);
break;
case REG_A_EEA:
RegLog(2, "EEAH", rmem, core, value);
break;
#define LOG_REVB_REG(n, t) \
case R_##n: \
RegLog(2, t "H", mem, core, value); \
break; \
case (R_##n + 2): \
RegLog(2, t "L", mem, core, value); \
break;
LOG_REVB_REG(APF1_SIZE, "APF1_SIZE")
LOG_REVB_REG(APF2_SIZE, "APF2_SIZE")
LOG_REVB_REG(SAME_L_SRC, "SAME_L_SRC")
LOG_REVB_REG(SAME_R_SRC, "SAME_R_SRC")
LOG_REVB_REG(DIFF_L_SRC, "DIFF_L_SRC")
LOG_REVB_REG(DIFF_R_SRC, "DIFF_R_SRC")
LOG_REVB_REG(SAME_L_DST, "SAME_L_DST")
LOG_REVB_REG(SAME_R_DST, "SAME_R_DST")
LOG_REVB_REG(DIFF_L_DST, "DIFF_L_DST")
LOG_REVB_REG(DIFF_R_DST, "DIFF_R_DST")
LOG_REVB_REG(COMB1_L_SRC, "COMB1_L_SRC")
LOG_REVB_REG(COMB1_R_SRC, "COMB1_R_SRC")
LOG_REVB_REG(COMB2_L_SRC, "COMB2_L_SRC")
LOG_REVB_REG(COMB2_R_SRC, "COMB2_R_SRC")
LOG_REVB_REG(COMB3_L_SRC, "COMB3_L_SRC")
LOG_REVB_REG(COMB3_R_SRC, "COMB3_R_SRC")
LOG_REVB_REG(COMB4_L_SRC, "COMB4_L_SRC")
LOG_REVB_REG(COMB4_R_SRC, "COMB4_R_SRC")
LOG_REVB_REG(APF1_L_DST, "APF1_L_DST")
LOG_REVB_REG(APF1_R_DST, "APF1_R_DST")
LOG_REVB_REG(APF2_L_DST, "APF2_L_DST")
LOG_REVB_REG(APF2_R_DST, "APF2_R_DST")
default:
RegLog(2, "UNKNOWN", rmem, core, value);
spu2Ru16(mem) = value;
}
}
}

View File

@ -1,303 +0,0 @@
/* 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"
#define PCORE(c, p) \
U16P(Cores[c].p)
#define PVCP(c, v, p) \
PCORE(c, Voices[v].p)
#define PVC(c, v) \
PVCP(c, v, Volume.Left.Reg_VOL) \
, \
PVCP(c, v, Volume.Right.Reg_VOL), \
PVCP(c, v, Pitch), \
PVCP(c, v, ADSR.regADSR1), \
PVCP(c, v, ADSR.regADSR2), \
PVCP(c, v, ADSR.Value) + 1, \
PVCP(c, v, Volume.Left.Value) + 1, \
PVCP(c, v, Volume.Right.Value) + 1
#define PVCA(c, v) \
PVCP(c, v, StartA) + 1, \
PVCP(c, v, StartA), \
PVCP(c, v, LoopStartA) + 1, \
PVCP(c, v, LoopStartA), \
PVCP(c, v, NextA) + 1, \
PVCP(c, v, NextA)
#define PRAW(a) \
((u16 *)NULL)
#define PREVB_REG(c, n) \
PCORE(c, Revb.n) + 1, \
PCORE(c, Revb.n)
u16 *regtable[0x401];
u16 const *const regtable_original[0x401] =
{
// Voice Params: 8 params, 24 voices = 0x180 bytes
PVC(0, 0), PVC(0, 1), PVC(0, 2), PVC(0, 3), PVC(0, 4), PVC(0, 5),
PVC(0, 6), PVC(0, 7), PVC(0, 8), PVC(0, 9), PVC(0, 10), PVC(0, 11),
PVC(0, 12), PVC(0, 13), PVC(0, 14), PVC(0, 15), PVC(0, 16), PVC(0, 17),
PVC(0, 18), PVC(0, 19), PVC(0, 20), PVC(0, 21), PVC(0, 22), PVC(0, 23),
PCORE(0, Regs.PMON),
PCORE(0, Regs.PMON) + 1,
PCORE(0, Regs.NON),
PCORE(0, Regs.NON) + 1,
PCORE(0, Regs.VMIXL),
PCORE(0, Regs.VMIXL) + 1,
PCORE(0, Regs.VMIXEL),
PCORE(0, Regs.VMIXEL) + 1,
PCORE(0, Regs.VMIXR),
PCORE(0, Regs.VMIXR) + 1,
PCORE(0, Regs.VMIXER),
PCORE(0, Regs.VMIXER) + 1,
PCORE(0, Regs.MMIX),
PCORE(0, Regs.ATTR),
PCORE(0, IRQA) + 1,
PCORE(0, IRQA),
NULL, NULL,
NULL, NULL,
PCORE(0, TSA) + 1,
PCORE(0, TSA),
PRAW(REG__1AC), PRAW(REG__1AE),
PCORE(0, AutoDMACtrl),
PRAW(0x1b2), PRAW(0x1b4), PRAW(0x1b6), PRAW(0x1b8), PRAW(0x1ba), PRAW(0x1bc), PRAW(0x1be), // unknown
// Voice Addresses
PVCA(0, 0), PVCA(0, 1), PVCA(0, 2), PVCA(0, 3), PVCA(0, 4), PVCA(0, 5),
PVCA(0, 6), PVCA(0, 7), PVCA(0, 8), PVCA(0, 9), PVCA(0, 10), PVCA(0, 11),
PVCA(0, 12), PVCA(0, 13), PVCA(0, 14), PVCA(0, 15), PVCA(0, 16), PVCA(0, 17),
PVCA(0, 18), PVCA(0, 19), PVCA(0, 20), PVCA(0, 21), PVCA(0, 22), PVCA(0, 23),
PCORE(0, ExtEffectsStartA) + 1,
PCORE(0, ExtEffectsStartA),
PREVB_REG(0, APF1_SIZE),
PREVB_REG(0, APF2_SIZE),
PREVB_REG(0, SAME_L_DST),
PREVB_REG(0, SAME_R_DST),
PREVB_REG(0, COMB1_L_SRC),
PREVB_REG(0, COMB1_R_SRC),
PREVB_REG(0, COMB2_L_SRC),
PREVB_REG(0, COMB2_R_SRC),
PREVB_REG(0, SAME_L_SRC),
PREVB_REG(0, SAME_R_SRC),
PREVB_REG(0, DIFF_L_DST),
PREVB_REG(0, DIFF_R_DST),
PREVB_REG(0, COMB3_L_SRC),
PREVB_REG(0, COMB3_R_SRC),
PREVB_REG(0, COMB4_L_SRC),
PREVB_REG(0, COMB4_R_SRC),
PREVB_REG(0, DIFF_L_SRC),
PREVB_REG(0, DIFF_R_SRC),
PREVB_REG(0, APF1_L_DST),
PREVB_REG(0, APF1_R_DST),
PREVB_REG(0, APF2_L_DST),
PREVB_REG(0, APF2_R_DST),
PCORE(0, ExtEffectsEndA) + 1,
PCORE(0, ExtEffectsEndA),
PCORE(0, Regs.ENDX),
PCORE(0, Regs.ENDX) + 1,
PCORE(0, Regs.STATX),
//0x346 here
PRAW(0x346),
PRAW(0x348), PRAW(0x34A), PRAW(0x34C), PRAW(0x34E),
PRAW(0x350), PRAW(0x352), PRAW(0x354), PRAW(0x356),
PRAW(0x358), PRAW(0x35A), PRAW(0x35C), PRAW(0x35E),
PRAW(0x360), PRAW(0x362), PRAW(0x364), PRAW(0x366),
PRAW(0x368), PRAW(0x36A), PRAW(0x36C), PRAW(0x36E),
PRAW(0x370), PRAW(0x372), PRAW(0x374), PRAW(0x376),
PRAW(0x378), PRAW(0x37A), PRAW(0x37C), PRAW(0x37E),
PRAW(0x380), PRAW(0x382), PRAW(0x384), PRAW(0x386),
PRAW(0x388), PRAW(0x38A), PRAW(0x38C), PRAW(0x38E),
PRAW(0x390), PRAW(0x392), PRAW(0x394), PRAW(0x396),
PRAW(0x398), PRAW(0x39A), PRAW(0x39C), PRAW(0x39E),
PRAW(0x3A0), PRAW(0x3A2), PRAW(0x3A4), PRAW(0x3A6),
PRAW(0x3A8), PRAW(0x3AA), PRAW(0x3AC), PRAW(0x3AE),
PRAW(0x3B0), PRAW(0x3B2), PRAW(0x3B4), PRAW(0x3B6),
PRAW(0x3B8), PRAW(0x3BA), PRAW(0x3BC), PRAW(0x3BE),
PRAW(0x3C0), PRAW(0x3C2), PRAW(0x3C4), PRAW(0x3C6),
PRAW(0x3C8), PRAW(0x3CA), PRAW(0x3CC), PRAW(0x3CE),
PRAW(0x3D0), PRAW(0x3D2), PRAW(0x3D4), PRAW(0x3D6),
PRAW(0x3D8), PRAW(0x3DA), PRAW(0x3DC), PRAW(0x3DE),
PRAW(0x3E0), PRAW(0x3E2), PRAW(0x3E4), PRAW(0x3E6),
PRAW(0x3E8), PRAW(0x3EA), PRAW(0x3EC), PRAW(0x3EE),
PRAW(0x3F0), PRAW(0x3F2), PRAW(0x3F4), PRAW(0x3F6),
PRAW(0x3F8), PRAW(0x3FA), PRAW(0x3FC), PRAW(0x3FE),
//AND... we reached 0x400!
// Voice Params: 8 params, 24 voices = 0x180 bytes
PVC(1, 0), PVC(1, 1), PVC(1, 2), PVC(1, 3), PVC(1, 4), PVC(1, 5),
PVC(1, 6), PVC(1, 7), PVC(1, 8), PVC(1, 9), PVC(1, 10), PVC(1, 11),
PVC(1, 12), PVC(1, 13), PVC(1, 14), PVC(1, 15), PVC(1, 16), PVC(1, 17),
PVC(1, 18), PVC(1, 19), PVC(1, 20), PVC(1, 21), PVC(1, 22), PVC(1, 23),
PCORE(1, Regs.PMON),
PCORE(1, Regs.PMON) + 1,
PCORE(1, Regs.NON),
PCORE(1, Regs.NON) + 1,
PCORE(1, Regs.VMIXL),
PCORE(1, Regs.VMIXL) + 1,
PCORE(1, Regs.VMIXEL),
PCORE(1, Regs.VMIXEL) + 1,
PCORE(1, Regs.VMIXR),
PCORE(1, Regs.VMIXR) + 1,
PCORE(1, Regs.VMIXER),
PCORE(1, Regs.VMIXER) + 1,
PCORE(1, Regs.MMIX),
PCORE(1, Regs.ATTR),
PCORE(1, IRQA) + 1,
PCORE(1, IRQA),
NULL, NULL,
NULL, NULL,
PCORE(1, TSA) + 1,
PCORE(1, TSA),
PRAW(0x5ac), PRAW(0x5ae),
PCORE(1, AutoDMACtrl),
PRAW(0x5b2), PRAW(0x5b4), PRAW(0x5b6), PRAW(0x5b8), PRAW(0x5ba), PRAW(0x5bc), PRAW(0x5be), // unknown
// Voice Addresses
PVCA(1, 0), PVCA(1, 1), PVCA(1, 2), PVCA(1, 3), PVCA(1, 4), PVCA(1, 5),
PVCA(1, 6), PVCA(1, 7), PVCA(1, 8), PVCA(1, 9), PVCA(1, 10), PVCA(1, 11),
PVCA(1, 12), PVCA(1, 13), PVCA(1, 14), PVCA(1, 15), PVCA(1, 16), PVCA(1, 17),
PVCA(1, 18), PVCA(1, 19), PVCA(1, 20), PVCA(1, 21), PVCA(1, 22), PVCA(1, 23),
PCORE(1, ExtEffectsStartA) + 1,
PCORE(1, ExtEffectsStartA),
PREVB_REG(1, APF1_SIZE),
PREVB_REG(1, APF2_SIZE),
PREVB_REG(1, SAME_L_DST),
PREVB_REG(1, SAME_R_DST),
PREVB_REG(1, COMB1_L_SRC),
PREVB_REG(1, COMB1_R_SRC),
PREVB_REG(1, COMB2_L_SRC),
PREVB_REG(1, COMB2_R_SRC),
PREVB_REG(1, SAME_L_SRC),
PREVB_REG(1, SAME_R_SRC),
PREVB_REG(1, DIFF_L_DST),
PREVB_REG(1, DIFF_R_DST),
PREVB_REG(1, COMB3_L_SRC),
PREVB_REG(1, COMB3_R_SRC),
PREVB_REG(1, COMB4_L_SRC),
PREVB_REG(1, COMB4_R_SRC),
PREVB_REG(1, DIFF_L_SRC),
PREVB_REG(1, DIFF_R_SRC),
PREVB_REG(1, APF1_L_DST),
PREVB_REG(1, APF1_R_DST),
PREVB_REG(1, APF2_L_DST),
PREVB_REG(1, APF2_R_DST),
PCORE(1, ExtEffectsEndA) + 1,
PCORE(1, ExtEffectsEndA),
PCORE(1, Regs.ENDX),
PCORE(1, Regs.ENDX) + 1,
PCORE(1, Regs.STATX),
PRAW(0x746),
PRAW(0x748), PRAW(0x74A), PRAW(0x74C), PRAW(0x74E),
PRAW(0x750), PRAW(0x752), PRAW(0x754), PRAW(0x756),
PRAW(0x758), PRAW(0x75A), PRAW(0x75C), PRAW(0x75E),
//0x760: weird area
PCORE(0, MasterVol.Left.Reg_VOL),
PCORE(0, MasterVol.Right.Reg_VOL),
PCORE(0, FxVol.Left) + 1,
PCORE(0, FxVol.Right) + 1,
PCORE(0, ExtVol.Left) + 1,
PCORE(0, ExtVol.Right) + 1,
PCORE(0, InpVol.Left) + 1,
PCORE(0, InpVol.Right) + 1,
PCORE(0, MasterVol.Left.Value) + 1,
PCORE(0, MasterVol.Right.Value) + 1,
PCORE(0, Revb.IIR_VOL),
PCORE(0, Revb.COMB1_VOL),
PCORE(0, Revb.COMB2_VOL),
PCORE(0, Revb.COMB3_VOL),
PCORE(0, Revb.COMB4_VOL),
PCORE(0, Revb.WALL_VOL),
PCORE(0, Revb.APF1_VOL),
PCORE(0, Revb.APF2_VOL),
PCORE(0, Revb.IN_COEF_L),
PCORE(0, Revb.IN_COEF_R),
PCORE(1, MasterVol.Left.Reg_VOL),
PCORE(1, MasterVol.Right.Reg_VOL),
PCORE(1, FxVol.Left) + 1,
PCORE(1, FxVol.Right) + 1,
PCORE(1, ExtVol.Left) + 1,
PCORE(1, ExtVol.Right) + 1,
PCORE(1, InpVol.Left) + 1,
PCORE(1, InpVol.Right) + 1,
PCORE(1, MasterVol.Left.Value) + 1,
PCORE(1, MasterVol.Right.Value) + 1,
PCORE(1, Revb.IIR_VOL),
PCORE(1, Revb.COMB1_VOL),
PCORE(1, Revb.COMB2_VOL),
PCORE(1, Revb.COMB3_VOL),
PCORE(1, Revb.COMB4_VOL),
PCORE(1, Revb.WALL_VOL),
PCORE(1, Revb.APF1_VOL),
PCORE(1, Revb.APF2_VOL),
PCORE(1, Revb.IN_COEF_L),
PCORE(1, Revb.IN_COEF_R),
PRAW(0x7B0), PRAW(0x7B2), PRAW(0x7B4), PRAW(0x7B6),
PRAW(0x7B8), PRAW(0x7BA), PRAW(0x7BC), PRAW(0x7BE),
// SPDIF interface
U16P(Spdif.Out),
U16P(Spdif.Info),
U16P(Spdif.Unknown1),
U16P(Spdif.Mode),
U16P(Spdif.Media),
U16P(Spdif.Unknown2),
U16P(Spdif.Protection),
PRAW(0x7CE),
PRAW(0x7D0), PRAW(0x7D2), PRAW(0x7D4), PRAW(0x7D6),
PRAW(0x7D8), PRAW(0x7DA), PRAW(0x7DC), PRAW(0x7DE),
PRAW(0x7E0), PRAW(0x7E2), PRAW(0x7E4), PRAW(0x7E6),
PRAW(0x7E8), PRAW(0x7EA), PRAW(0x7EC), PRAW(0x7EE),
PRAW(0x7F0), PRAW(0x7F2), PRAW(0x7F4), PRAW(0x7F6),
PRAW(0x7F8), PRAW(0x7FA), PRAW(0x7FC), PRAW(0x7FE),
NULL};

View File

@ -1,133 +0,0 @@
/* 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"
__forceinline s32 V_Core::RevbGetIndexer(s32 offset)
{
u32 pos = ReverbX + offset;
// Fast and simple single step wrapping, made possible by the preparation of the
// effects buffer addresses.
if (pos > EffectsEndA) {
pos -= EffectsEndA + 1;
pos += EffectsStartA;
}
assert(pos >= EffectsStartA && pos <= EffectsEndA);
return pos;
}
void V_Core::Reverb_AdvanceBuffer()
{
if (RevBuffers.NeedsUpdated)
UpdateEffectsBufferSize();
if ((Cycles & 1) && (EffectsBufferSize > 0)) {
ReverbX += 1;
if (ReverbX >= (u32)EffectsBufferSize)
ReverbX = 0;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
StereoOut32 V_Core::DoReverb(const StereoOut32 &Input)
{
if (EffectsBufferSize <= 0) {
return StereoOut32::Empty;
}
bool R = Cycles & 1;
// Calculate the read/write addresses we'll be needing for this session of reverb.
const u32 same_src = RevbGetIndexer(R ? RevBuffers.SAME_R_SRC : RevBuffers.SAME_L_SRC);
const u32 same_dst = RevbGetIndexer(R ? RevBuffers.SAME_R_DST : RevBuffers.SAME_L_DST);
const u32 same_prv = RevbGetIndexer(R ? RevBuffers.SAME_R_PRV : RevBuffers.SAME_L_PRV);
const u32 diff_src = RevbGetIndexer(R ? RevBuffers.DIFF_L_SRC : RevBuffers.DIFF_R_SRC);
const u32 diff_dst = RevbGetIndexer(R ? RevBuffers.DIFF_R_DST : RevBuffers.DIFF_L_DST);
const u32 diff_prv = RevbGetIndexer(R ? RevBuffers.DIFF_R_PRV : RevBuffers.DIFF_L_PRV);
const u32 comb1_src = RevbGetIndexer(R ? RevBuffers.COMB1_R_SRC : RevBuffers.COMB1_L_SRC);
const u32 comb2_src = RevbGetIndexer(R ? RevBuffers.COMB2_R_SRC : RevBuffers.COMB2_L_SRC);
const u32 comb3_src = RevbGetIndexer(R ? RevBuffers.COMB3_R_SRC : RevBuffers.COMB3_L_SRC);
const u32 comb4_src = RevbGetIndexer(R ? RevBuffers.COMB4_R_SRC : RevBuffers.COMB4_L_SRC);
const u32 apf1_src = RevbGetIndexer(R ? RevBuffers.APF1_R_SRC : RevBuffers.APF1_L_SRC);
const u32 apf1_dst = RevbGetIndexer(R ? RevBuffers.APF1_R_DST : RevBuffers.APF1_L_DST);
const u32 apf2_src = RevbGetIndexer(R ? RevBuffers.APF2_R_SRC : RevBuffers.APF2_L_SRC);
const u32 apf2_dst = RevbGetIndexer(R ? RevBuffers.APF2_R_DST : RevBuffers.APF2_L_DST);
// -----------------------------------------
// Optimized IRQ Testing !
// -----------------------------------------
// This test is enhanced by using the reverb effects area begin/end test as a
// shortcut, since all buffer addresses are within that area. If the IRQA isn't
// within that zone then the "bulk" of the test is skipped, so this should only
// be a slowdown on a few evil games.
for (int i = 0; i < 2; i++) {
if (Cores[i].IRQEnable && ((Cores[i].IRQA >= EffectsStartA) && (Cores[i].IRQA <= EffectsEndA))) {
if ((Cores[i].IRQA == same_src) || (Cores[i].IRQA == diff_src) ||
(Cores[i].IRQA == same_dst) || (Cores[i].IRQA == diff_dst) ||
(Cores[i].IRQA == same_prv) || (Cores[i].IRQA == diff_prv) ||
(Cores[i].IRQA == comb1_src) || (Cores[i].IRQA == comb2_src) ||
(Cores[i].IRQA == comb3_src) || (Cores[i].IRQA == comb4_src) ||
(Cores[i].IRQA == apf1_dst) || (Cores[i].IRQA == apf1_src) ||
(Cores[i].IRQA == apf2_dst) || (Cores[i].IRQA == apf2_src)) {
//printf("Core %d IRQ Called (Reverb). IRQA = %x\n",i,addr);
SetIrqCall(i);
}
}
}
// Reverb algorithm pretty much directly ripped from http://drhell.web.fc2.com/ps1/
// minus the 35 step FIR which just seems to break things.
s32 in, same, diff, apf1, apf2, out;
#define MUL(x, y) ((x) * (y) >> 15)
in = MUL(R ? Revb.IN_COEF_R : Revb.IN_COEF_L, R ? Input.Right : Input.Left);
same = MUL(Revb.IIR_VOL, in + MUL(Revb.WALL_VOL, _spu2mem[same_src]) - _spu2mem[same_prv]) + _spu2mem[same_prv];
diff = MUL(Revb.IIR_VOL, in + MUL(Revb.WALL_VOL, _spu2mem[diff_src]) - _spu2mem[diff_prv]) + _spu2mem[diff_prv];
out = MUL(Revb.COMB1_VOL, _spu2mem[comb1_src]) + MUL(Revb.COMB2_VOL, _spu2mem[comb2_src]) + MUL(Revb.COMB3_VOL, _spu2mem[comb3_src]) + MUL(Revb.COMB4_VOL, _spu2mem[comb4_src]);
apf1 = out - MUL(Revb.APF1_VOL, _spu2mem[apf1_src]);
out = _spu2mem[apf1_src] + MUL(Revb.APF1_VOL, apf1);
apf2 = out - MUL(Revb.APF2_VOL, _spu2mem[apf2_src]);
out = _spu2mem[apf2_src] + MUL(Revb.APF2_VOL, apf2);
// According to no$psx the effects always run but don't always write back, see check in V_Core::Mix
if (FxEnable) {
_spu2mem[same_dst] = clamp_mix(same);
_spu2mem[diff_dst] = clamp_mix(diff);
_spu2mem[apf1_dst] = clamp_mix(apf1);
_spu2mem[apf2_dst] = clamp_mix(apf2);
}
(R ? LastEffect.Right : LastEffect.Left) = -clamp_mix(out);
return LastEffect;
}

View File

@ -1,495 +0,0 @@
/* 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"
StereoOut32 StereoOut32::Empty(0, 0);
StereoOut32::StereoOut32(const StereoOut16 &src)
: Left(src.Left)
, Right(src.Right)
{
}
StereoOut32::StereoOut32(const StereoOutFloat &src)
: Left((s32)(src.Left * 2147483647.0f))
, Right((s32)(src.Right * 2147483647.0f))
{
}
StereoOut16 StereoOut32::DownSample() const
{
return StereoOut16(
Left >> SndOutVolumeShift,
Right >> SndOutVolumeShift);
}
StereoOut32 StereoOut16::UpSample() const
{
return StereoOut32(
Left << SndOutVolumeShift,
Right << SndOutVolumeShift);
}
class NullOutModule : public SndOutModule
{
public:
s32 Init() { return 0; }
void Close() {}
s32 Test() const { return 0; }
void Configure(uptr parent) {}
int GetEmptySampleCount() { return 0; }
const wchar_t *GetIdent() const
{
return L"nullout";
}
const wchar_t *GetLongName() const
{
return L"No Sound (Emulate SPU2 only)";
}
void ReadSettings()
{
}
void SetApiSettings(wxString api)
{
}
void WriteSettings() const
{
}
} NullOut;
SndOutModule *mods[] =
{
&NullOut,
#ifdef _MSC_VER
XAudio2Out,
DSoundOut,
WaveOut,
#endif
#if defined(_WIN32) || defined(SPU2X_PORTAUDIO)
PortaudioOut,
#endif
#if defined(SPU2X_SDL) || defined(SPU2X_SDL2)
SDLOut,
#endif
#if defined(__linux__) /* && defined(__ALSA__)*/
AlsaOut,
#endif
NULL // signals the end of our list
};
int FindOutputModuleById(const wchar_t *omodid)
{
int modcnt = 0;
while (mods[modcnt] != NULL) {
if (wcscmp(mods[modcnt]->GetIdent(), omodid) == 0)
break;
++modcnt;
}
return modcnt;
}
StereoOut32 *SndBuffer::m_buffer;
s32 SndBuffer::m_size;
__aligned(4) volatile s32 SndBuffer::m_rpos;
__aligned(4) volatile s32 SndBuffer::m_wpos;
bool SndBuffer::m_underrun_freeze;
StereoOut32 *SndBuffer::sndTempBuffer = NULL;
StereoOut16 *SndBuffer::sndTempBuffer16 = NULL;
int SndBuffer::sndTempProgress = 0;
int GetAlignedBufferSize(int comp)
{
return (comp + SndOutPacketSize - 1) & ~(SndOutPacketSize - 1);
}
// Returns TRUE if there is data to be output, or false if no data
// is available to be copied.
bool SndBuffer::CheckUnderrunStatus(int &nSamples, int &quietSampleCount)
{
quietSampleCount = 0;
int data = _GetApproximateDataInBuffer();
if (m_underrun_freeze) {
int toFill = m_size / ((SynchMode == 2) ? 32 : 400); // TimeStretch and Async off?
toFill = GetAlignedBufferSize(toFill);
// toFill is now aligned to a SndOutPacket
if (data < toFill) {
quietSampleCount = nSamples;
return false;
}
m_underrun_freeze = false;
if (MsgOverruns())
ConLog(" * SPU2 > Underrun compensation (%d packets buffered)\n", toFill / SndOutPacketSize);
lastPct = 0.0; // normalize timestretcher
} else if (data < nSamples) {
nSamples = data;
quietSampleCount = SndOutPacketSize - data;
m_underrun_freeze = true;
if (SynchMode == 0) // TimeStrech on
timeStretchUnderrun();
return nSamples != 0;
}
return true;
}
void SndBuffer::_InitFail()
{
// If a failure occurs, just initialize the NoSound driver. This'll allow
// the game to emulate properly (hopefully), albeit without sound.
OutputModule = FindOutputModuleById(NullOut.GetIdent());
mods[OutputModule]->Init();
}
int SndBuffer::_GetApproximateDataInBuffer()
{
// WARNING: not necessarily 100% up to date by the time it's used, but it will have to do.
return (m_wpos + m_size - m_rpos) % m_size;
}
void SndBuffer::_WriteSamples_Internal(StereoOut32 *bData, int nSamples)
{
// WARNING: This assumes the write will NOT wrap around,
// and also assumes there's enough free space in the buffer.
memcpy(m_buffer + m_wpos, bData, nSamples * sizeof(StereoOut32));
m_wpos = (m_wpos + nSamples) % m_size;
}
void SndBuffer::_DropSamples_Internal(int nSamples)
{
m_rpos = (m_rpos + nSamples) % m_size;
}
void SndBuffer::_ReadSamples_Internal(StereoOut32 *bData, int nSamples)
{
// WARNING: This assumes the read will NOT wrap around,
// and also assumes there's enough data in the buffer.
memcpy(bData, m_buffer + m_rpos, nSamples * sizeof(StereoOut32));
_DropSamples_Internal(nSamples);
}
void SndBuffer::_WriteSamples_Safe(StereoOut32 *bData, int nSamples)
{
// WARNING: This code assumes there's only ONE writing process.
if ((m_size - m_wpos) < nSamples) {
int b1 = m_size - m_wpos;
int b2 = nSamples - b1;
_WriteSamples_Internal(bData, b1);
_WriteSamples_Internal(bData + b1, b2);
} else {
_WriteSamples_Internal(bData, nSamples);
}
}
void SndBuffer::_ReadSamples_Safe(StereoOut32 *bData, int nSamples)
{
// WARNING: This code assumes there's only ONE reading process.
if ((m_size - m_rpos) < nSamples) {
int b1 = m_size - m_rpos;
int b2 = nSamples - b1;
_ReadSamples_Internal(bData, b1);
_ReadSamples_Internal(bData + b1, b2);
} else {
_ReadSamples_Internal(bData, nSamples);
}
}
// Note: When using with 32 bit output buffers, the user of this function is responsible
// for shifting the values to where they need to be manually. The fixed point depth of
// the sample output is determined by the SndOutVolumeShift, which is the number of bits
// to shift right to get a 16 bit result.
template <typename T>
void SndBuffer::ReadSamples(T *bData)
{
int nSamples = SndOutPacketSize;
// Problem:
// If the SPU2 gets even the least bit out of sync with the SndOut device,
// the readpos of the circular buffer will overtake the writepos,
// leading to a prolonged period of hopscotching read/write accesses (ie,
// lots of staticy crap sound for several seconds).
//
// Fix:
// If the read position overtakes the write position, abort the
// transfer immediately and force the SndOut driver to wait until
// the read buffer has filled up again before proceeding.
// This will cause one brief hiccup that can never exceed the user's
// set buffer length in duration.
int quietSamples;
if (CheckUnderrunStatus(nSamples, quietSamples)) {
pxAssume(nSamples <= SndOutPacketSize);
// WARNING: This code assumes there's only ONE reading process.
int b1 = m_size - m_rpos;
if (b1 > nSamples)
b1 = nSamples;
if (AdvancedVolumeControl) {
// First part
for (int i = 0; i < b1; i++)
bData[i].AdjustFrom(m_buffer[i + m_rpos]);
// Second part
int b2 = nSamples - b1;
for (int i = 0; i < b2; i++)
bData[i + b1].AdjustFrom(m_buffer[i]);
} else {
// First part
for (int i = 0; i < b1; i++)
bData[i].ResampleFrom(m_buffer[i + m_rpos]);
// Second part
int b2 = nSamples - b1;
for (int i = 0; i < b2; i++)
bData[i + b1].ResampleFrom(m_buffer[i]);
}
_DropSamples_Internal(nSamples);
}
// If quietSamples != 0 it means we have an underrun...
// Let's just dull out some silence, because that's usually the least
// painful way of dealing with underruns:
std::fill_n(bData, quietSamples, T{});
}
template void SndBuffer::ReadSamples(StereoOut16 *);
template void SndBuffer::ReadSamples(StereoOut32 *);
//template void SndBuffer::ReadSamples(StereoOutFloat*);
template void SndBuffer::ReadSamples(Stereo21Out16 *);
template void SndBuffer::ReadSamples(Stereo40Out16 *);
template void SndBuffer::ReadSamples(Stereo41Out16 *);
template void SndBuffer::ReadSamples(Stereo51Out16 *);
template void SndBuffer::ReadSamples(Stereo51Out16Dpl *);
template void SndBuffer::ReadSamples(Stereo51Out16DplII *);
template void SndBuffer::ReadSamples(Stereo71Out16 *);
template void SndBuffer::ReadSamples(Stereo20Out32 *);
template void SndBuffer::ReadSamples(Stereo21Out32 *);
template void SndBuffer::ReadSamples(Stereo40Out32 *);
template void SndBuffer::ReadSamples(Stereo41Out32 *);
template void SndBuffer::ReadSamples(Stereo51Out32 *);
template void SndBuffer::ReadSamples(Stereo51Out32Dpl *);
template void SndBuffer::ReadSamples(Stereo51Out32DplII *);
template void SndBuffer::ReadSamples(Stereo71Out32 *);
void SndBuffer::_WriteSamples(StereoOut32 *bData, int nSamples)
{
m_predictData = 0;
// Problem:
// If the SPU2 gets out of sync with the SndOut device, the writepos of the
// circular buffer will overtake the readpos, leading to a prolonged period
// of hopscotching read/write accesses (ie, lots of staticy crap sound for
// several seconds).
//
// Compromise:
// When an overrun occurs, we adapt by discarding a portion of the buffer.
// The older portion of the buffer is discarded rather than incoming data,
// so that the overall audio synchronization is better.
int free = m_size - _GetApproximateDataInBuffer(); // -1, but the <= handles that
if (free <= nSamples) {
// Disabled since the lock-free queue can't handle changing the read end from the write thread
#if 0
// Buffer overrun!
// Dump samples from the read portion of the buffer instead of dropping
// the newly written stuff.
s32 comp;
if( SynchMode == 0 ) // TimeStrech on
{
comp = timeStretchOverrun();
}
else
{
// Toss half the buffer plus whatever's being written anew:
comp = GetAlignedBufferSize( (m_size + nSamples ) / 16 );
if( comp > (m_size-SndOutPacketSize) ) comp = m_size-SndOutPacketSize;
}
_DropSamples_Internal(comp);
if( MsgOverruns() )
ConLog(" * SPU2 > Overrun Compensation (%d packets tossed)\n", comp / SndOutPacketSize );
lastPct = 0.0; // normalize the timestretcher
#else
if (MsgOverruns())
ConLog(" * SPU2 > Overrun! 1 packet tossed)\n");
lastPct = 0.0; // normalize the timestretcher
return;
#endif
}
_WriteSamples_Safe(bData, nSamples);
}
void SndBuffer::Init()
{
if (mods[OutputModule] == NULL) {
_InitFail();
return;
}
// initialize sound buffer
// Buffer actually attempts to run ~50%, so allocate near double what
// the requested latency is:
m_rpos = 0;
m_wpos = 0;
try {
const float latencyMS = SndOutLatencyMS * 16;
m_size = GetAlignedBufferSize((int)(latencyMS * SampleRate / 1000.0f));
printf("%d SampleRate: \n", SampleRate);
m_buffer = new StereoOut32[m_size];
m_underrun_freeze = false;
sndTempBuffer = new StereoOut32[SndOutPacketSize];
sndTempBuffer16 = new StereoOut16[SndOutPacketSize * 2]; // in case of leftovers.
} catch (std::bad_alloc &) {
// out of memory exception (most likely)
SysMessage("Out of memory error occurred while initializing SPU2.");
_InitFail();
return;
}
sndTempProgress = 0;
soundtouchInit(); // initializes the timestretching
// initialize module
if (mods[OutputModule]->Init() == -1)
_InitFail();
}
void SndBuffer::Cleanup()
{
mods[OutputModule]->Close();
soundtouchCleanup();
safe_delete_array(m_buffer);
safe_delete_array(sndTempBuffer);
safe_delete_array(sndTempBuffer16);
}
int SndBuffer::m_dsp_progress = 0;
int SndBuffer::m_timestretch_progress = 0;
int SndBuffer::ssFreeze = 0;
void SndBuffer::ClearContents()
{
SndBuffer::soundtouchClearContents();
SndBuffer::ssFreeze = 256; //Delays sound output for about 1 second.
}
void SndBuffer::Write(const StereoOut32 &Sample)
{
// Log final output to wavefile.
WaveDump::WriteCore(1, CoreSrc_External, Sample.DownSample());
if (WavRecordEnabled)
RecordWrite(Sample.DownSample());
if (mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p
return;
sndTempBuffer[sndTempProgress++] = Sample;
// If we haven't accumulated a full packet yet, do nothing more:
if (sndTempProgress < SndOutPacketSize)
return;
sndTempProgress = 0;
//Don't play anything directly after loading a savestate, avoids static killing your speakers.
if (ssFreeze > 0) {
ssFreeze--;
// Play silence
std::fill_n(sndTempBuffer, SndOutPacketSize, StereoOut32{});
}
#ifndef __POSIX__
if (dspPluginEnabled) {
// Convert in, send to winamp DSP, and convert out.
int ei = m_dsp_progress;
for (int i = 0; i < SndOutPacketSize; ++i, ++ei) {
sndTempBuffer16[ei] = sndTempBuffer[i].DownSample();
}
m_dsp_progress += DspProcess((s16 *)sndTempBuffer16 + m_dsp_progress, SndOutPacketSize);
// Some ugly code to ensure full packet handling:
ei = 0;
while (m_dsp_progress >= SndOutPacketSize) {
for (int i = 0; i < SndOutPacketSize; ++i, ++ei) {
sndTempBuffer[i] = sndTempBuffer16[ei].UpSample();
}
if (SynchMode == 0) // TimeStrech on
timeStretchWrite();
else
_WriteSamples(sndTempBuffer, SndOutPacketSize);
m_dsp_progress -= SndOutPacketSize;
}
// copy any leftovers to the front of the dsp buffer.
if (m_dsp_progress > 0) {
memcpy(sndTempBuffer16, &sndTempBuffer16[ei],
sizeof(sndTempBuffer16[0]) * m_dsp_progress);
}
}
#endif
else {
if (SynchMode == 0) // TimeStrech on
timeStretchWrite();
else
_WriteSamples(sndTempBuffer, SndOutPacketSize);
}
}
s32 SndBuffer::Test()
{
if (mods[OutputModule] == NULL)
return -1;
return mods[OutputModule]->Test();
}

View File

@ -1,698 +0,0 @@
/* 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
// Number of stereo samples per SndOut block.
// All drivers must work in units of this size when communicating with
// SndOut.
static const int SndOutPacketSize = 64;
// Overall master volume shift; this is meant to be a precision value and does not affect
// actual output volumes. It converts SPU2 16 bit volumes to 32-bit volumes, and likewise
// downsamples 32 bit samples to 16 bit sound driver output (this way timestretching and
// DSP effects get better precision results)
static const int SndOutVolumeShift = 12;
static const int SndOutVolumeShift32 = 16 - SndOutVolumeShift; // shift up, not down
// Samplerate of the SPU2. For accurate playback we need to match this
// exactly. Trying to scale samplerates and maintain SPU2's Ts timing accuracy
// is too problematic. :)
extern int SampleRate;
extern int FindOutputModuleById(const wchar_t *omodid);
// Implemented in Config.cpp
extern float VolumeAdjustFL;
extern float VolumeAdjustC;
extern float VolumeAdjustFR;
extern float VolumeAdjustBL;
extern float VolumeAdjustBR;
extern float VolumeAdjustSL;
extern float VolumeAdjustSR;
extern float VolumeAdjustLFE;
extern unsigned int delayCycles;
struct Stereo51Out16DplII;
struct Stereo51Out32DplII;
struct Stereo51Out16Dpl; // similar to DplII but without rear balancing
struct Stereo51Out32Dpl;
extern void ResetDplIIDecoder();
extern void ProcessDplIISample16(const StereoOut32 &src, Stereo51Out16DplII *s);
extern void ProcessDplIISample32(const StereoOut32 &src, Stereo51Out32DplII *s);
extern void ProcessDplSample16(const StereoOut32 &src, Stereo51Out16Dpl *s);
extern void ProcessDplSample32(const StereoOut32 &src, Stereo51Out32Dpl *s);
struct StereoOut16
{
s16 Left;
s16 Right;
StereoOut16()
: Left(0)
, Right(0)
{
}
StereoOut16(const StereoOut32 &src)
: Left((s16)src.Left)
, Right((s16)src.Right)
{
}
StereoOut16(s16 left, s16 right)
: Left(left)
, Right(right)
{
}
StereoOut32 UpSample() const;
void ResampleFrom(const StereoOut32 &src)
{
// Use StereoOut32's built in conversion
*this = src.DownSample();
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s16)(Left * VolumeAdjustFL);
Right = (s16)(Right * VolumeAdjustFR);
}
};
struct StereoOutFloat
{
float Left;
float Right;
StereoOutFloat()
: Left(0)
, Right(0)
{
}
explicit StereoOutFloat(const StereoOut32 &src)
: Left(src.Left / 2147483647.0f)
, Right(src.Right / 2147483647.0f)
{
}
explicit StereoOutFloat(s32 left, s32 right)
: Left(left / 2147483647.0f)
, Right(right / 2147483647.0f)
{
}
StereoOutFloat(float left, float right)
: Left(left)
, Right(right)
{
}
};
struct Stereo21Out16
{
s16 Left;
s16 Right;
s16 LFE;
void ResampleFrom(const StereoOut32 &src)
{
Left = src.Left >> SndOutVolumeShift;
Right = src.Right >> SndOutVolumeShift;
LFE = (src.Left + src.Right) >> (SndOutVolumeShift + 1);
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s16)(Left * VolumeAdjustFL);
Right = (s16)(Right * VolumeAdjustFR);
LFE = (s16)(LFE * VolumeAdjustLFE);
}
};
struct Stereo40Out16
{
s16 Left;
s16 Right;
s16 LeftBack;
s16 RightBack;
void ResampleFrom(const StereoOut32 &src)
{
Left = src.Left >> SndOutVolumeShift;
Right = src.Right >> SndOutVolumeShift;
LeftBack = src.Left >> SndOutVolumeShift;
RightBack = src.Right >> SndOutVolumeShift;
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s16)(Left * VolumeAdjustFL);
Right = (s16)(Right * VolumeAdjustFR);
LeftBack = (s16)(LeftBack * VolumeAdjustBL);
RightBack = (s16)(RightBack * VolumeAdjustBR);
}
};
struct Stereo40Out32
{
s32 Left;
s32 Right;
s32 LeftBack;
s32 RightBack;
void ResampleFrom(const StereoOut32 &src)
{
Left = src.Left << SndOutVolumeShift32;
Right = src.Right << SndOutVolumeShift32;
LeftBack = src.Left << SndOutVolumeShift32;
RightBack = src.Right << SndOutVolumeShift32;
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s32)(Left * VolumeAdjustFL);
Right = (s32)(Right * VolumeAdjustFR);
LeftBack = (s32)(LeftBack * VolumeAdjustBL);
RightBack = (s32)(RightBack * VolumeAdjustBR);
}
};
struct Stereo41Out16
{
s16 Left;
s16 Right;
s16 LFE;
s16 LeftBack;
s16 RightBack;
void ResampleFrom(const StereoOut32 &src)
{
Left = src.Left >> SndOutVolumeShift;
Right = src.Right >> SndOutVolumeShift;
LFE = (src.Left + src.Right) >> (SndOutVolumeShift + 1);
LeftBack = src.Left >> SndOutVolumeShift;
RightBack = src.Right >> SndOutVolumeShift;
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s32)(Left * VolumeAdjustFL);
Right = (s32)(Right * VolumeAdjustFR);
LeftBack = (s32)(LeftBack * VolumeAdjustBL);
RightBack = (s32)(RightBack * VolumeAdjustBR);
LFE = (s32)(LFE * VolumeAdjustLFE);
}
};
struct Stereo51Out16
{
s16 Left;
s16 Right;
s16 Center;
s16 LFE;
s16 LeftBack;
s16 RightBack;
// Implementation Note: Center and Subwoofer/LFE -->
// This method is simple and sounds nice. It relies on the speaker/soundcard
// systems do to their own low pass / crossover. Manual lowpass is wasted effort
// and can't match solid state results anyway.
void ResampleFrom(const StereoOut32 &src)
{
Left = src.Left >> SndOutVolumeShift;
Right = src.Right >> SndOutVolumeShift;
Center = (src.Left + src.Right) >> (SndOutVolumeShift + 1);
LFE = Center;
LeftBack = src.Left >> SndOutVolumeShift;
RightBack = src.Right >> SndOutVolumeShift;
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s16)(Left * VolumeAdjustFL);
Right = (s16)(Right * VolumeAdjustFR);
LeftBack = (s16)(LeftBack * VolumeAdjustBL);
RightBack = (s16)(RightBack * VolumeAdjustBR);
Center = (s16)(Center * VolumeAdjustC);
LFE = (s16)(LFE * VolumeAdjustLFE);
}
};
struct Stereo51Out16DplII
{
s16 Left;
s16 Right;
s16 Center;
s16 LFE;
s16 LeftBack;
s16 RightBack;
void ResampleFrom(const StereoOut32 &src)
{
ProcessDplIISample16(src, this);
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s32)(Left * VolumeAdjustFL);
Right = (s32)(Right * VolumeAdjustFR);
LeftBack = (s32)(LeftBack * VolumeAdjustBL);
RightBack = (s32)(RightBack * VolumeAdjustBR);
Center = (s32)(Center * VolumeAdjustC);
LFE = (s32)(LFE * VolumeAdjustLFE);
}
};
struct Stereo51Out32DplII
{
s32 Left;
s32 Right;
s32 Center;
s32 LFE;
s32 LeftBack;
s32 RightBack;
void ResampleFrom(const StereoOut32 &src)
{
ProcessDplIISample32(src, this);
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s32)(Left * VolumeAdjustFL);
Right = (s32)(Right * VolumeAdjustFR);
LeftBack = (s32)(LeftBack * VolumeAdjustBL);
RightBack = (s32)(RightBack * VolumeAdjustBR);
Center = (s32)(Center * VolumeAdjustC);
LFE = (s32)(LFE * VolumeAdjustLFE);
}
};
struct Stereo51Out16Dpl
{
s16 Left;
s16 Right;
s16 Center;
s16 LFE;
s16 LeftBack;
s16 RightBack;
void ResampleFrom(const StereoOut32 &src)
{
ProcessDplSample16(src, this);
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s32)(Left * VolumeAdjustFL);
Right = (s32)(Right * VolumeAdjustFR);
LeftBack = (s32)(LeftBack * VolumeAdjustBL);
RightBack = (s32)(RightBack * VolumeAdjustBR);
Center = (s32)(Center * VolumeAdjustC);
LFE = (s32)(LFE * VolumeAdjustLFE);
}
};
struct Stereo51Out32Dpl
{
s32 Left;
s32 Right;
s32 Center;
s32 LFE;
s32 LeftBack;
s32 RightBack;
void ResampleFrom(const StereoOut32 &src)
{
ProcessDplSample32(src, this);
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s32)(Left * VolumeAdjustFL);
Right = (s32)(Right * VolumeAdjustFR);
LeftBack = (s32)(LeftBack * VolumeAdjustBL);
RightBack = (s32)(RightBack * VolumeAdjustBR);
Center = (s32)(Center * VolumeAdjustC);
LFE = (s32)(LFE * VolumeAdjustLFE);
}
};
struct Stereo71Out16
{
s16 Left;
s16 Right;
s16 Center;
s16 LFE;
s16 LeftBack;
s16 RightBack;
s16 LeftSide;
s16 RightSide;
void ResampleFrom(const StereoOut32 &src)
{
Left = src.Left >> SndOutVolumeShift;
Right = src.Right >> SndOutVolumeShift;
Center = (src.Left + src.Right) >> (SndOutVolumeShift + 1);
LFE = Center;
LeftBack = src.Left >> SndOutVolumeShift;
RightBack = src.Right >> SndOutVolumeShift;
LeftSide = src.Left >> (SndOutVolumeShift + 1);
RightSide = src.Right >> (SndOutVolumeShift + 1);
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s16)(Left * VolumeAdjustFL);
Right = (s16)(Right * VolumeAdjustFR);
LeftBack = (s16)(LeftBack * VolumeAdjustBL);
RightBack = (s16)(RightBack * VolumeAdjustBR);
LeftSide = (s16)(LeftBack * VolumeAdjustSL);
RightSide = (s16)(RightBack * VolumeAdjustSR);
Center = (s16)(Center * VolumeAdjustC);
LFE = (s16)(LFE * VolumeAdjustLFE);
}
};
struct Stereo71Out32
{
s32 Left;
s32 Right;
s32 Center;
s32 LFE;
s32 LeftBack;
s32 RightBack;
s32 LeftSide;
s32 RightSide;
void ResampleFrom(const StereoOut32 &src)
{
Left = src.Left << SndOutVolumeShift32;
Right = src.Right << SndOutVolumeShift32;
Center = (src.Left + src.Right) << (SndOutVolumeShift32 - 1);
LFE = Center;
LeftBack = src.Left << SndOutVolumeShift32;
RightBack = src.Right << SndOutVolumeShift32;
LeftSide = src.Left << (SndOutVolumeShift32 - 1);
RightSide = src.Right << (SndOutVolumeShift32 - 1);
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s32)(Left * VolumeAdjustFL);
Right = (s32)(Right * VolumeAdjustFR);
LeftBack = (s32)(LeftBack * VolumeAdjustBL);
RightBack = (s32)(RightBack * VolumeAdjustBR);
LeftSide = (s32)(LeftBack * VolumeAdjustSL);
RightSide = (s32)(RightBack * VolumeAdjustSR);
Center = (s32)(Center * VolumeAdjustC);
LFE = (s32)(LFE * VolumeAdjustLFE);
}
};
struct Stereo20Out32
{
s32 Left;
s32 Right;
void ResampleFrom(const StereoOut32 &src)
{
Left = src.Left << SndOutVolumeShift32;
Right = src.Right << SndOutVolumeShift32;
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s32)(Left * VolumeAdjustFL);
Right = (s32)(Right * VolumeAdjustFR);
}
};
struct Stereo21Out32
{
s32 Left;
s32 Right;
s32 LFE;
void ResampleFrom(const StereoOut32 &src)
{
Left = src.Left << SndOutVolumeShift32;
Right = src.Right << SndOutVolumeShift32;
LFE = (src.Left + src.Right) << (SndOutVolumeShift32 - 1);
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s32)(Left * VolumeAdjustFL);
Right = (s32)(Right * VolumeAdjustFR);
LFE = (s32)(LFE * VolumeAdjustLFE);
}
};
struct Stereo41Out32
{
s32 Left;
s32 Right;
s32 LFE;
s32 LeftBack;
s32 RightBack;
void ResampleFrom(const StereoOut32 &src)
{
Left = src.Left << SndOutVolumeShift32;
Right = src.Right << SndOutVolumeShift32;
LFE = (src.Left + src.Right) << (SndOutVolumeShift32 - 1);
LeftBack = src.Left << SndOutVolumeShift32;
RightBack = src.Right << SndOutVolumeShift32;
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s32)(Left * VolumeAdjustFL);
Right = (s32)(Right * VolumeAdjustFR);
LeftBack = (s32)(LeftBack * VolumeAdjustBL);
RightBack = (s32)(RightBack * VolumeAdjustBR);
LFE = (s32)(LFE * VolumeAdjustLFE);
}
};
struct Stereo51Out32
{
s32 Left;
s32 Right;
s32 Center;
s32 LFE;
s32 LeftBack;
s32 RightBack;
void ResampleFrom(const StereoOut32 &src)
{
Left = src.Left << SndOutVolumeShift32;
Right = src.Right << SndOutVolumeShift32;
Center = (src.Left + src.Right) << (SndOutVolumeShift32 - 1);
LFE = Center;
LeftBack = src.Left << SndOutVolumeShift32;
RightBack = src.Right << SndOutVolumeShift32;
}
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s32)(Left * VolumeAdjustFL);
Right = (s32)(Right * VolumeAdjustFR);
LeftBack = (s32)(LeftBack * VolumeAdjustBL);
RightBack = (s32)(RightBack * VolumeAdjustBR);
Center = (s32)(Center * VolumeAdjustC);
LFE = (s32)(LFE * VolumeAdjustLFE);
}
};
// Developer Note: This is a static class only (all static members).
class SndBuffer
{
private:
static bool m_underrun_freeze;
static s32 m_predictData;
static float lastPct;
static StereoOut32 *sndTempBuffer;
static StereoOut16 *sndTempBuffer16;
static int sndTempProgress;
static int m_dsp_progress;
static int m_timestretch_progress;
static int m_timestretch_writepos;
static StereoOut32 *m_buffer;
static s32 m_size;
static __aligned(4) volatile s32 m_rpos;
static __aligned(4) volatile s32 m_wpos;
static float lastEmergencyAdj;
static float cTempo;
static float eTempo;
static int ssFreeze;
static void _InitFail();
static bool CheckUnderrunStatus(int &nSamples, int &quietSampleCount);
static void soundtouchInit();
static void soundtouchClearContents();
static void soundtouchCleanup();
static void timeStretchWrite();
static void timeStretchUnderrun();
static s32 timeStretchOverrun();
static void PredictDataWrite(int samples);
static float GetStatusPct();
static void UpdateTempoChangeSoundTouch();
static void UpdateTempoChangeSoundTouch2();
static void _WriteSamples(StereoOut32 *bData, int nSamples);
static void _WriteSamples_Safe(StereoOut32 *bData, int nSamples);
static void _ReadSamples_Safe(StereoOut32 *bData, int nSamples);
static void _WriteSamples_Internal(StereoOut32 *bData, int nSamples);
static void _DropSamples_Internal(int nSamples);
static void _ReadSamples_Internal(StereoOut32 *bData, int nSamples);
static int _GetApproximateDataInBuffer();
public:
static void UpdateTempoChangeAsyncMixing();
static void Init();
static void Cleanup();
static void Write(const StereoOut32 &Sample);
static s32 Test();
static void ClearContents();
// Note: When using with 32 bit output buffers, the user of this function is responsible
// for shifting the values to where they need to be manually. The fixed point depth of
// the sample output is determined by the SndOutVolumeShift, which is the number of bits
// to shift right to get a 16 bit result.
template <typename T>
static void ReadSamples(T *bData);
};
class SndOutModule
{
public:
// Virtual destructor, because it helps fight C+++ funny-business.
virtual ~SndOutModule() {}
// Returns a unique identification string for this driver.
// (usually just matches the driver's cpp filename)
virtual const wchar_t *GetIdent() const = 0;
// Returns the long name / description for this driver.
// (for use in configuration screen)
virtual const wchar_t *GetLongName() const = 0;
virtual s32 Init() = 0;
virtual void Close() = 0;
virtual s32 Test() const = 0;
// Gui function: Used to open the configuration box for this driver.
virtual void Configure(uptr parent) = 0;
// Loads settings from the INI file for this driver
virtual void ReadSettings() = 0;
// Set output API for this driver
virtual void SetApiSettings(wxString api) = 0;
// Saves settings to the INI file for this driver
virtual void WriteSettings() const = 0;
// Returns the number of empty samples in the output buffer.
// (which is effectively the amount of data played since the last update)
virtual int GetEmptySampleCount() = 0;
};
#ifdef _MSC_VER
//internal
extern SndOutModule *WaveOut;
extern SndOutModule *DSoundOut;
extern SndOutModule *XAudio2Out;
#endif
#if defined(_WIN32) || defined(SPU2X_PORTAUDIO)
extern SndOutModule *PortaudioOut;
#endif
#if defined(SPU2X_SDL) || defined(SPU2X_SDL2)
extern SndOutModule *const SDLOut;
#endif
#ifdef __linux__
extern SndOutModule *AlsaOut;
#endif
extern SndOutModule *mods[];
// =====================================================================================================
extern bool WavRecordEnabled;
extern void RecordStart(std::wstring* filename);
extern void RecordStop();
extern void RecordWrite(const StereoOut16 &sample);
extern s32 DspLoadLibrary(wchar_t *fileName, int modNum);
extern void DspCloseLibrary();
extern int DspProcess(s16 *buffer, int samples);
extern void DspUpdate(); // to let the Dsp process window messages

View File

@ -1,686 +0,0 @@
/* 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"
#define _WIN32_DCOM
#include "Dialogs.h"
#include "portaudio.h"
#include "wchar.h"
#include <vector>
#ifdef _WIN32
#include "pa_win_wasapi.h"
#endif
int PaCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData);
class Portaudio : public SndOutModule
{
private:
//////////////////////////////////////////////////////////////////////////////////////////
// Configuration Vars (unused still)
int m_ApiId;
wxString m_Device;
bool m_UseHardware;
bool m_WasapiExclusiveMode;
bool m_SuggestedLatencyMinimal;
int m_SuggestedLatencyMS;
//////////////////////////////////////////////////////////////////////////////////////////
// Instance vars
int writtenSoFar;
int writtenLastTime;
int availableLastTime;
int actualUsedChannels;
bool started;
PaStream *stream;
//////////////////////////////////////////////////////////////////////////////////////////
// Stuff necessary for speaker expansion
class SampleReader
{
public:
virtual int ReadSamples(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData) = 0;
};
template <class T>
class ConvertedSampleReader : public SampleReader
{
int *written;
public:
ConvertedSampleReader(int *pWritten)
{
written = pWritten;
}
virtual int ReadSamples(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData)
{
T *p1 = (T *)outputBuffer;
int packets = framesPerBuffer / SndOutPacketSize;
for (int p = 0; p < packets; p++, p1 += SndOutPacketSize)
SndBuffer::ReadSamples(p1);
(*written) += packets * SndOutPacketSize;
return 0;
}
};
public:
SampleReader *ActualPaCallback;
Portaudio()
{
m_SuggestedLatencyMinimal = true;
m_UseHardware = false;
m_WasapiExclusiveMode = false;
started = false;
stream = NULL;
ActualPaCallback = NULL;
m_ApiId = -1;
m_SuggestedLatencyMS = 20;
actualUsedChannels = 0;
writtenSoFar = 0;
writtenLastTime = 0;
availableLastTime = 0;
}
s32 Init()
{
started = false;
stream = NULL;
ReadSettings();
PaError err = Pa_Initialize();
if (err != paNoError) {
fprintf(stderr, "* SPU2-X: PortAudio error: %s\n", Pa_GetErrorText(err));
return -1;
}
started = true;
int deviceIndex = -1;
fprintf(stderr, "* SPU2-X: Enumerating PortAudio devices:\n");
for (int i = 0, j = 0; i < Pa_GetDeviceCount(); i++) {
const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
if (info->maxOutputChannels > 0) {
const PaHostApiInfo *apiinfo = Pa_GetHostApiInfo(info->hostApi);
fprintf(stderr, " *** Device %d: '%s' (%s)", j, info->name, apiinfo->name);
if (apiinfo->type == m_ApiId) {
if (m_Device == wxString::FromUTF8(info->name)) {
deviceIndex = i;
fprintf(stderr, " (selected)");
}
}
fprintf(stderr, "\n");
j++;
}
}
fflush(stderr);
if (deviceIndex < 0 && m_ApiId >= 0) {
for (int i = 0; i < Pa_GetHostApiCount(); i++) {
const PaHostApiInfo *apiinfo = Pa_GetHostApiInfo(i);
if (apiinfo->type == m_ApiId) {
deviceIndex = apiinfo->defaultOutputDevice;
}
}
}
if (deviceIndex >= 0) {
void *infoPtr = NULL;
const PaDeviceInfo *devinfo = Pa_GetDeviceInfo(deviceIndex);
int speakers;
switch (numSpeakers) // speakers = (numSpeakers + 1) *2; ?
{
case 0:
speakers = 2;
break; // Stereo
case 1:
speakers = 4;
break; // Quadrafonic
case 2:
speakers = 6;
break; // Surround 5.1
case 3:
speakers = 8;
break; // Surround 7.1
default:
speakers = 2;
}
actualUsedChannels = std::min(speakers, devinfo->maxOutputChannels);
switch (actualUsedChannels) {
case 2:
ConLog("* SPU2 > Using normal 2 speaker stereo output.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo20Out32>(&writtenSoFar);
break;
case 3:
ConLog("* SPU2 > 2.1 speaker expansion enabled.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo21Out32>(&writtenSoFar);
break;
case 4:
ConLog("* SPU2 > 4 speaker expansion enabled [quadraphenia]\n");
ActualPaCallback = new ConvertedSampleReader<Stereo40Out32>(&writtenSoFar);
break;
case 5:
ConLog("* SPU2 > 4.1 speaker expansion enabled.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo41Out32>(&writtenSoFar);
break;
case 6:
case 7:
switch (dplLevel) {
case 0:
ConLog("* SPU2 > 5.1 speaker expansion enabled.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo51Out32>(&writtenSoFar); //"normal" stereo upmix
break;
case 1:
ConLog("* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo51Out32Dpl>(&writtenSoFar); // basic Dpl decoder without rear stereo balancing
break;
case 2:
ConLog("* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo51Out32DplII>(&writtenSoFar); //gigas PLII
break;
}
actualUsedChannels = 6; // we do not support 7.0 or 6.2 configurations, downgrade to 5.1
break;
default: // anything 8 or more gets the 7.1 treatment!
ConLog("* SPU2 > 7.1 speaker expansion enabled.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo71Out32>(&writtenSoFar);
actualUsedChannels = 8; // we do not support 7.2 or more, downgrade to 7.1
break;
}
#ifdef _WIN32
PaWasapiStreamInfo info = {
sizeof(PaWasapiStreamInfo),
paWASAPI,
1,
paWinWasapiExclusive};
if ((m_ApiId == paWASAPI) && m_WasapiExclusiveMode) {
// Pass it the Exclusive mode enable flag
infoPtr = &info;
}
#endif
PaStreamParameters outParams = {
// PaDeviceIndex device;
// int channelCount;
// PaSampleFormat sampleFormat;
// PaTime suggestedLatency;
// void *hostApiSpecificStreamInfo;
deviceIndex,
actualUsedChannels,
paInt32,
m_SuggestedLatencyMinimal ? (SndOutPacketSize / (float)SampleRate) : (m_SuggestedLatencyMS / 1000.0f),
infoPtr};
err = Pa_OpenStream(&stream,
NULL, &outParams, SampleRate,
SndOutPacketSize,
paNoFlag,
PaCallback,
NULL);
} else {
err = Pa_OpenDefaultStream(&stream,
0, actualUsedChannels, paInt32, 48000,
SndOutPacketSize,
PaCallback,
NULL);
}
if (err != paNoError) {
fprintf(stderr, "* SPU2-X: PortAudio error: %s\n", Pa_GetErrorText(err));
Pa_Terminate();
return -1;
}
err = Pa_StartStream(stream);
if (err != paNoError) {
fprintf(stderr, "* SPU2-X: PortAudio error: %s\n", Pa_GetErrorText(err));
Pa_CloseStream(stream);
stream = NULL;
Pa_Terminate();
return -1;
}
return 0;
}
void Close()
{
PaError err;
if (started) {
if (stream) {
if (Pa_IsStreamActive(stream)) {
err = Pa_StopStream(stream);
if (err != paNoError)
fprintf(stderr, "* SPU2-X: PortAudio error: %s\n", Pa_GetErrorText(err));
}
err = Pa_CloseStream(stream);
if (err != paNoError)
fprintf(stderr, "* SPU2-X: PortAudio error: %s\n", Pa_GetErrorText(err));
stream = NULL;
}
// Seems to do more harm than good.
//PaError err = Pa_Terminate();
//if( err != paNoError )
// fprintf(stderr,"* SPU2-X: PortAudio error: %s\n", Pa_GetErrorText( err ) );
started = false;
}
}
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
#ifdef _WIN32
private:
bool _ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
int tSel = 0;
switch (uMsg) {
case WM_INITDIALOG: {
wchar_t temp[128];
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_RESETCONTENT, 0, 0);
SendMessageA(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_ADDSTRING, 0, (LPARAM) "Default Device");
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETCURSEL, 0, 0);
SendMessage(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_RESETCONTENT, 0, 0);
SendMessageA(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_ADDSTRING, 0, (LPARAM) "Unspecified");
int idx = 0;
for (int i = 0; i < Pa_GetHostApiCount(); i++) {
const PaHostApiInfo *apiinfo = Pa_GetHostApiInfo(i);
if (apiinfo->deviceCount > 0) {
SendMessageA(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_ADDSTRING, 0, (LPARAM)apiinfo->name);
SendMessageA(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_SETITEMDATA, i + 1, apiinfo->type);
}
if (apiinfo->type == m_ApiId) {
idx = i + 1;
}
}
SendMessage(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_SETCURSEL, idx, 0);
if (idx > 0) {
int api_idx = idx - 1;
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_RESETCONTENT, 0, 0);
SendMessageA(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_ADDSTRING, 0, (LPARAM) "Default Device");
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETITEMDATA, 0, 0);
int _idx = 0;
int i = 1;
for (int j = 0; j < Pa_GetDeviceCount(); j++) {
const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
if (info->hostApi == api_idx && info->maxOutputChannels > 0) {
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_ADDSTRING, 0, (LPARAM)wxString::FromUTF8(info->name).wc_str());
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETITEMDATA, i, (LPARAM)info);
if (wxString::FromUTF8(info->name) == m_Device) {
_idx = i;
}
i++;
}
}
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETCURSEL, _idx, 0);
}
INIT_SLIDER(IDC_LATENCY, 10, 200, 10, 1, 1);
SendMessage(GetDlgItem(hWnd, IDC_LATENCY), TBM_SETPOS, TRUE, m_SuggestedLatencyMS);
swprintf_s(temp, L"%d ms", m_SuggestedLatencyMS);
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
if (m_SuggestedLatencyMinimal)
SET_CHECK(IDC_MINIMIZE, true);
else
SET_CHECK(IDC_MANUAL, true);
SET_CHECK(IDC_EXCLUSIVE, m_WasapiExclusiveMode);
} break;
case WM_COMMAND: {
//wchar_t temp[128];
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId) {
case IDOK: {
int idx = (int)SendMessage(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_GETCURSEL, 0, 0);
m_ApiId = SendMessage(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_GETITEMDATA, idx, 0);
idx = (int)SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_GETCURSEL, 0, 0);
const PaDeviceInfo *info = (const PaDeviceInfo *)SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_GETITEMDATA, idx, 0);
if (info)
m_Device = wxString::FromUTF8(info->name);
else
m_Device = L"default";
m_SuggestedLatencyMS = (int)SendMessage(GetDlgItem(hWnd, IDC_LATENCY), TBM_GETPOS, 0, 0);
if (m_SuggestedLatencyMS < 10)
m_SuggestedLatencyMS = 10;
if (m_SuggestedLatencyMS > 200)
m_SuggestedLatencyMS = 200;
m_SuggestedLatencyMinimal = SendMessage(GetDlgItem(hWnd, IDC_MINIMIZE), BM_GETCHECK, 0, 0) == BST_CHECKED;
m_WasapiExclusiveMode = SendMessage(GetDlgItem(hWnd, IDC_EXCLUSIVE), BM_GETCHECK, 0, 0) == BST_CHECKED;
EndDialog(hWnd, 0);
} break;
case IDCANCEL:
EndDialog(hWnd, 0);
break;
case IDC_PA_HOSTAPI: {
if (wmEvent == CBN_SELCHANGE) {
int api_idx = (int)SendMessage(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_GETCURSEL, 0, 0) - 1;
int apiId = SendMessageA(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_GETITEMDATA, api_idx, 0);
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_RESETCONTENT, 0, 0);
SendMessageA(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_ADDSTRING, 0, (LPARAM) "Default Device");
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETITEMDATA, 0, 0);
int idx = 0;
int i = 1;
for (int j = 0; j < Pa_GetDeviceCount(); j++) {
const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
if (info->hostApi == api_idx && info->maxOutputChannels > 0) {
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_ADDSTRING, 0, (LPARAM)wxString::FromUTF8(info->name).wc_str());
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETITEMDATA, i, (LPARAM)info);
i++;
}
}
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETCURSEL, idx, 0);
}
} break;
default:
return FALSE;
}
} break;
case WM_HSCROLL: {
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId) {
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_TOP:
case TB_BOTTOM:
wmEvent = (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
case TB_THUMBPOSITION:
case TB_THUMBTRACK: {
wchar_t temp[128];
if (wmEvent < 10)
wmEvent = 10;
if (wmEvent > 200)
wmEvent = 200;
SendMessage((HWND)lParam, TBM_SETPOS, TRUE, wmEvent);
swprintf_s(temp, L"%d ms", wmEvent);
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
break;
}
default:
return FALSE;
}
} break;
default:
return FALSE;
}
return TRUE;
}
static BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK DSEnumCallback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext);
public:
virtual void Configure(uptr parent)
{
PaError err = Pa_Initialize(); // Initialization can be done multiple times, PA keeps a counter
if (err != paNoError) {
fprintf(stderr, "* SPU2-X: PortAudio error: %s\n", Pa_GetErrorText(err));
return;
}
// keep portaudio initialized until the dialog closes
INT_PTR ret;
ret = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PORTAUDIO), (HWND)parent, (DLGPROC)ConfigProc, 1);
if (ret == -1) {
MessageBox((HWND)parent, L"Error Opening the config dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
Pa_Terminate();
}
#else
virtual void Configure(uptr parent)
{
}
#endif
s32 Test() const
{
return 0;
}
int GetEmptySampleCount()
{
long availableNow = Pa_GetStreamWriteAvailable(stream);
int playedSinceLastTime = (writtenSoFar - writtenLastTime) + (availableNow - availableLastTime);
writtenLastTime = writtenSoFar;
availableLastTime = availableNow;
// Lowest resolution here is the SndOutPacketSize we use.
return playedSinceLastTime;
}
const wchar_t *GetIdent() const
{
return L"portaudio";
}
const wchar_t *GetLongName() const
{
return L"PortAudio (Cross-platform)";
}
void ReadSettings()
{
wxString api(L"EMPTYEMPTYEMPTY");
m_Device = L"EMPTYEMPTYEMPTY";
#ifdef __linux__
// By default on linux use the ALSA API (+99% users) -- Gregory
CfgReadStr(L"PORTAUDIO", L"HostApi", api, L"ALSA");
#elif defined(__APPLE__)
// Suppose OSX only has CoreAudio...
CfgReadStr(L"PORTAUDIO", L"HostApi", api, L"CoreAudio");
#else
CfgReadStr(L"PORTAUDIO", L"HostApi", api, L"WASAPI");
#endif
CfgReadStr(L"PORTAUDIO", L"Device", m_Device, L"default");
SetApiSettings(api);
m_WasapiExclusiveMode = CfgReadBool(L"PORTAUDIO", L"Wasapi_Exclusive_Mode", false);
m_SuggestedLatencyMinimal = CfgReadBool(L"PORTAUDIO", L"Minimal_Suggested_Latency", true);
m_SuggestedLatencyMS = CfgReadInt(L"PORTAUDIO", L"Manual_Suggested_Latency_MS", 20);
if (m_SuggestedLatencyMS < 10)
m_SuggestedLatencyMS = 10;
if (m_SuggestedLatencyMS > 200)
m_SuggestedLatencyMS = 200;
}
void SetApiSettings(wxString api)
{
m_ApiId = -1;
if (api == L"InDevelopment")
m_ApiId = paInDevelopment; /* use while developing support for a new host API */
if (api == L"DirectSound")
m_ApiId = paDirectSound;
if (api == L"MME")
m_ApiId = paMME;
if (api == L"ASIO")
m_ApiId = paASIO;
if (api == L"SoundManager")
m_ApiId = paSoundManager;
if (api == L"CoreAudio")
m_ApiId = paCoreAudio;
if (api == L"OSS")
m_ApiId = paOSS;
if (api == L"ALSA")
m_ApiId = paALSA;
if (api == L"AL")
m_ApiId = paAL;
if (api == L"BeOS")
m_ApiId = paBeOS;
if (api == L"WDMKS")
m_ApiId = paWDMKS;
if (api == L"JACK")
m_ApiId = paJACK;
if (api == L"WASAPI")
m_ApiId = paWASAPI;
if (api == L"AudioScienceHPI")
m_ApiId = paAudioScienceHPI;
}
void WriteSettings() const
{
wxString api;
switch (m_ApiId) {
case paInDevelopment:
api = L"InDevelopment";
break; /* use while developing support for a new host API */
case paDirectSound:
api = L"DirectSound";
break;
case paMME:
api = L"MME";
break;
case paASIO:
api = L"ASIO";
break;
case paSoundManager:
api = L"SoundManager";
break;
case paCoreAudio:
api = L"CoreAudio";
break;
case paOSS:
api = L"OSS";
break;
case paALSA:
api = L"ALSA";
break;
case paAL:
api = L"AL";
break;
case paBeOS:
api = L"BeOS";
break;
case paWDMKS:
api = L"WDMKS";
break;
case paJACK:
api = L"JACK";
break;
case paWASAPI:
api = L"WASAPI";
break;
case paAudioScienceHPI:
api = L"AudioScienceHPI";
break;
default:
api = L"Unknown";
}
CfgWriteStr(L"PORTAUDIO", L"HostApi", api);
CfgWriteStr(L"PORTAUDIO", L"Device", m_Device);
CfgWriteBool(L"PORTAUDIO", L"Wasapi_Exclusive_Mode", m_WasapiExclusiveMode);
CfgWriteBool(L"PORTAUDIO", L"Minimal_Suggested_Latency", m_SuggestedLatencyMinimal);
CfgWriteInt(L"PORTAUDIO", L"Manual_Suggested_Latency_MS", m_SuggestedLatencyMS);
}
} static PA;
int PaCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData)
{
return PA.ActualPaCallback->ReadSamples(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags, userData);
}
#ifdef _WIN32
BOOL CALLBACK Portaudio::ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return PA._ConfigProc(hWnd, uMsg, wParam, lParam);
}
#endif
SndOutModule *PortaudioOut = &PA;

View File

@ -1,189 +0,0 @@
/* SDL Audio sink for SPU2-X.
* Copyright (c) 2013, Matt Scheirer <matt.scheirer@gmail.com>
*
* 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 <cassert>
#include <iostream>
#include "Global.h"
#include "SndOut.h"
#include "Dialogs.h"
#include <memory>
/* Using SDL2 requires other SDL dependencies in pcsx2 get upgraded as well, or the
* symbol tables would conflict. Other dependencies in Linux are wxwidgets (you can
* build wx without sdl support, though) and onepad at the time of writing this. */
#include <SDL.h>
#include <SDL_audio.h>
typedef StereoOut16 StereoOut_SDL;
namespace
{
/* Since spu2 only ever outputs stereo, we don't worry about emitting surround sound
* even though SDL2 supports it */
const Uint8 channels = 2;
/* SDL2 supports s32 audio */
/* Samples should vary from [512,8192] according to SDL spec. Take note this is the desired
* sample count and SDL may provide otherwise. Pulseaudio will cut this value in half if
* PA_STREAM_ADJUST_LATENCY is set in the backened, for example. */
const Uint16 desiredSamples = 2048;
const Uint16 format = AUDIO_S16SYS;
Uint16 samples = desiredSamples;
std::unique_ptr<StereoOut_SDL[]> buffer;
void callback_fillBuffer(void *userdata, Uint8 *stream, int len)
{
Uint16 sdl_samples = samples;
#if SDL_MAJOR_VERSION >= 2
memset(stream, 0, len);
// As of SDL 2.0.4 the buffer is too small to contains all samples
// len is 2048, samples is 1024 and sizeof(StereoOut_SDL) is 4
sdl_samples = len / sizeof(StereoOut_SDL);
#endif
// Length should always be samples in bytes.
assert(len / sizeof(StereoOut_SDL) == sdl_samples);
for (Uint16 i = 0; i < sdl_samples; i += SndOutPacketSize)
SndBuffer::ReadSamples(&buffer[i]);
SDL_MixAudio(stream, (Uint8 *)buffer.get(), len, SDL_MIX_MAXVOLUME);
}
}
struct SDLAudioMod : public SndOutModule
{
static SDLAudioMod mod;
std::string m_api;
s32 Init()
{
ReadSettings();
#if SDL_MAJOR_VERSION >= 2
std::cerr << "Request SDL audio driver: " << m_api.c_str() << std::endl;
#endif
/* SDL backends will mangle the AudioSpec and change the sample count. If we reopen
* the audio backend, we need to make sure we keep our desired samples in the spec */
spec.samples = desiredSamples;
// Mandatory otherwise, init will be redone in SDL_OpenAudio
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
std::cerr << "SPU2-X: SDL INIT audio error: " << SDL_GetError() << std::endl;
return -1;
}
#if SDL_MAJOR_VERSION >= 2
if (m_api.compare("pulseaudio")) {
// Close the audio, but keep the subsystem open
SDL_AudioQuit();
// Reopen the audio
if (SDL_AudioInit(m_api.c_str()) < 0) {
std::cerr << "SPU2-X: SDL audio init error: " << SDL_GetError() << std::endl;
return -1;
}
}
#endif
if (SDL_OpenAudio(&spec, NULL) < 0) {
std::cerr << "SPU2-X: SDL audio error: " << SDL_GetError() << std::endl;
return -1;
}
#if SDL_MAJOR_VERSION >= 2
std::cerr << "Opened SDL audio driver: " << SDL_GetCurrentAudioDriver() << std::endl;
#endif
/* This is so ugly. It is hilariously ugly. I didn't use a vector to save reallocs. */
if (samples != spec.samples || buffer == NULL)
buffer = std::unique_ptr<StereoOut_SDL[]>(new StereoOut_SDL[spec.samples]);
if (samples != spec.samples) {
fprintf(stderr, "SPU2-X: SDL failed to get desired samples (%d) got %d samples instead\n", samples, spec.samples);
// Samples must always be a multiple of packet size.
assert(spec.samples % SndOutPacketSize == 0);
samples = spec.samples;
}
SDL_PauseAudio(0);
return 0;
}
const wchar_t *GetIdent() const { return L"SDLAudio"; }
const wchar_t *GetLongName() const { return L"SDL Audio"; }
void Close()
{
// Related to SDL_Init(SDL_INIT_AUDIO)
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
~SDLAudioMod() { Close(); }
s32 Test() const { return 0; }
int GetEmptySampleCount() { return 0; }
void Configure(uptr parent) {}
void ReadSettings()
{
wxString api(L"EMPTYEMPTYEMPTY");
CfgReadStr(L"SDL", L"HostApi", api, L"pulseaudio");
SetApiSettings(api);
}
void WriteSettings() const
{
CfgWriteStr(L"SDL", L"HostApi", wxString(m_api.c_str(), wxConvUTF8));
};
void SetApiSettings(wxString api)
{
#if SDL_MAJOR_VERSION >= 2
// Validate the api name
bool valid = false;
std::string api_name = std::string(api.utf8_str());
for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
valid |= (api_name.compare(SDL_GetAudioDriver(i)) == 0);
}
if (valid) {
m_api = api.utf8_str();
} else {
std::cerr << "SDL audio driver configuration is invalid!" << std::endl
<< "It will be replaced by pulseaudio!" << std::endl;
m_api = "pulseaudio";
}
#endif
}
private:
SDL_AudioSpec spec;
SDLAudioMod()
: m_api("pulseaudio")
, spec({SampleRate, format, channels, 0,
desiredSamples, 0, 0, &callback_fillBuffer, nullptr})
{
// Number of samples must be a multiple of packet size.
assert(samples % SndOutPacketSize == 0);
}
};
SDLAudioMod SDLAudioMod::mod;
SndOutModule *const SDLOut = &SDLAudioMod::mod;

View File

@ -1,321 +0,0 @@
//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

View File

@ -1,31 +0,0 @@
//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;

View File

@ -1,540 +0,0 @@
/* 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 "soundtouch/SoundTouch.h"
#include <wx/datetime.h>
#include <algorithm>
//Uncomment the next line to use the old time stretcher
//#define SPU2X_USE_OLD_STRETCHER
static soundtouch::SoundTouch *pSoundTouch = NULL;
// data prediction amount, used to "commit" data that hasn't
// finished timestretch processing.
s32 SndBuffer::m_predictData;
// records last buffer status (fill %, range -100 to 100, with 0 being 50% full)
float SndBuffer::lastPct;
float SndBuffer::lastEmergencyAdj;
float SndBuffer::cTempo = 1;
float SndBuffer::eTempo = 1;
void SndBuffer::PredictDataWrite(int samples)
{
m_predictData += samples;
}
// Calculate the buffer status percentage.
// Returns range from -1.0 to 1.0
// 1.0 = buffer overflow!
// 0.0 = buffer nominal (50% full)
// -1.0 = buffer underflow!
float SndBuffer::GetStatusPct()
{
// Get the buffer status of the output driver too, so that we can
// obtain a more accurate overall buffer status.
int drvempty = mods[OutputModule]->GetEmptySampleCount(); // / 2;
//ConLog( "Data %d >>> driver: %d predict: %d\n", m_data, drvempty, m_predictData );
int data = _GetApproximateDataInBuffer();
float result = (float)(data + m_predictData - drvempty) - (m_size / 16);
result /= (m_size / 16);
return result;
}
//Alternative simple tempo adjustment. Based only on the soundtouch buffer state.
//Base algorithm: aim at specific average number of samples at the buffer (by GUI), and adjust tempo simply by current/target.
//An extra mechanism is added to keep adjustment at perfect 1:1 ratio (when emulation speed is stable around 100%)
// to prevent constant stretching/shrinking of packets if possible.
// This mechanism is triggered when the adjustment is close to 1:1 for long enough (defaults to 100 iterations within hys_ok_factor - defaults to 3%).
// 1:1 state is aborted when required adjustment goes beyond hys_bad_factor (defaults to 20%).
//
//To compensate for wide variation of the <num of samples> ratio due to relatively small size of the buffer,
// The required tempo is a running average of STRETCH_AVERAGE_LEN (defaults to 50) last calculations.
// This averaging slows down the respons time of the algorithm, but greatly stablize it towards steady stretching.
//
//Keeping the buffer at required latency:
// This algorithm stabilises when the actual latency is <speed>*<required_latency>. While this is just fine at 100% speed,
// it's problematic especially for slow speeds, as the number of actual samples at the buffer gets very small on that case,
// which may lead to underruns (or just too much latency when running very fast).
//To compensate for that, the algorithm has a slowly moving compensation factor which will eventually bring the actual latency to the required one.
//compensationDivider defines how slow this compensation changes. By default it's set to 100,
// which will finalize the compensation after about 200 iterations.
//
// Note, this algorithm is intentionally simplified by not taking extreme actions at extreme scenarios (mostly underruns when speed drops sharply),
// and let's the overrun/underrun protections do what they should (doesn't happen much though in practice, even at big FPS variations).
//
// These params were tested to show good respond and stability, on all audio systems (dsound, wav, port audio, xaudio2),
// even at extreme small latency of 50ms which can handle 50%-100% variations without audible glitches.
int targetIPS = 750;
//Dynamic tuning changes the values of the base algorithm parameters (derived from targetIPS) to adapt, in real time, to
// different number of invocations/sec (mostly affects number of iterations to average).
// Dynamic tuning can have a slight negative effect on the behavior of the algorithm, so it's preferred to have it off.
//Currently it looks like it's around 750/sec on all systems when playing at 100% speed (50/60fps),
// and proportional to that speed otherwise.
//If changes are made to SPU2X which affects this number (but it's still the same on all systems), then just change targetIPS.
//If we find out that some systems are very different, we can turn on dynamic tuning by uncommenting the next line.
//#define NEWSTRETCHER_USE_DYNAMIC_TUNING
//Additional performance note: since MAX_STRETCH_AVERAGE_LEN = 128 (or any power of 2), the '%' below
//could be replaced with a faster '&'. The compiler is highly likely to do it since all the values are unsigned.
#define AVERAGING_BUFFER_SIZE 256U
unsigned int AVERAGING_WINDOW = 50.0 * targetIPS / 750;
#define STRETCHER_RESET_THRESHOLD 5
int gRequestStretcherReset = STRETCHER_RESET_THRESHOLD;
//Adds a value to the running average buffer, and return the new running average.
float addToAvg(float val)
{
static float avg_fullness[AVERAGING_BUFFER_SIZE];
static unsigned int nextAvgPos = 0;
static unsigned int available = 0; // Make sure we're not averaging AVERAGING_WINDOW items if we inserted less.
if (gRequestStretcherReset >= STRETCHER_RESET_THRESHOLD)
available = 0;
if (available < AVERAGING_BUFFER_SIZE)
available++;
avg_fullness[nextAvgPos] = val;
nextAvgPos = (nextAvgPos + 1U) % AVERAGING_BUFFER_SIZE;
unsigned int actualWindow = std::min(available, AVERAGING_WINDOW);
unsigned int first = (nextAvgPos - actualWindow + AVERAGING_BUFFER_SIZE) % AVERAGING_BUFFER_SIZE;
// Possible optimization: if we know that actualWindow hasn't changed since
// last invocation, we could calculate the running average in O(1) instead of O(N)
// by keeping a running sum between invocations, and then
// do "runningSum = runningSum + val - avg_fullness[(first-1)%...]" instead of the following loop.
// Few gotchas: val overwrites first-1, handling actualWindow changes, etc.
// However, this isn't hot code, so unless proven otherwise, we can live with unoptimized code.
float sum = 0;
for (unsigned int i = first; i < first + actualWindow; i++) {
sum += avg_fullness[i % AVERAGING_BUFFER_SIZE];
}
sum = sum / actualWindow;
return sum ? sum : 1; // 1 because that's the 100% perfect speed value
}
template <class T>
bool IsInRange(const T &val, const T &min, const T &max)
{
return (min <= val && val <= max);
}
//actual stretch algorithm implementation
void SndBuffer::UpdateTempoChangeSoundTouch2()
{
long targetSamplesReservoir = 48 * SndOutLatencyMS; //48000*SndOutLatencyMS/1000
//base aim at buffer filled %
float baseTargetFullness = (double)targetSamplesReservoir; ///(double)m_size;//0.05;
//state vars
static bool inside_hysteresis; //=false;
static int hys_ok_count; //=0;
static float dynamicTargetFullness; //=baseTargetFullness;
if (gRequestStretcherReset >= STRETCHER_RESET_THRESHOLD) {
ConLog("______> stretch: Reset.\n");
inside_hysteresis = false;
hys_ok_count = 0;
dynamicTargetFullness = baseTargetFullness;
}
int data = _GetApproximateDataInBuffer();
float bufferFullness = (float)data; ///(float)m_size;
#ifdef NEWSTRETCHER_USE_DYNAMIC_TUNING
{ //test current iterations/sec every 0.5s, and change algo params accordingly if different than previous IPS more than 30%
static long iters = 0;
static wxDateTime last = wxDateTime::UNow();
wxDateTime unow = wxDateTime::UNow();
wxTimeSpan delta = unow.Subtract(last);
if (delta.GetMilliseconds() > 500) {
int pot_targetIPS = 1000.0 / delta.GetMilliseconds().ToDouble() * iters;
if (!IsInRange(pot_targetIPS, int((float)targetIPS / 1.3f), int((float)targetIPS * 1.3f))) {
if (MsgOverruns())
ConLog("Stretcher: setting iters/sec from %d to %d\n", targetIPS, pot_targetIPS);
targetIPS = pot_targetIPS;
AVERAGING_WINDOW = GetClamped((int)(50.0f * (float)targetIPS / 750.0f), 3, (int)AVERAGING_BUFFER_SIZE);
}
last = unow;
iters = 0;
}
iters++;
}
#endif
//Algorithm params: (threshold params (hysteresis), etc)
const float hys_ok_factor = 1.04f;
const float hys_bad_factor = 1.2f;
int hys_min_ok_count = GetClamped((int)(50.0 * (float)targetIPS / 750.0), 2, 100); //consecutive iterations within hys_ok before going to 1:1 mode
int compensationDivider = GetClamped((int)(100.0 * (float)targetIPS / 750), 15, 150);
float tempoAdjust = bufferFullness / dynamicTargetFullness;
float avgerage = addToAvg(tempoAdjust);
tempoAdjust = avgerage;
// Dampen the adjustment to avoid overshoots (this means the average will compensate to the other side).
// This is different than simply bigger averaging window since bigger window also has bigger "momentum",
// so it's slower to slow down when it gets close to the equilibrium state and can therefore resonate.
// The dampening (sqrt was chosen for no very good reason) manages to mostly prevent that.
tempoAdjust = sqrt(tempoAdjust);
tempoAdjust = GetClamped(tempoAdjust, 0.05f, 10.0f);
if (tempoAdjust < 1)
baseTargetFullness /= sqrt(tempoAdjust); // slightly increase latency when running slow.
dynamicTargetFullness += (baseTargetFullness / tempoAdjust - dynamicTargetFullness) / (double)compensationDivider;
if (IsInRange(tempoAdjust, 0.9f, 1.1f) && IsInRange(dynamicTargetFullness, baseTargetFullness * 0.9f, baseTargetFullness * 1.1f))
dynamicTargetFullness = baseTargetFullness;
if (!inside_hysteresis) {
if (IsInRange(tempoAdjust, 1.0f / hys_ok_factor, hys_ok_factor))
hys_ok_count++;
else
hys_ok_count = 0;
if (hys_ok_count >= hys_min_ok_count) {
inside_hysteresis = true;
if (MsgOverruns())
ConLog("======> stretch: None (1:1)\n");
}
} else if (!IsInRange(tempoAdjust, 1.0f / hys_bad_factor, hys_bad_factor)) {
if (MsgOverruns())
ConLog("~~~~~~> stretch: Dynamic\n");
inside_hysteresis = false;
hys_ok_count = 0;
}
if (inside_hysteresis)
tempoAdjust = 1.0;
if (MsgOverruns()) {
static int iters = 0;
static wxDateTime last = wxDateTime::UNow();
wxDateTime unow = wxDateTime::UNow();
wxTimeSpan delta = unow.Subtract(last);
if (delta.GetMilliseconds() > 1000) { //report buffers state and tempo adjust every second
ConLog("buffers: %4d ms (%3.0f%%), tempo: %f, comp: %2.3f, iters: %d, (N-IPS:%d -> avg:%d, minokc:%d, div:%d) reset:%d\n",
(int)(data / 48), (double)(100.0 * bufferFullness / baseTargetFullness), (double)tempoAdjust, (double)(dynamicTargetFullness / baseTargetFullness), iters, (int)targetIPS, AVERAGING_WINDOW, hys_min_ok_count, compensationDivider, gRequestStretcherReset);
last = unow;
iters = 0;
}
iters++;
}
pSoundTouch->setTempo(tempoAdjust);
if (gRequestStretcherReset >= STRETCHER_RESET_THRESHOLD)
gRequestStretcherReset = 0;
return;
}
void SndBuffer::UpdateTempoChangeSoundTouch()
{
float statusPct = GetStatusPct();
float pctChange = statusPct - lastPct;
float tempoChange;
float emergencyAdj = 0;
float newcee = cTempo; // workspace var. for cTempo
// IMPORTANT!
// If you plan to tweak these values, make sure you're using a release build
// OUTSIDE THE DEBUGGER to test it! The Visual Studio debugger can really cause
// erratic behavior in the audio buffers, and makes the timestretcher seem a
// lot more inconsistent than it really is.
// We have two factors.
// * Distance from nominal buffer status (50% full)
// * The change from previous update to this update.
// Prediction based on the buffer change:
// (linear seems to work better here)
tempoChange = pctChange * 0.75f;
if (statusPct * tempoChange < 0.0f) {
// only apply tempo change if it is in synch with the buffer status.
// In other words, if the buffer is high (over 0%), and is decreasing,
// ignore it. It'll just muck things up.
tempoChange = 0;
}
// Sudden spikes in framerate can cause the nominal buffer status
// to go critical, in which case we have to enact an emergency
// stretch. The following cubic formulas do that. Values near
// the extremeites give much larger results than those near 0.
// And the value is added only this time, and does not accumulate.
// (otherwise a large value like this would cause problems down the road)
// Constants:
// Weight - weights the statusPct's "emergency" consideration.
// higher values here will make the buffer perform more drastic
// compensations at the outer edges of the buffer (at -75 or +75%
// or beyond, for example).
// Range - scales the adjustment to the given range (more or less).
// The actual range is dependent on the weight used, so if you increase
// Weight you'll usually want to decrease Range somewhat to compensate.
// Prediction based on the buffer fill status:
const float statusWeight = 2.99f;
const float statusRange = 0.068f;
// "non-emergency" deadzone: In this area stretching will be strongly discouraged.
// Note: due tot he nature of timestretch latency, it's always a wee bit harder to
// cope with low fps (underruns) than it is high fps (overruns). So to help out a
// little, the low-end portions of this check are less forgiving than the high-sides.
if (cTempo < 0.965f || cTempo > 1.060f ||
pctChange < -0.38f || pctChange > 0.54f ||
statusPct < -0.42f || statusPct > 0.70f ||
eTempo < 0.89f || eTempo > 1.19f) {
//printf("Emergency stretch: cTempo = %f eTempo = %f pctChange = %f statusPct = %f\n",cTempo,eTempo,pctChange,statusPct);
emergencyAdj = (pow(statusPct * statusWeight, 3.0f) * statusRange);
}
// Smooth things out by factoring our previous adjustment into this one.
// It helps make the system 'feel' a little smarter by giving it at least
// one packet worth of history to help work off of:
emergencyAdj = (emergencyAdj * 0.75f) + (lastEmergencyAdj * 0.25f);
lastEmergencyAdj = emergencyAdj;
lastPct = statusPct;
// Accumulate a fraction of the tempo change into the tempo itself.
// This helps the system run "smarter" to games that run consistently
// fast or slow by altering the base tempo to something closer to the
// game's active speed. In tests most games normalize within 2 seconds
// at 100ms latency, which is pretty good (larger buffers normalize even
// quicker).
newcee += newcee * (tempoChange + emergencyAdj) * 0.03f;
// Apply tempoChange as a scale of cTempo. That way the effect is proportional
// to the current tempo. (otherwise tempos rate of change at the extremes would
// be too drastic)
float newTempo = newcee + (emergencyAdj * cTempo);
// ... and as a final optimization, only stretch if the new tempo is outside
// a nominal threshold. Keep this threshold check small, because it could
// cause some serious side effects otherwise. (enlarging the cTempo check above
// is usually better/safer)
if (newTempo < 0.970f || newTempo > 1.045f) {
cTempo = (float)newcee;
if (newTempo < 0.10f)
newTempo = 0.10f;
else if (newTempo > 10.0f)
newTempo = 10.0f;
if (cTempo < 0.15f)
cTempo = 0.15f;
else if (cTempo > 7.5f)
cTempo = 7.5f;
pSoundTouch->setTempo(eTempo = (float)newTempo);
/*ConLog("* SPU2-X: [Nominal %d%%] [Emergency: %d%%] (baseTempo: %d%% ) (newTempo: %d%%) (buffer: %d%%)\n",
//(relation < 0.0) ? "Normalize" : "",
(int)(tempoChange * 100.0 * 0.03),
(int)(emergencyAdj * 100.0),
(int)(cTempo * 100.0),
(int)(newTempo * 100.0),
(int)(statusPct * 100.0)
);*/
} else {
// Nominal operation -- turn off stretching.
// note: eTempo 'slides' toward 1.0 for smoother audio and better
// protection against spikes.
if (cTempo != 1.0f) {
cTempo = 1.0f;
eTempo = (1.0f + eTempo) * 0.5f;
pSoundTouch->setTempo(eTempo);
} else {
if (eTempo != cTempo)
pSoundTouch->setTempo(eTempo = cTempo);
}
}
}
extern uint TickInterval;
void SndBuffer::UpdateTempoChangeAsyncMixing()
{
float statusPct = GetStatusPct();
lastPct = statusPct;
if (statusPct < -0.1f) {
TickInterval -= 4;
if (statusPct < -0.3f)
TickInterval = 64;
if (TickInterval < 64)
TickInterval = 64;
//printf("-- %d, %f\n",TickInterval,statusPct);
} else if (statusPct > 0.2f) {
TickInterval += 1;
if (TickInterval >= 7000)
TickInterval = 7000;
//printf("++ %d, %f\n",TickInterval,statusPct);
} else
TickInterval = 768;
}
void SndBuffer::timeStretchUnderrun()
{
gRequestStretcherReset++;
// timeStretcher failed it's job. We need to slow down the audio some.
cTempo -= (cTempo * 0.12f);
eTempo -= (eTempo * 0.30f);
if (eTempo < 0.1f)
eTempo = 0.1f;
// pSoundTouch->setTempo( eTempo );
//pSoundTouch->setTempoChange(-30); // temporary (until stretcher is called) slow down
}
s32 SndBuffer::timeStretchOverrun()
{
// If we overran it means the timestretcher failed. We need to speed
// up audio playback.
cTempo += cTempo * 0.12f;
eTempo += eTempo * 0.40f;
if (eTempo > 7.5f)
eTempo = 7.5f;
//pSoundTouch->setTempo( eTempo );
//pSoundTouch->setTempoChange(30);// temporary (until stretcher is called) speed up
// Throw out just a little bit (two packets worth) to help
// give the TS some room to work:
gRequestStretcherReset++;
return SndOutPacketSize * 2;
}
static void CvtPacketToFloat(StereoOut32 *srcdest)
{
StereoOutFloat *dest = (StereoOutFloat *)srcdest;
const StereoOut32 *src = (StereoOut32 *)srcdest;
for (uint i = 0; i < SndOutPacketSize; ++i, ++dest, ++src)
*dest = (StereoOutFloat)*src;
}
// Parameter note: Size should always be a multiple of 128, thanks!
static void CvtPacketToInt(StereoOut32 *srcdest, uint size)
{
//pxAssume( (size & 127) == 0 );
const StereoOutFloat *src = (StereoOutFloat *)srcdest;
StereoOut32 *dest = srcdest;
for (uint i = 0; i < size; ++i, ++dest, ++src)
*dest = (StereoOut32)*src;
}
void SndBuffer::timeStretchWrite()
{
// data prediction helps keep the tempo adjustments more accurate.
// The timestretcher returns packets in belated "clump" form.
// Meaning that most of the time we'll get nothing back, and then
// suddenly we'll get several chunks back at once. Thus we use
// data prediction to make the timestretcher more responsive.
PredictDataWrite((int)(SndOutPacketSize / eTempo));
CvtPacketToFloat(sndTempBuffer);
pSoundTouch->putSamples((float *)sndTempBuffer, SndOutPacketSize);
int tempProgress;
while (tempProgress = pSoundTouch->receiveSamples((float *)sndTempBuffer, SndOutPacketSize),
tempProgress != 0) {
// Hint: It's assumed that pSoundTouch will return chunks of 128 bytes (it always does as
// long as the SSE optimizations are enabled), which means we can do our own SSE opts here.
CvtPacketToInt(sndTempBuffer, tempProgress);
_WriteSamples(sndTempBuffer, tempProgress);
}
#ifdef SPU2X_USE_OLD_STRETCHER
UpdateTempoChangeSoundTouch();
#else
UpdateTempoChangeSoundTouch2();
#endif
}
void SndBuffer::soundtouchInit()
{
pSoundTouch = new soundtouch::SoundTouch();
pSoundTouch->setSampleRate(SampleRate);
pSoundTouch->setChannels(2);
pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, 0);
pSoundTouch->setSetting(SETTING_USE_AA_FILTER, 0);
SoundtouchCfg::ApplySettings(*pSoundTouch);
pSoundTouch->setTempo(1);
// some timestretch management vars:
cTempo = 1.0;
eTempo = 1.0;
lastPct = 0;
lastEmergencyAdj = 0;
m_predictData = 0;
}
// reset timestretch management vars, and delay updates a bit:
void SndBuffer::soundtouchClearContents()
{
if (pSoundTouch == NULL)
return;
pSoundTouch->clear();
pSoundTouch->setTempo(1);
cTempo = 1.0;
eTempo = 1.0;
lastPct = 0;
lastEmergencyAdj = 0;
m_predictData = 0;
}
void SndBuffer::soundtouchCleanup()
{
safe_delete(pSoundTouch);
}

View File

@ -1,148 +0,0 @@
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
* Developed and maintained by the Pcsx2 Development Team.
*
* The file is based on WavFile.h from SoundTouch library.
* Original portions are (c) 2009 by Olli Parviainen (oparviai 'at' iki.fi)
*
* 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/>.
*/
// Note the file is mostly a copy paste of the WavFile.h from SoundTouch library. It was
// shrunken to support only output 16 bits wav files
#include <stdio.h>
#include <stdexcept>
#include <string>
#include <cstring>
#include <assert.h>
#include <limits.h>
#include "WavFile.h"
using namespace std;
static const char riffStr[] = "RIFF";
static const char waveStr[] = "WAVE";
static const char fmtStr[] = "fmt ";
static const char dataStr[] = "data";
//////////////////////////////////////////////////////////////////////////////
//
// Class WavOutFile
//
WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels)
{
bytesWritten = 0;
fptr = fopen(fileName, "wb");
if (fptr == NULL) {
string msg = "Error : Unable to open file \"";
msg += fileName;
msg += "\" for writing.";
//pmsg = msg.c_str;
throw runtime_error(msg);
}
fillInHeader(sampleRate, bits, channels);
writeHeader();
}
WavOutFile::~WavOutFile()
{
if (fptr) {
finishHeader();
fclose(fptr);
}
}
void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels)
{
// fill in the 'riff' part..
// copy string 'RIFF' to riff_char
memcpy(&(header.riff.riff_char), riffStr, 4);
// package_len unknown so far
header.riff.package_len = 0;
// copy string 'WAVE' to wave
memcpy(&(header.riff.wave), waveStr, 4);
// fill in the 'format' part..
// copy string 'fmt ' to fmt
memcpy(&(header.format.fmt), fmtStr, 4);
header.format.format_len = 0x10;
header.format.fixed = 1;
header.format.channel_number = (short)channels;
header.format.sample_rate = (int)sampleRate;
header.format.bits_per_sample = (short)bits;
header.format.byte_per_sample = (short)(bits * channels / 8);
header.format.byte_rate = header.format.byte_per_sample * (int)sampleRate;
header.format.sample_rate = (int)sampleRate;
// fill in the 'data' part..
// copy string 'data' to data_field
memcpy(&(header.data.data_field), dataStr, 4);
// data_len unknown so far
header.data.data_len = 0;
}
void WavOutFile::finishHeader()
{
// supplement the file length into the header structure
header.riff.package_len = bytesWritten + 36;
header.data.data_len = bytesWritten;
writeHeader();
}
void WavOutFile::writeHeader()
{
int res;
// write the supplemented header in the beginning of the file
fseek(fptr, 0, SEEK_SET);
res = fwrite(&header, sizeof(header), 1, fptr);
if (res != 1) {
throw runtime_error("Error while writing to a wav file.");
}
// jump back to the end of the file
fseek(fptr, 0, SEEK_END);
}
void WavOutFile::write(const short *buffer, int numElems)
{
int res;
// 16bit format & 16 bit samples
assert(header.format.bits_per_sample == 16);
if (numElems < 1)
return; // nothing to do
res = fwrite(buffer, 2, numElems, fptr);
if (res != numElems) {
throw runtime_error("Error while writing to a wav file.");
}
bytesWritten += 2 * numElems;
}

View File

@ -1,112 +0,0 @@
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
* Developed and maintained by the Pcsx2 Development Team.
*
* The file is based on WavFile.h from SoundTouch library.
* Original portions are (c) 2009 by Olli Parviainen (oparviai 'at' iki.fi)
*
* 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/>.
*/
// Note the file is mostly a copy paste of the WavFile.h from SoundTouch library. It was
// shrunken to support only output 16 bits wav files
#ifndef WAVFILE_H
#define WAVFILE_H
#include <stdio.h>
#ifndef uint
typedef unsigned int uint;
#endif
/// WAV audio file 'riff' section header
typedef struct
{
char riff_char[4];
int package_len;
char wave[4];
} WavRiff;
/// WAV audio file 'format' section header
typedef struct
{
char fmt[4];
int format_len;
short fixed;
short channel_number;
int sample_rate;
int byte_rate;
short byte_per_sample;
short bits_per_sample;
} WavFormat;
/// WAV audio file 'data' section header
typedef struct
{
char data_field[4];
uint data_len;
} WavData;
/// WAV audio file header
typedef struct
{
WavRiff riff;
WavFormat format;
WavData data;
} WavHeader;
/// Class for writing WAV audio files.
class WavOutFile
{
private:
/// Pointer to the WAV file
FILE *fptr;
/// WAV file header data.
WavHeader header;
/// Counter of how many bytes have been written to the file so far.
int bytesWritten;
/// Fills in WAV file header information.
void fillInHeader(const uint sampleRate, const uint bits, const uint channels);
/// Finishes the WAV file header by supplementing information of amount of
/// data written to file etc
void finishHeader();
/// Writes the WAV file header.
void writeHeader();
public:
/// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
/// if file creation fails.
WavOutFile(const char *fileName, ///< Filename
int sampleRate, ///< Sample rate (e.g. 44100 etc)
int bits, ///< Bits per sample (8 or 16 bits)
int channels ///< Number of channels (1=mono, 2=stereo)
);
/// Destructor: Finalizes & closes the WAV file.
~WavOutFile();
/// Write data to WAV file. Throws a 'runtime_error' exception if writing to
/// file fails.
void write(const short *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file.
);
};
#endif

View File

@ -1,142 +0,0 @@
/* 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"
#ifdef __POSIX__
#include "WavFile.h"
#else
#include "soundtouch/source/SoundStretch/WavFile.h"
#endif
static WavOutFile *_new_WavOutFile(const char *destfile)
{
return new WavOutFile(destfile, 48000, 16, 2);
}
namespace WaveDump
{
static WavOutFile *m_CoreWav[2][CoreSrc_Count];
static const char *m_tbl_CoreOutputTypeNames[CoreSrc_Count] =
{
"Input",
"DryVoiceMix",
"WetVoiceMix",
"PreReverb",
"PostReverb",
"External"};
void Open()
{
if (!IsDevBuild)
return;
if (!WaveLog())
return;
char wavfilename[256];
for (uint cidx = 0; cidx < 2; cidx++) {
for (int srcidx = 0; srcidx < CoreSrc_Count; srcidx++) {
safe_delete(m_CoreWav[cidx][srcidx]);
#ifdef __POSIX__
sprintf(wavfilename, "logs/spu2x-Core%ud-%s.wav",
cidx, m_tbl_CoreOutputTypeNames[srcidx]);
#else
sprintf(wavfilename, "logs\\spu2x-Core%ud-%s.wav",
cidx, m_tbl_CoreOutputTypeNames[srcidx]);
#endif
try {
m_CoreWav[cidx][srcidx] = _new_WavOutFile(wavfilename);
} catch (std::runtime_error &ex) {
printf("SPU2-X > %s.\n\tWave Log for this core source disabled.", ex.what());
m_CoreWav[cidx][srcidx] = NULL;
}
}
}
}
void Close()
{
if (!IsDevBuild)
return;
for (uint cidx = 0; cidx < 2; cidx++) {
for (int srcidx = 0; srcidx < CoreSrc_Count; srcidx++) {
safe_delete(m_CoreWav[cidx][srcidx]);
}
}
}
void WriteCore(uint coreidx, CoreSourceType src, const StereoOut16 &sample)
{
if (!IsDevBuild)
return;
if (m_CoreWav[coreidx][src] != NULL)
m_CoreWav[coreidx][src]->write((s16 *)&sample, 2);
}
void WriteCore(uint coreidx, CoreSourceType src, s16 left, s16 right)
{
WriteCore(coreidx, src, StereoOut16(left, right));
}
}
#include "Utilities/Threading.h"
using namespace Threading;
bool WavRecordEnabled = false;
static WavOutFile *m_wavrecord = NULL;
static Mutex WavRecordMutex;
void RecordStart(std::wstring* filename)
{
WavRecordEnabled = false;
try {
ScopedLock lock(WavRecordMutex);
safe_delete(m_wavrecord);
#ifdef _WIN32
if (filename)
m_wavrecord = new WavOutFile((*filename) + "wav", 48000, 16, 2);
else
m_wavrecord = new WavOutFile("audio_recording.wav", 48000, 16, 2);
#elif defined(__unix__)
m_wavrecord = new WavOutFile("audio_recording.wav", 48000, 16, 2);
#endif
WavRecordEnabled = true;
} catch (std::runtime_error &) {
m_wavrecord = NULL; // not needed, but what the heck. :)
SysMessage("SPU2-X couldn't open file for recording: %s.\nRecording to wavfile disabled.", "audio_recording.wav");
}
}
void RecordStop()
{
WavRecordEnabled = false;
ScopedLock lock(WavRecordMutex);
safe_delete(m_wavrecord);
}
void RecordWrite(const StereoOut16 &sample)
{
ScopedLock lock(WavRecordMutex);
if (m_wavrecord == NULL)
return;
m_wavrecord->write((s16 *)&sample, 2);
}

View File

@ -1,197 +0,0 @@
/* 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 "Dialogs.h"
#include "Utilities/StringHelpers.h"
extern uptr gsWindowHandle;
void SysMessage(const char *fmt, ...)
{
va_list list;
char tmp[512];
wchar_t wtmp[512];
va_start(list, fmt);
vsprintf_s(tmp, fmt, list);
va_end(list);
swprintf_s(wtmp, L"%S", tmp);
MessageBox((!!gsWindowHandle) ? (HWND)gsWindowHandle : GetActiveWindow(), wtmp,
L"SPU2-X System Message", MB_OK | MB_SETFOREGROUND);
}
void SysMessage(const wchar_t *fmt, ...)
{
va_list list;
va_start(list, fmt);
wxString wtmp;
wtmp.PrintfV(fmt, list);
va_end(list);
MessageBox((!!gsWindowHandle) ? (HWND)gsWindowHandle : GetActiveWindow(), wtmp,
L"SPU2-X System Message", MB_OK | MB_SETFOREGROUND);
}
//////
#include "Utilities/Path.h"
static wxString CfgFile(L"inis/SPU2-X.ini");
void CfgSetSettingsDir(const char *dir)
{
CfgFile = Path::Combine((dir == NULL) ? wxString(L"inis") : wxString::FromUTF8(dir), L"SPU2-X.ini");
}
/*| Config File Format: |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*\
+--+---------------------+------------------------+
| |
| Option=Value |
| |
| |
| Boolean Values: TRUE,YES,1,T,Y mean 'true', |
| everything else means 'false'. |
| |
| All Values are limited to 255 chars. |
| |
+-------------------------------------------------+
\*_____________________________________________*/
void CfgWriteBool(const TCHAR *Section, const TCHAR *Name, bool Value)
{
const TCHAR *Data = Value ? L"TRUE" : L"FALSE";
WritePrivateProfileString(Section, Name, Data, CfgFile);
}
void CfgWriteInt(const TCHAR *Section, const TCHAR *Name, int Value)
{
TCHAR Data[32];
_itow(Value, Data, 10);
WritePrivateProfileString(Section, Name, Data, CfgFile);
}
void CfgWriteFloat(const TCHAR *Section, const TCHAR *Name, float Value)
{
TCHAR Data[32];
_swprintf(Data, L"%f", Value);
WritePrivateProfileString(Section, Name, Data, CfgFile);
}
/*void CfgWriteStr(const TCHAR* Section, const TCHAR* Name, const TCHAR *Data)
{
WritePrivateProfileString( Section, Name, Data, CfgFile );
}*/
void CfgWriteStr(const TCHAR *Section, const TCHAR *Name, const wxString &Data)
{
WritePrivateProfileString(Section, Name, Data, CfgFile);
}
/*****************************************************************************/
bool CfgReadBool(const TCHAR *Section, const TCHAR *Name, bool Default)
{
TCHAR Data[255] = {0};
GetPrivateProfileString(Section, Name, L"", Data, 255, CfgFile);
Data[254] = 0;
if (wcslen(Data) == 0) {
CfgWriteBool(Section, Name, Default);
return Default;
}
if (wcscmp(Data, L"1") == 0)
return true;
if (wcscmp(Data, L"Y") == 0)
return true;
if (wcscmp(Data, L"T") == 0)
return true;
if (wcscmp(Data, L"YES") == 0)
return true;
if (wcscmp(Data, L"TRUE") == 0)
return true;
return false;
}
int CfgReadInt(const TCHAR *Section, const TCHAR *Name, int Default)
{
TCHAR Data[255] = {0};
GetPrivateProfileString(Section, Name, L"", Data, 255, CfgFile);
Data[254] = 0;
if (wcslen(Data) == 0) {
CfgWriteInt(Section, Name, Default);
return Default;
}
return _wtoi(Data);
}
float CfgReadFloat(const TCHAR *Section, const TCHAR *Name, float Default)
{
TCHAR Data[255] = {0};
GetPrivateProfileString(Section, Name, L"", Data, 255, CfgFile);
Data[254] = 0;
if (wcslen(Data) == 0) {
CfgWriteFloat(Section, Name, Default);
return Default;
}
return (float)_wtof(Data);
}
void CfgReadStr(const TCHAR *Section, const TCHAR *Name, TCHAR *Data, int DataSize, const TCHAR *Default)
{
GetPrivateProfileString(Section, Name, L"", Data, DataSize, CfgFile);
if (wcslen(Data) == 0) {
swprintf_s(Data, DataSize, L"%s", Default);
CfgWriteStr(Section, Name, Data);
}
}
void CfgReadStr(const TCHAR *Section, const TCHAR *Name, wxString &Data, const TCHAR *Default)
{
wchar_t workspace[512];
GetPrivateProfileString(Section, Name, L"", workspace, ArraySize(workspace), CfgFile);
Data = workspace;
if (Data.empty()) {
Data = Default;
CfgWriteStr(Section, Name, Default);
}
}
// Tries to read the requested value.
// Returns FALSE if the value isn't found.
bool CfgFindName(const TCHAR *Section, const TCHAR *Name)
{
// Only load 24 characters. No need to load more.
TCHAR Data[24] = {0};
GetPrivateProfileString(Section, Name, L"", Data, 24, CfgFile);
Data[23] = 0;
if (wcslen(Data) == 0)
return false;
return true;
}

View File

@ -1,428 +0,0 @@
/* 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 "Dialogs.h"
#include <math.h>
#ifdef PCSX2_DEVBUILD
static const int LATENCY_MAX = 3000;
#else
static const int LATENCY_MAX = 750;
#endif
static const int LATENCY_MIN = 3;
static const int LATENCY_MIN_TS = 15;
// MIXING
int Interpolation = 4;
/* values:
0: no interpolation (use nearest)
1. linear interpolation
2. cubic interpolation
3. hermite interpolation
4. catmull-rom interpolation
*/
bool EffectsDisabled = false;
float FinalVolume; // Global
bool AdvancedVolumeControl;
float VolumeAdjustFLdb; // decibels settings, cos audiophiles love that
float VolumeAdjustCdb;
float VolumeAdjustFRdb;
float VolumeAdjustBLdb;
float VolumeAdjustBRdb;
float VolumeAdjustSLdb;
float VolumeAdjustSRdb;
float VolumeAdjustLFEdb;
float VolumeAdjustFL; // linear coefs calcualted from decibels,
float VolumeAdjustC;
float VolumeAdjustFR;
float VolumeAdjustBL;
float VolumeAdjustBR;
float VolumeAdjustSL;
float VolumeAdjustSR;
float VolumeAdjustLFE;
unsigned int delayCycles;
bool postprocess_filter_enabled = 1;
bool postprocess_filter_dealias = false;
// OUTPUT
int SndOutLatencyMS = 100;
int SynchMode = 0; // Time Stretch, Async or Disabled
u32 OutputModule = 0;
CONFIG_WAVEOUT Config_WaveOut;
CONFIG_XAUDIO2 Config_XAudio2;
// DSP
bool dspPluginEnabled = false;
int dspPluginModule = 0;
wchar_t dspPlugin[256];
int numSpeakers = 0;
int dplLevel = 0;
/*****************************************************************************/
void ReadSettings()
{
Interpolation = CfgReadInt(L"MIXING", L"Interpolation", 4);
EffectsDisabled = CfgReadBool(L"MIXING", L"Disable_Effects", false);
postprocess_filter_dealias = CfgReadBool(L"MIXING", L"DealiasFilter", false);
FinalVolume = ((float)CfgReadInt(L"MIXING", L"FinalVolume", 100)) / 100;
if (FinalVolume > 1.0f)
FinalVolume = 1.0f;
AdvancedVolumeControl = CfgReadBool(L"MIXING", L"AdvancedVolumeControl", false);
VolumeAdjustCdb = CfgReadFloat(L"MIXING", L"VolumeAdjustC(dB)", 0);
VolumeAdjustFLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustFL(dB)", 0);
VolumeAdjustFRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustFR(dB)", 0);
VolumeAdjustBLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustBL(dB)", 0);
VolumeAdjustBRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustBR(dB)", 0);
VolumeAdjustSLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustSL(dB)", 0);
VolumeAdjustSRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustSR(dB)", 0);
VolumeAdjustLFEdb = CfgReadFloat(L"MIXING", L"VolumeAdjustLFE(dB)", 0);
delayCycles = CfgReadInt(L"DEBUG", L"DelayCycles", 4);
VolumeAdjustC = powf(10, VolumeAdjustCdb / 10);
VolumeAdjustFL = powf(10, VolumeAdjustFLdb / 10);
VolumeAdjustFR = powf(10, VolumeAdjustFRdb / 10);
VolumeAdjustBL = powf(10, VolumeAdjustBLdb / 10);
VolumeAdjustBR = powf(10, VolumeAdjustBRdb / 10);
VolumeAdjustSL = powf(10, VolumeAdjustSLdb / 10);
VolumeAdjustSR = powf(10, VolumeAdjustSRdb / 10);
VolumeAdjustLFE = powf(10, VolumeAdjustLFEdb / 10);
SynchMode = CfgReadInt(L"OUTPUT", L"Synch_Mode", 0);
numSpeakers = CfgReadInt(L"OUTPUT", L"SpeakerConfiguration", 0);
dplLevel = CfgReadInt(L"OUTPUT", L"DplDecodingLevel", 0);
SndOutLatencyMS = CfgReadInt(L"OUTPUT", L"Latency", 100);
if ((SynchMode == 0) && (SndOutLatencyMS < LATENCY_MIN_TS)) // can't use low-latency with timestretcher atm
SndOutLatencyMS = LATENCY_MIN_TS;
else if (SndOutLatencyMS < LATENCY_MIN)
SndOutLatencyMS = LATENCY_MIN;
wchar_t omodid[128];
// portaudio occasionally has issues selecting the proper default audio device.
// let's use xaudio2 until this is sorted (rama)
// CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, PortaudioOut->GetIdent());
CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2Out->GetIdent());
// find the driver index of this module:
OutputModule = FindOutputModuleById(omodid);
CfgReadStr(L"DSP PLUGIN", L"Filename", dspPlugin, 255, L"");
dspPluginModule = CfgReadInt(L"DSP PLUGIN", L"ModuleNum", 0);
dspPluginEnabled = CfgReadBool(L"DSP PLUGIN", L"Enabled", false);
// Read DSOUNDOUT and WAVEOUT configs:
CfgReadStr(L"WAVEOUT", L"Device", Config_WaveOut.Device, L"default");
Config_WaveOut.NumBuffers = CfgReadInt(L"WAVEOUT", L"Buffer_Count", 4);
DSoundOut->ReadSettings();
PortaudioOut->ReadSettings();
SoundtouchCfg::ReadSettings();
DebugConfig::ReadSettings();
// Sanity Checks
// -------------
Clampify(SndOutLatencyMS, LATENCY_MIN, LATENCY_MAX);
if (mods[OutputModule] == NULL) {
// Unsupported or legacy module.
fwprintf(stderr, L"* SPU2-X: Unknown output module '%s' specified in configuration file.\n", omodid);
fprintf(stderr, "* SPU2-X: Defaulting to DirectSound (%S).\n", DSoundOut->GetIdent());
OutputModule = FindOutputModuleById(DSoundOut->GetIdent());
}
}
/*****************************************************************************/
void WriteSettings()
{
CfgWriteInt(L"MIXING", L"Interpolation", Interpolation);
CfgWriteBool(L"MIXING", L"Disable_Effects", EffectsDisabled);
CfgWriteBool(L"MIXING", L"DealiasFilter", postprocess_filter_dealias);
CfgWriteInt(L"MIXING", L"FinalVolume", (int)(FinalVolume * 100 + 0.5f));
CfgWriteBool(L"MIXING", L"AdvancedVolumeControl", AdvancedVolumeControl);
CfgWriteFloat(L"MIXING", L"VolumeAdjustC(dB)", VolumeAdjustCdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustFL(dB)", VolumeAdjustFLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustFR(dB)", VolumeAdjustFRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustBL(dB)", VolumeAdjustBLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustBR(dB)", VolumeAdjustBRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustSL(dB)", VolumeAdjustSLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustSR(dB)", VolumeAdjustSRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustLFE(dB)", VolumeAdjustLFEdb);
CfgWriteStr(L"OUTPUT", L"Output_Module", mods[OutputModule]->GetIdent());
CfgWriteInt(L"OUTPUT", L"Latency", SndOutLatencyMS);
CfgWriteInt(L"OUTPUT", L"Synch_Mode", SynchMode);
CfgWriteInt(L"OUTPUT", L"SpeakerConfiguration", numSpeakers);
CfgWriteInt(L"OUTPUT", L"DplDecodingLevel", dplLevel);
CfgWriteInt(L"DEBUG", L"DelayCycles", delayCycles);
if (Config_WaveOut.Device.empty())
Config_WaveOut.Device = L"default";
CfgWriteStr(L"WAVEOUT", L"Device", Config_WaveOut.Device);
CfgWriteInt(L"WAVEOUT", L"Buffer_Count", Config_WaveOut.NumBuffers);
CfgWriteStr(L"DSP PLUGIN", L"Filename", dspPlugin);
CfgWriteInt(L"DSP PLUGIN", L"ModuleNum", dspPluginModule);
CfgWriteBool(L"DSP PLUGIN", L"Enabled", dspPluginEnabled);
PortaudioOut->WriteSettings();
DSoundOut->WriteSettings();
SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings();
}
void CheckOutputModule(HWND window)
{
OutputModule = SendMessage(GetDlgItem(window, IDC_OUTPUT), CB_GETCURSEL, 0, 0);
const bool IsConfigurable =
mods[OutputModule] == PortaudioOut ||
mods[OutputModule] == WaveOut ||
mods[OutputModule] == DSoundOut;
const bool AudioExpansion =
mods[OutputModule] == XAudio2Out ||
mods[OutputModule] == PortaudioOut;
EnableWindow(GetDlgItem(window, IDC_OUTCONF), IsConfigurable);
EnableWindow(GetDlgItem(window, IDC_SPEAKERS), AudioExpansion);
EnableWindow(GetDlgItem(window, IDC_SPEAKERS_TEXT), AudioExpansion);
}
BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
wchar_t temp[384] = {0};
switch (uMsg) {
case WM_PAINT:
return FALSE;
case WM_INITDIALOG: {
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_RESETCONTENT, 0, 0);
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_ADDSTRING, 0, (LPARAM)L"0 - Nearest (Fastest/bad quality)");
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_ADDSTRING, 0, (LPARAM)L"1 - Linear (Simple/okay sound)");
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_ADDSTRING, 0, (LPARAM)L"2 - Cubic (Artificial highs)");
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_ADDSTRING, 0, (LPARAM)L"3 - Hermite (Better highs)");
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_ADDSTRING, 0, (LPARAM)L"4 - Catmull-Rom (PS2-like/slow)");
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_SETCURSEL, Interpolation, 0);
SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_RESETCONTENT, 0, 0);
SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_ADDSTRING, 0, (LPARAM)L"TimeStretch (Recommended)");
SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_ADDSTRING, 0, (LPARAM)L"Async Mix (Breaks some games!)");
SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_ADDSTRING, 0, (LPARAM)L"None (Audio can skip.)");
SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_SETCURSEL, SynchMode, 0);
SendDialogMsg(hWnd, IDC_SPEAKERS, CB_RESETCONTENT, 0, 0);
SendDialogMsg(hWnd, IDC_SPEAKERS, CB_ADDSTRING, 0, (LPARAM)L"Stereo (None, Default)");
SendDialogMsg(hWnd, IDC_SPEAKERS, CB_ADDSTRING, 0, (LPARAM)L"Quadrafonic");
SendDialogMsg(hWnd, IDC_SPEAKERS, CB_ADDSTRING, 0, (LPARAM)L"Surround 5.1");
SendDialogMsg(hWnd, IDC_SPEAKERS, CB_ADDSTRING, 0, (LPARAM)L"Surround 7.1");
SendDialogMsg(hWnd, IDC_SPEAKERS, CB_SETCURSEL, numSpeakers, 0);
SendDialogMsg(hWnd, IDC_OUTPUT, CB_RESETCONTENT, 0, 0);
int modidx = 0;
while (mods[modidx] != NULL) {
swprintf_s(temp, 72, L"%d - %s", modidx, mods[modidx]->GetLongName());
SendDialogMsg(hWnd, IDC_OUTPUT, CB_ADDSTRING, 0, (LPARAM)temp);
++modidx;
}
SendDialogMsg(hWnd, IDC_OUTPUT, CB_SETCURSEL, OutputModule, 0);
double minlat = (SynchMode == 0) ? LATENCY_MIN_TS : LATENCY_MIN;
int minexp = (int)(pow(minlat + 1, 1.0 / 3.0) * 128.0);
int maxexp = (int)(pow((double)LATENCY_MAX + 2, 1.0 / 3.0) * 128.0);
INIT_SLIDER(IDC_LATENCY_SLIDER, minexp, maxexp, 200, 42, 1);
SendDialogMsg(hWnd, IDC_LATENCY_SLIDER, TBM_SETPOS, TRUE, (int)((pow((double)SndOutLatencyMS, 1.0 / 3.0) * 128.0) + 1));
swprintf_s(temp, L"%d ms (avg)", SndOutLatencyMS);
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
int configvol = (int)(FinalVolume * 100 + 0.5f);
INIT_SLIDER(IDC_VOLUME_SLIDER, 0, 100, 10, 42, 1);
SendDialogMsg(hWnd, IDC_VOLUME_SLIDER, TBM_SETPOS, TRUE, configvol);
swprintf_s(temp, L"%d%%", configvol);
SetWindowText(GetDlgItem(hWnd, IDC_VOLUME_LABEL), temp);
CheckOutputModule(hWnd);
EnableWindow(GetDlgItem(hWnd, IDC_OPEN_CONFIG_SOUNDTOUCH), (SynchMode == 0));
EnableWindow(GetDlgItem(hWnd, IDC_OPEN_CONFIG_DEBUG), DebugEnabled);
SET_CHECK(IDC_EFFECTS_DISABLE, EffectsDisabled);
SET_CHECK(IDC_DEALIASFILTER, postprocess_filter_dealias);
SET_CHECK(IDC_DEBUG_ENABLE, DebugEnabled);
SET_CHECK(IDC_DSP_ENABLE, dspPluginEnabled);
} break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId) {
case IDOK: {
double res = ((int)SendDialogMsg(hWnd, IDC_LATENCY_SLIDER, TBM_GETPOS, 0, 0)) / 128.0;
SndOutLatencyMS = (int)pow(res, 3.0);
Clampify(SndOutLatencyMS, LATENCY_MIN, LATENCY_MAX);
FinalVolume = (float)(SendDialogMsg(hWnd, IDC_VOLUME_SLIDER, TBM_GETPOS, 0, 0)) / 100;
Interpolation = (int)SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_GETCURSEL, 0, 0);
OutputModule = (int)SendDialogMsg(hWnd, IDC_OUTPUT, CB_GETCURSEL, 0, 0);
SynchMode = (int)SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_GETCURSEL, 0, 0);
numSpeakers = (int)SendDialogMsg(hWnd, IDC_SPEAKERS, CB_GETCURSEL, 0, 0);
WriteSettings();
EndDialog(hWnd, 0);
} break;
case IDCANCEL:
EndDialog(hWnd, 0);
break;
case IDC_OUTPUT:
if (wmEvent == CBN_SELCHANGE) {
CheckOutputModule(hWnd);
}
break;
case IDC_OUTCONF: {
const int module = (int)SendMessage(GetDlgItem(hWnd, IDC_OUTPUT), CB_GETCURSEL, 0, 0);
if (mods[module] == NULL)
break;
mods[module]->Configure((uptr)hWnd);
} break;
case IDC_OPEN_CONFIG_DEBUG: {
// Quick Hack -- DebugEnabled is re-loaded with the DebugConfig's API,
// so we need to override it here:
bool dbgtmp = DebugEnabled;
DebugConfig::OpenDialog();
DebugEnabled = dbgtmp;
} break;
case IDC_SYNCHMODE: {
if (wmEvent == CBN_SELCHANGE) {
int sMode = (int)SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_GETCURSEL, 0, 0);
double minlat = (sMode == 0) ? LATENCY_MIN_TS : LATENCY_MIN;
int minexp = (int)(pow(minlat + 1, 1.0 / 3.0) * 128.0);
int maxexp = (int)(pow((double)LATENCY_MAX + 2, 1.0 / 3.0) * 128.0);
INIT_SLIDER(IDC_LATENCY_SLIDER, minexp, maxexp, 200, 42, 1);
int curpos = (int)SendMessage(GetDlgItem(hWnd, IDC_LATENCY_SLIDER), TBM_GETPOS, 0, 0);
double res = pow(curpos / 128.0, 3.0);
curpos = (int)res;
swprintf_s(temp, L"%d ms (avg)", curpos);
SetDlgItemText(hWnd, IDC_LATENCY_LABEL, temp);
bool soundtouch = sMode == 0;
EnableWindow(GetDlgItem(hWnd, IDC_OPEN_CONFIG_SOUNDTOUCH), soundtouch);
}
} break;
case IDC_OPEN_CONFIG_SOUNDTOUCH:
SoundtouchCfg::OpenDialog(hWnd);
break;
HANDLE_CHECK(IDC_EFFECTS_DISABLE, EffectsDisabled);
HANDLE_CHECK(IDC_DEALIASFILTER, postprocess_filter_dealias);
HANDLE_CHECK(IDC_DSP_ENABLE, dspPluginEnabled);
HANDLE_CHECKNB(IDC_DEBUG_ENABLE, DebugEnabled);
DebugConfig::EnableControls(hWnd);
EnableWindow(GetDlgItem(hWnd, IDC_OPEN_CONFIG_DEBUG), DebugEnabled);
break;
default:
return FALSE;
}
break;
case WM_HSCROLL: {
wmEvent = LOWORD(wParam);
HWND hwndDlg = (HWND)lParam;
int curpos = HIWORD(wParam);
switch (wmEvent) {
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_TOP:
case TB_BOTTOM:
curpos = (int)SendMessage(hwndDlg, TBM_GETPOS, 0, 0);
case TB_THUMBPOSITION:
case TB_THUMBTRACK:
Clampify(curpos,
(int)SendMessage(hwndDlg, TBM_GETRANGEMIN, 0, 0),
(int)SendMessage(hwndDlg, TBM_GETRANGEMAX, 0, 0));
SendMessage((HWND)lParam, TBM_SETPOS, TRUE, curpos);
if (hwndDlg == GetDlgItem(hWnd, IDC_LATENCY_SLIDER)) {
double res = pow(curpos / 128.0, 3.0);
curpos = (int)res;
swprintf_s(temp, L"%d ms (avg)", curpos);
SetDlgItemText(hWnd, IDC_LATENCY_LABEL, temp);
}
if (hwndDlg == GetDlgItem(hWnd, IDC_VOLUME_SLIDER)) {
swprintf_s(temp, L"%d%%", curpos);
SetDlgItemText(hWnd, IDC_VOLUME_LABEL, temp);
}
break;
default:
return FALSE;
}
} break;
default:
return FALSE;
}
return TRUE;
}
void configure()
{
INT_PTR ret;
ReadSettings();
ret = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_CONFIG), GetActiveWindow(), (DLGPROC)ConfigProc, 1);
if (ret == -1) {
MessageBox(GetActiveWindow(), L"Error Opening the config dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
ReadSettings();
}

View File

@ -1,269 +0,0 @@
/* 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 "Dialogs.h"
#include "Utilities\Path.h"
bool DebugEnabled = false;
bool _MsgToConsole = false;
bool _MsgKeyOnOff = false;
bool _MsgVoiceOff = false;
bool _MsgDMA = false;
bool _MsgAutoDMA = false;
bool _MsgOverruns = false;
bool _MsgCache = false;
bool _AccessLog = false;
bool _DMALog = false;
bool _WaveLog = false;
bool _CoresDump = false;
bool _MemDump = false;
bool _RegDump = false;
bool _visual_debug_enabled = false;
// this is set true if PCSX2 invokes the SetLogDir callback, which tells SPU2-X to use that over
// the configured crap in the ini file.
static bool LogLocationSetByPcsx2 = false;
static wxString CfgLogsFolder;
static wxString CfgDumpsFolder;
static wxDirName LogsFolder;
static wxDirName DumpsFolder;
wxString AccessLogFileName;
wxString DMA4LogFileName;
wxString DMA7LogFileName;
wxString CoresDumpFileName;
wxString MemDumpFileName;
wxString RegDumpFileName;
void CfgSetLogDir(const char *dir)
{
LogsFolder = (dir == NULL) ? wxString(L"logs") : wxString(dir, wxConvFile);
DumpsFolder = (dir == NULL) ? wxString(L"logs") : wxString(dir, wxConvFile);
LogLocationSetByPcsx2 = (dir != NULL);
}
FILE *OpenBinaryLog(const wxString &logfile)
{
return wxFopen(Path::Combine(LogsFolder, logfile), L"wb");
}
FILE *OpenLog(const wxString &logfile)
{
return wxFopen(Path::Combine(LogsFolder, logfile), L"w");
}
FILE *OpenDump(const wxString &logfile)
{
return wxFopen(Path::Combine(DumpsFolder, logfile), L"w");
}
namespace DebugConfig
{
static const wxChar *Section = L"DEBUG";
void ReadSettings()
{
DebugEnabled = CfgReadBool(Section, L"Global_Enable", 0);
_MsgToConsole = CfgReadBool(Section, L"Show_Messages", 0);
_MsgKeyOnOff = CfgReadBool(Section, L"Show_Messages_Key_On_Off", 0);
_MsgVoiceOff = CfgReadBool(Section, L"Show_Messages_Voice_Off", 0);
_MsgDMA = CfgReadBool(Section, L"Show_Messages_DMA_Transfer", 0);
_MsgAutoDMA = CfgReadBool(Section, L"Show_Messages_AutoDMA", 0);
_MsgOverruns = CfgReadBool(Section, L"Show_Messages_Overruns", 0);
_MsgCache = CfgReadBool(Section, L"Show_Messages_CacheStats", 0);
_AccessLog = CfgReadBool(Section, L"Log_Register_Access", 0);
_DMALog = CfgReadBool(Section, L"Log_DMA_Transfers", 0);
_WaveLog = CfgReadBool(Section, L"Log_WAVE_Output", 0);
_CoresDump = CfgReadBool(Section, L"Dump_Info", 0);
_MemDump = CfgReadBool(Section, L"Dump_Memory", 0);
_RegDump = CfgReadBool(Section, L"Dump_Regs", 0);
_visual_debug_enabled = CfgReadBool(Section, L"Visual_Debug_Enabled", 0);
CfgReadStr(Section, L"Logs_Folder", CfgLogsFolder, L"logs");
CfgReadStr(Section, L"Dumps_Folder", CfgDumpsFolder, L"logs");
CfgReadStr(Section, L"Access_Log_Filename", AccessLogFileName, L"SPU2Log.txt");
CfgReadStr(Section, L"DMA4Log_Filename", DMA4LogFileName, L"SPU2dma4.dat");
CfgReadStr(Section, L"DMA7Log_Filename", DMA7LogFileName, L"SPU2dma7.dat");
CfgReadStr(Section, L"Info_Dump_Filename", CoresDumpFileName, L"SPU2Cores.txt");
CfgReadStr(Section, L"Mem_Dump_Filename", MemDumpFileName, L"SPU2mem.dat");
CfgReadStr(Section, L"Reg_Dump_Filename", RegDumpFileName, L"SPU2regs.dat");
if (!LogLocationSetByPcsx2) {
LogsFolder = CfgLogsFolder;
DumpsFolder = CfgLogsFolder;
}
}
void WriteSettings()
{
CfgWriteBool(Section, L"Global_Enable", DebugEnabled);
CfgWriteBool(Section, L"Show_Messages", _MsgToConsole);
CfgWriteBool(Section, L"Show_Messages_Key_On_Off", _MsgKeyOnOff);
CfgWriteBool(Section, L"Show_Messages_Voice_Off", _MsgVoiceOff);
CfgWriteBool(Section, L"Show_Messages_DMA_Transfer", _MsgDMA);
CfgWriteBool(Section, L"Show_Messages_AutoDMA", _MsgAutoDMA);
CfgWriteBool(Section, L"Show_Messages_Overruns", _MsgOverruns);
CfgWriteBool(Section, L"Show_Messages_CacheStats", _MsgCache);
CfgWriteBool(Section, L"Log_Register_Access", _AccessLog);
CfgWriteBool(Section, L"Log_DMA_Transfers", _DMALog);
CfgWriteBool(Section, L"Log_WAVE_Output", _WaveLog);
CfgWriteBool(Section, L"Dump_Info", _CoresDump);
CfgWriteBool(Section, L"Dump_Memory", _MemDump);
CfgWriteBool(Section, L"Dump_Regs", _RegDump);
CfgWriteBool(Section, L"Visual_Debug_Enabled", _visual_debug_enabled);
// None of the logs strings are changable via GUI, so no point in bothering to
// write them back out.
CfgWriteStr(Section, L"Logs_Folder", CfgLogsFolder);
CfgWriteStr(Section, L"Dumps_Folder", CfgDumpsFolder);
CfgWriteStr(Section, L"Access_Log_Filename", AccessLogFileName);
CfgWriteStr(Section, L"DMA4Log_Filename", DMA4LogFileName);
CfgWriteStr(Section, L"DMA7Log_Filename", DMA7LogFileName);
CfgWriteStr(Section, L"Info_Dump_Filename", CoresDumpFileName);
CfgWriteStr(Section, L"Mem_Dump_Filename", MemDumpFileName);
CfgWriteStr(Section, L"Reg_Dump_Filename", RegDumpFileName);
}
static void EnableMessages(HWND hWnd)
{
ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled);
ENABLE_CONTROL(IDC_MSGKEY, MsgToConsole());
ENABLE_CONTROL(IDC_MSGVOICE, MsgToConsole());
ENABLE_CONTROL(IDC_MSGDMA, MsgToConsole());
ENABLE_CONTROL(IDC_MSGADMA, MsgToConsole());
ENABLE_CONTROL(IDC_DBG_OVERRUNS, MsgToConsole());
ENABLE_CONTROL(IDC_DBG_CACHE, MsgToConsole());
}
void EnableControls(HWND hWnd)
{
EnableMessages(hWnd);
ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled);
ENABLE_CONTROL(IDC_LOGREGS, IsDevBuild ? DebugEnabled : false);
ENABLE_CONTROL(IDC_LOGWAVE, IsDevBuild ? DebugEnabled : false);
ENABLE_CONTROL(IDC_DUMPCORE, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPREGS, DebugEnabled);
ENABLE_CONTROL(IDC_DEBUG_VISUAL, IsDevBuild ? DebugEnabled : false);
}
static BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId;
//wchar_t temp[384]={0};
switch (uMsg) {
case WM_PAINT:
return FALSE;
case WM_INITDIALOG: {
EnableControls(hWnd);
// Debugging / Logging Flags:
SET_CHECK(IDC_DEBUG, DebugEnabled);
SET_CHECK(IDC_MSGSHOW, _MsgToConsole);
SET_CHECK(IDC_MSGKEY, _MsgKeyOnOff);
SET_CHECK(IDC_MSGVOICE, _MsgVoiceOff);
SET_CHECK(IDC_MSGDMA, _MsgDMA);
SET_CHECK(IDC_MSGADMA, _MsgAutoDMA);
SET_CHECK(IDC_DBG_OVERRUNS, _MsgOverruns);
SET_CHECK(IDC_DBG_CACHE, _MsgCache);
SET_CHECK(IDC_LOGREGS, _AccessLog);
SET_CHECK(IDC_LOGDMA, _DMALog);
SET_CHECK(IDC_LOGWAVE, _WaveLog);
SET_CHECK(IDC_DUMPCORE, _CoresDump);
SET_CHECK(IDC_DUMPMEM, _MemDump);
SET_CHECK(IDC_DUMPREGS, _RegDump);
SET_CHECK(IDC_DEBUG_VISUAL, _visual_debug_enabled);
ShowWindow(GetDlgItem(hWnd, IDC_MSG_PUBLIC_BUILD), !IsDevBuild);
} break;
case WM_COMMAND:
wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId) {
case IDOK:
WriteSettings();
EndDialog(hWnd, 0);
break;
case IDCANCEL:
EndDialog(hWnd, 0);
break;
HANDLE_CHECKNB(IDC_MSGSHOW, _MsgToConsole);
EnableMessages(hWnd);
break;
HANDLE_CHECK(IDC_MSGKEY, _MsgKeyOnOff);
HANDLE_CHECK(IDC_MSGVOICE, _MsgVoiceOff);
HANDLE_CHECK(IDC_MSGDMA, _MsgDMA);
HANDLE_CHECK(IDC_MSGADMA, _MsgAutoDMA);
break;
HANDLE_CHECK(IDC_DBG_OVERRUNS, _MsgOverruns);
HANDLE_CHECK(IDC_DBG_CACHE, _MsgCache);
HANDLE_CHECK(IDC_LOGREGS, _AccessLog);
HANDLE_CHECK(IDC_LOGDMA, _DMALog);
HANDLE_CHECK(IDC_LOGWAVE, _WaveLog);
HANDLE_CHECK(IDC_DUMPCORE, _CoresDump);
HANDLE_CHECK(IDC_DUMPMEM, _MemDump);
HANDLE_CHECK(IDC_DUMPREGS, _RegDump);
HANDLE_CHECK(IDC_DEBUG_VISUAL, _visual_debug_enabled);
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
void OpenDialog()
{
INT_PTR ret = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_CONFIG_DEBUG), GetActiveWindow(), (DLGPROC)DialogProc, 1);
if (ret == -1) {
MessageBox(GetActiveWindow(), L"Error Opening the debug configuration dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
ReadSettings();
}
}

View File

@ -1,131 +0,0 @@
/* 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 "Dialogs.h"
#include "soundtouch/SoundTouch.h"
static int SequenceLenMS = 30;
static int SeekWindowMS = 20;
static int OverlapMS = 10;
// Timestretch Slider Bounds, Min/Max
static const int SequenceLen_Min = 20;
static const int SequenceLen_Max = 100;
static const int SeekWindow_Min = 10;
static const int SeekWindow_Max = 30;
static const int Overlap_Min = 5;
static const int Overlap_Max = 15;
void SoundtouchCfg::ApplySettings(soundtouch::SoundTouch &sndtouch)
{
sndtouch.setSetting(SETTING_SEQUENCE_MS, SequenceLenMS);
sndtouch.setSetting(SETTING_SEEKWINDOW_MS, SeekWindowMS);
sndtouch.setSetting(SETTING_OVERLAP_MS, OverlapMS);
}
static void ClampValues()
{
Clampify(SequenceLenMS, SequenceLen_Min, SequenceLen_Max);
Clampify(SeekWindowMS, SeekWindow_Min, SeekWindow_Max);
Clampify(OverlapMS, Overlap_Min, Overlap_Max);
}
void SoundtouchCfg::ReadSettings()
{
SequenceLenMS = CfgReadInt(L"SOUNDTOUCH", L"SequenceLengthMS", 30);
SeekWindowMS = CfgReadInt(L"SOUNDTOUCH", L"SeekWindowMS", 20);
OverlapMS = CfgReadInt(L"SOUNDTOUCH", L"OverlapMS", 10);
ClampValues();
}
void SoundtouchCfg::WriteSettings()
{
CfgWriteInt(L"SOUNDTOUCH", L"SequenceLengthMS", SequenceLenMS);
CfgWriteInt(L"SOUNDTOUCH", L"SeekWindowMS", SeekWindowMS);
CfgWriteInt(L"SOUNDTOUCH", L"OverlapMS", OverlapMS);
}
BOOL CALLBACK SoundtouchCfg::DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId;
//wchar_t temp[384]={0};
switch (uMsg) {
case WM_PAINT:
return FALSE;
case WM_INITDIALOG: {
INIT_SLIDER(IDC_SEQLEN_SLIDER, SequenceLen_Min, SequenceLen_Max, 20, 5, 1);
INIT_SLIDER(IDC_SEEKWIN_SLIDER, SeekWindow_Min, SeekWindow_Max, 5, 2, 1);
INIT_SLIDER(IDC_OVERLAP_SLIDER, Overlap_Min, Overlap_Max, 3, 2, 1);
SendDialogMsg(hWnd, IDC_SEQLEN_SLIDER, TBM_SETPOS, TRUE, SequenceLenMS);
SendDialogMsg(hWnd, IDC_SEEKWIN_SLIDER, TBM_SETPOS, TRUE, SeekWindowMS);
SendDialogMsg(hWnd, IDC_OVERLAP_SLIDER, TBM_SETPOS, TRUE, OverlapMS);
}
case WM_COMMAND:
wmId = LOWORD(wParam);
// Parse the menu selections:
if (wmId == IDOK) {
SequenceLenMS = (int)SendDialogMsg(hWnd, IDC_SEQLEN_SLIDER, TBM_GETPOS, 0, 0);
SeekWindowMS = (int)SendDialogMsg(hWnd, IDC_SEEKWIN_SLIDER, TBM_GETPOS, 0, 0);
OverlapMS = (int)SendDialogMsg(hWnd, IDC_OVERLAP_SLIDER, TBM_GETPOS, 0, 0);
ClampValues();
WriteSettings();
EndDialog(hWnd, 0);
} else if (wmId == IDC_RESET_DEFAULTS) {
SequenceLenMS = 30;
SeekWindowMS = 20;
OverlapMS = 10;
SendDialogMsg(hWnd, IDC_SEQLEN_SLIDER, TBM_SETPOS, TRUE, SequenceLenMS);
SendDialogMsg(hWnd, IDC_SEEKWIN_SLIDER, TBM_SETPOS, TRUE, SeekWindowMS);
SendDialogMsg(hWnd, IDC_OVERLAP_SLIDER, TBM_SETPOS, TRUE, OverlapMS);
AssignSliderValue((HWND)lParam, hWnd, SequenceLenMS);
} else if (wmId == IDCANCEL) {
EndDialog(hWnd, 0);
}
break;
case WM_HSCROLL:
DoHandleScrollMessage(hWnd, wParam, lParam);
break;
default:
return FALSE;
}
return TRUE;
}
void SoundtouchCfg::OpenDialog(HWND hWnd)
{
INT_PTR ret;
ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_CONFIG_SOUNDTOUCH), hWnd, (DLGPROC)DialogProc);
if (ret == -1) {
MessageBox(GetActiveWindow(), L"Error Opening the Soundtouch advanced dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
ReadSettings();
}

View File

@ -1,76 +0,0 @@
/* 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
#ifdef _WIN32
#include "WinConfig.h"
#else
#include "LnxConfig.h"
#endif
namespace DebugConfig
{
extern void ReadSettings();
extern void WriteSettings();
extern void OpenDialog();
extern void EnableControls(HWND hWnd);
}
namespace SoundtouchCfg
{
extern void ReadSettings();
extern void WriteSettings();
extern void OpenDialog(HWND hWnd);
extern BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
}
extern int SendDialogMsg(HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam);
extern void AssignSliderValue(HWND idcwnd, HWND hwndDisplay, int value);
extern void AssignSliderValue(HWND hWnd, int idc, int editbox, int value);
extern int GetSliderValue(HWND hWnd, int idc);
extern BOOL DoHandleScrollMessage(HWND hwndDisplay, WPARAM wParam, LPARAM lParam);
extern void CfgSetSettingsDir(const char *dir);
extern void CfgSetLogDir(const char *dir);
extern bool CfgFindName(const TCHAR *Section, const TCHAR *Name);
extern void CfgWriteBool(const TCHAR *Section, const TCHAR *Name, bool Value);
extern void CfgWriteInt(const TCHAR *Section, const TCHAR *Name, int Value);
extern void CfgWriteFloat(const TCHAR *Section, const TCHAR *Name, float Value);
extern void CfgWriteStr(const TCHAR *Section, const TCHAR *Name, const wxString &Data);
extern bool CfgReadBool(const TCHAR *Section, const TCHAR *Name, bool Default);
extern void CfgReadStr(const TCHAR *Section, const TCHAR *Name, wxString &Data, const TCHAR *Default);
extern void CfgReadStr(const TCHAR *Section, const TCHAR *Name, TCHAR *Data, int DataSize, const TCHAR *Default);
extern int CfgReadInt(const TCHAR *Section, const TCHAR *Name, int Default);
extern float CfgReadFloat(const TCHAR *Section, const TCHAR *Name, float Default);
// Items Specific to DirectSound
#define STRFY(x) #x
#define verifyc(x) Verifyc(x, STRFY(x))
extern void Verifyc(HRESULT hr, const char *fn);
struct ds_device_data
{
wxString name;
GUID guid;
bool hasGuid;
};

View File

@ -1,269 +0,0 @@
/* 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 "Dialogs.h"
bool debugDialogOpen = false;
HWND hDebugDialog = NULL;
#ifdef PCSX2_DEVBUILD
int FillRectangle(HDC dc, int left, int top, int width, int height)
{
RECT r = {left, top, left + width, top + height};
return FillRect(dc, &r, (HBRUSH)GetStockObject(DC_BRUSH));
}
BOOL DrawRectangle(HDC dc, int left, int top, int width, int height)
{
RECT r = {left, top, left + width, top + height};
POINT p[5] = {
{r.left, r.top},
{r.right, r.top},
{r.right, r.bottom},
{r.left, r.bottom},
{r.left, r.top},
};
return Polyline(dc, p, 5);
}
HFONT hf = NULL;
int lCount = 0;
void UpdateDebugDialog()
{
if (!debugDialogOpen)
return;
lCount++;
if (lCount >= (SampleRate / 100)) // Increase to SampleRate/200 for smooth display.
{
HDC hdc = GetDC(hDebugDialog);
if (!hf) {
hf = CreateFont(12, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Lucida Console");
}
SelectObject(hdc, hf);
SelectObject(hdc, GetStockObject(DC_BRUSH));
SelectObject(hdc, GetStockObject(DC_PEN));
for (int c = 0; c < 2; c++) {
V_Core &cx(Cores[c]);
V_CoreDebug &cd(DebugCores[c]);
for (int v = 0; v < 24; v++) {
int cc = c * 2 + (v / 12);
int vv = v % 12;
int IX = 8 + 128 * cc;
int IY = 8 + 48 * vv;
V_Voice &vc(cx.Voices[v]);
V_VoiceDebug &vcd(cd.Voices[v]);
SetDCBrushColor(hdc, RGB(0, 0, 0));
if ((vc.ADSR.Phase > 0) && (vc.ADSR.Phase < 6)) {
SetDCBrushColor(hdc, RGB(0, 0, 128)); // light blue for playing voice
if (vc.Modulated) {
SetDCBrushColor(hdc, RGB(0, 128, 0)); // light green for playing voice with modulation enabled
}
if (vc.Noise) {
SetDCBrushColor(hdc, RGB(128, 0, 0)); // light red for playing voice with noise enabled
}
}
/*
else
{
if(vcd.lastStopReason==1)
{
SetDCBrushColor(hdc,RGB(128, 0, 0));
}
if(vcd.lastStopReason==2)
{
SetDCBrushColor(hdc,RGB( 0,128, 0));
}
}*/
FillRectangle(hdc, IX, IY, 124, 46);
SetDCPenColor(hdc, RGB(255, 128, 32));
DrawRectangle(hdc, IX, IY, 124, 46);
SetDCBrushColor(hdc, RGB(0, 255, 0));
int vl = abs(((vc.Volume.Left.Value >> 16) * 38) >> 15);
int vr = abs(((vc.Volume.Right.Value >> 16) * 38) >> 15);
FillRectangle(hdc, IX + 58, IY + 42 - vl, 4, vl);
FillRectangle(hdc, IX + 62, IY + 42 - vr, 4, vr);
int adsr = ((vc.ADSR.Value >> 16) * 38) / 32768;
FillRectangle(hdc, IX + 66, IY + 42 - adsr, 4, adsr);
int peak = (vcd.displayPeak * 38) / 32768;
if (vcd.displayPeak >= 32700) // leave a little bit of margin
{
SetDCBrushColor(hdc, RGB(255, 0, 0));
}
FillRectangle(hdc, IX + 70, IY + 42 - peak, 4, peak);
if (vc.ADSR.Value > 0) {
if (vc.SBuffer)
for (int i = 0; i < 28; i++) {
int val = ((int)vc.SBuffer[i] * 20) / 32768;
int y = 0;
if (val > 0) {
y = val;
} else
val = -val;
if (val != 0) {
FillRectangle(hdc, IX + 90 + i, IY + 24 - y, 1, val);
}
}
}
SetTextColor(hdc, RGB(0, 255, 0));
SetBkColor(hdc, RGB(0, 0, 0));
static wchar_t t[256];
swprintf_s(t, L"%06x", vc.StartA);
TextOut(hdc, IX + 4, IY + 4, t, 6);
swprintf_s(t, L"%06x", vc.NextA);
TextOut(hdc, IX + 4, IY + 18, t, 6);
swprintf_s(t, L"%06x", vc.LoopStartA);
TextOut(hdc, IX + 4, IY + 32, t, 6);
vcd.displayPeak = 0;
}
// top now: 400
int JX = 8 + c * 256;
int JY = 584;
SetDCBrushColor(hdc, RGB(0, 0, 0));
SetDCPenColor(hdc, RGB(255, 128, 32));
FillRectangle(hdc, JX, JY, 252, 60);
DrawRectangle(hdc, JX, JY, 252, 60);
SetTextColor(hdc, RGB(255, 255, 255));
SetBkColor(hdc, RGB(0, 0, 0));
static wchar_t t[256];
TextOut(hdc, JX + 4, JY + 4, L"REVB", 4);
TextOut(hdc, JX + 4, JY + 18, L"IRQE", 4);
TextOut(hdc, JX + 4, JY + 32, L"ADMA", 4);
swprintf_s(t, L"DMA%s", c == 0 ? L"4" : L"7");
TextOut(hdc, JX + 4, JY + 46, t, 4);
SetTextColor(hdc, RGB(0, 255, 0));
memset(t, 0, sizeof(t));
swprintf_s(t, L"ESA %x", cx.EffectsStartA);
TextOut(hdc, JX + 56, JY + 4, t, 9);
memset(t, 0, sizeof(t));
swprintf_s(t, L"EEA %x", cx.EffectsEndA);
TextOut(hdc, JX + 128, JY + 4, t, 9);
memset(t, 0, sizeof(t));
swprintf_s(t, L"(%x)", cx.EffectsBufferSize);
TextOut(hdc, JX + 200, JY + 4, t, 7);
memset(t, 0, sizeof(t));
swprintf_s(t, L"IRQA %x", cx.IRQA);
TextOut(hdc, JX + 56, JY + 18, t, 12);
SetTextColor(hdc, RGB(255, 255, 255));
SetDCBrushColor(hdc, RGB(255, 0, 0));
if (cx.FxEnable) {
FillRectangle(hdc, JX + 40, JY + 4, 10, 10);
}
if (cx.IRQEnable) {
FillRectangle(hdc, JX + 40, JY + 18, 10, 10);
}
if (cx.AutoDMACtrl != 0) {
FillRectangle(hdc, JX + 40, JY + 32, 10, 10);
for (int j = 0; j < 64; j++) {
int i = j * 256 / 64;
int val = (cd.admaWaveformL[i] * 26) / 32768;
int y = 0;
if (val > 0)
y = val;
else
val = -val;
if (val != 0) {
FillRectangle(hdc, JX + 60 + j, JY + 30 - y, 1, val);
}
}
for (int j = 0; j < 64; j++) {
int i = j * 256 / 64;
int val = (cd.admaWaveformR[i] * 26) / 32768;
int y = 0;
if (val > 0)
y = val;
else
val = -val;
if (val != 0) {
FillRectangle(hdc, JX + 136 + j, JY + 30 - y, 1, val);
}
}
}
if (cd.dmaFlag > 0) // So it shows x times this is called, since dmas are so fast
{
swprintf_s(t, L"size = %d", cd.lastsize);
TextOut(hdc, JX + 64, JY + 46, t, wcslen(t));
FillRectangle(hdc, JX + 40, JY + 46, 10, 10);
cd.dmaFlag--;
}
}
ReleaseDC(hDebugDialog, hdc);
lCount = 0;
}
MSG msg;
while (PeekMessage(&msg, hDebugDialog, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#else
void UpdateDebugDialog()
{
// Release mode. Nothing to do
}
#endif

View File

@ -1,457 +0,0 @@
/* 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"
#define _WIN32_DCOM
#include "Dialogs.h"
#define DIRECTSOUND_VERSION 0x1000
#include <dsound.h>
class DSound : public SndOutModule
{
private:
static const uint MAX_BUFFER_COUNT = 8;
static const int PacketsPerBuffer = 8;
static const int BufferSize = SndOutPacketSize * PacketsPerBuffer;
//////////////////////////////////////////////////////////////////////////////////////////
// Configuration Vars
wxString m_Device;
u8 m_NumBuffers;
bool m_DisableGlobalFocus;
bool m_UseHardware;
ds_device_data m_devices[32];
int ndevs;
GUID DevGuid; // currently employed GUID.
bool haveGuid;
//////////////////////////////////////////////////////////////////////////////////////////
// Instance vars
int channel;
int myLastWrite; // last write position, in bytes
bool dsound_running;
HANDLE thread;
DWORD tid;
IDirectSound8 *dsound;
IDirectSoundBuffer8 *buffer;
IDirectSoundNotify8 *buffer_notify;
HANDLE buffer_events[MAX_BUFFER_COUNT];
WAVEFORMATEX wfx;
HANDLE waitEvent;
template <typename T>
static DWORD CALLBACK RThread(DSound *obj)
{
return obj->Thread<T>();
}
template <typename T>
DWORD CALLBACK Thread()
{
static const int BufferSizeBytes = BufferSize * sizeof(T);
while (dsound_running) {
u32 rv = WaitForMultipleObjects(m_NumBuffers, buffer_events, FALSE, 200);
T *p1, *oldp1;
LPVOID p2;
DWORD s1, s2;
u32 poffset = BufferSizeBytes * rv;
if (FAILED(buffer->Lock(poffset, BufferSizeBytes, (LPVOID *)&p1, &s1, &p2, &s2, 0))) {
assert(0);
fputs("* SPU2-X: Directsound Warning > Buffer lock failure. You may need to increase\n\tyour configured DSound buffer count.\n", stderr);
continue;
}
oldp1 = p1;
for (int p = 0; p < PacketsPerBuffer; p++, p1 += SndOutPacketSize)
SndBuffer::ReadSamples(p1);
buffer->Unlock(oldp1, s1, p2, s2);
// Set the write pointer to the beginning of the next block.
myLastWrite = (poffset + BufferSizeBytes) & ~BufferSizeBytes;
}
return 0;
}
public:
s32 Init()
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
//
// Initialize DSound
//
GUID cGuid;
try {
if (m_Device.empty())
throw std::runtime_error("screw it");
if ((FAILED(IIDFromString(m_Device, &cGuid))) ||
FAILED(DirectSoundCreate8(&cGuid, &dsound, NULL)))
throw std::runtime_error("try again?");
} catch (std::runtime_error &) {
// if the GUID failed, just open up the default dsound driver:
if (FAILED(DirectSoundCreate8(NULL, &dsound, NULL)))
throw std::runtime_error("DirectSound failed to initialize!");
}
if (FAILED(dsound->SetCooperativeLevel(GetDesktopWindow(), DSSCL_PRIORITY)))
throw std::runtime_error("DirectSound Error: Cooperative level could not be set.");
// Determine the user's speaker configuration, and select an expansion option as needed.
// FAIL : Directsound doesn't appear to support audio expansion >_<
DWORD speakerConfig = 2;
//dsound->GetSpeakerConfig( &speakerConfig );
IDirectSoundBuffer *buffer_;
DSBUFFERDESC desc;
// Set up WAV format structure.
memset(&wfx, 0, sizeof(WAVEFORMATEX));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nSamplesPerSec = SampleRate;
wfx.nChannels = (WORD)speakerConfig;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = 2 * (WORD)speakerConfig;
wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign;
wfx.cbSize = 0;
uint BufferSizeBytes = BufferSize * wfx.nBlockAlign;
// Set up DSBUFFERDESC structure.
memset(&desc, 0, sizeof(DSBUFFERDESC));
desc.dwSize = sizeof(DSBUFFERDESC);
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;
desc.dwBufferBytes = BufferSizeBytes * m_NumBuffers;
desc.lpwfxFormat = &wfx;
// Try a hardware buffer first, and then fall back on a software buffer if
// that one fails.
desc.dwFlags |= m_UseHardware ? DSBCAPS_LOCHARDWARE : DSBCAPS_LOCSOFTWARE;
desc.dwFlags |= m_DisableGlobalFocus ? DSBCAPS_STICKYFOCUS : DSBCAPS_GLOBALFOCUS;
if (FAILED(dsound->CreateSoundBuffer(&desc, &buffer_, 0))) {
if (m_UseHardware) {
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_LOCSOFTWARE;
desc.dwFlags |= m_DisableGlobalFocus ? DSBCAPS_STICKYFOCUS : DSBCAPS_GLOBALFOCUS;
if (FAILED(dsound->CreateSoundBuffer(&desc, &buffer_, 0)))
throw std::runtime_error("DirectSound Error: Buffer could not be created.");
}
throw std::runtime_error("DirectSound Error: Buffer could not be created.");
}
if (FAILED(buffer_->QueryInterface(IID_IDirectSoundBuffer8, (void **)&buffer)) || buffer == NULL)
throw std::runtime_error("DirectSound Error: Interface could not be queried.");
buffer_->Release();
verifyc(buffer->QueryInterface(IID_IDirectSoundNotify8, (void **)&buffer_notify));
DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT];
for (uint i = 0; i < m_NumBuffers; i++) {
buffer_events[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
not[i].dwOffset = (wfx.nBlockAlign + BufferSizeBytes * (i + 1)) % desc.dwBufferBytes;
not[i].hEventNotify = buffer_events[i];
}
buffer_notify->SetNotificationPositions(m_NumBuffers, not);
LPVOID p1 = 0, p2 = 0;
DWORD s1 = 0, s2 = 0;
verifyc(buffer->Lock(0, desc.dwBufferBytes, &p1, &s1, &p2, &s2, 0));
assert(p2 == 0);
memset(p1, 0, s1);
verifyc(buffer->Unlock(p1, s1, p2, s2));
//Play the buffer !
verifyc(buffer->Play(0, 0, DSBPLAY_LOOPING));
// Start Thread
myLastWrite = 0;
dsound_running = true;
thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RThread<StereoOut16>, this, 0, &tid);
SetThreadPriority(thread, THREAD_PRIORITY_ABOVE_NORMAL);
return 0;
}
void Close()
{
// Stop Thread
fprintf(stderr, "* SPU2-X: Waiting for DSound thread to finish...");
dsound_running = false;
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
fprintf(stderr, " Done.\n");
//
// Clean up
//
if (buffer != NULL) {
buffer->Stop();
for (u32 i = 0; i < m_NumBuffers; i++) {
if (buffer_events[i] != NULL)
CloseHandle(buffer_events[i]);
buffer_events[i] = NULL;
}
safe_release(buffer_notify);
safe_release(buffer);
}
safe_release(dsound);
CoUninitialize();
}
private:
bool _DSEnumCallback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext)
{
m_devices[ndevs].name = lpcstrDescription;
if (lpGuid) {
m_devices[ndevs].guid = *lpGuid;
m_devices[ndevs].hasGuid = true;
} else {
m_devices[ndevs].hasGuid = false;
}
ndevs++;
if (ndevs < 32)
return TRUE;
return FALSE;
}
bool _ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
int tSel = 0;
switch (uMsg) {
case WM_INITDIALOG: {
wchar_t temp[128];
haveGuid = !FAILED(IIDFromString(m_Device, &DevGuid));
SendMessage(GetDlgItem(hWnd, IDC_DS_DEVICE), CB_RESETCONTENT, 0, 0);
ndevs = 0;
DirectSoundEnumerate(DSEnumCallback, NULL);
tSel = -1;
for (int i = 0; i < ndevs; i++) {
SendMessage(GetDlgItem(hWnd, IDC_DS_DEVICE), CB_ADDSTRING, 0, (LPARAM)m_devices[i].name.wc_str());
if (haveGuid && IsEqualGUID(m_devices[i].guid, DevGuid) || tSel < 0 && !m_devices[i].hasGuid)
tSel = i;
}
if (tSel >= 0)
SendMessage(GetDlgItem(hWnd, IDC_DS_DEVICE), CB_SETCURSEL, tSel, 0);
INIT_SLIDER(IDC_BUFFERS_SLIDER, 2, MAX_BUFFER_COUNT, 2, 1, 1);
SendMessage(GetDlgItem(hWnd, IDC_BUFFERS_SLIDER), TBM_SETPOS, TRUE, m_NumBuffers);
swprintf_s(temp, L"%d (%d ms latency)", m_NumBuffers, 1000 / (96000 / (m_NumBuffers * BufferSize)));
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
SET_CHECK(IDC_GLOBALFOCUS_DISABLE, m_DisableGlobalFocus);
SET_CHECK(IDC_USE_HARDWARE, m_UseHardware);
} break;
case WM_COMMAND: {
wchar_t temp[128];
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId) {
case IDOK: {
int i = (int)SendMessage(GetDlgItem(hWnd, IDC_DS_DEVICE), CB_GETCURSEL, 0, 0);
if (!m_devices[i].hasGuid) {
m_Device[0] = 0; // clear device name to ""
} else {
swprintf_s(temp, L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
m_devices[i].guid.Data1,
m_devices[i].guid.Data2,
m_devices[i].guid.Data3,
m_devices[i].guid.Data4[0],
m_devices[i].guid.Data4[1],
m_devices[i].guid.Data4[2],
m_devices[i].guid.Data4[3],
m_devices[i].guid.Data4[4],
m_devices[i].guid.Data4[5],
m_devices[i].guid.Data4[6],
m_devices[i].guid.Data4[7]);
m_Device = temp;
}
m_NumBuffers = (int)SendMessage(GetDlgItem(hWnd, IDC_BUFFERS_SLIDER), TBM_GETPOS, 0, 0);
if (m_NumBuffers < 2)
m_NumBuffers = 2;
if (m_NumBuffers > MAX_BUFFER_COUNT)
m_NumBuffers = MAX_BUFFER_COUNT;
EndDialog(hWnd, 0);
} break;
case IDCANCEL:
EndDialog(hWnd, 0);
break;
HANDLE_CHECK(IDC_GLOBALFOCUS_DISABLE, m_DisableGlobalFocus);
HANDLE_CHECK(IDC_USE_HARDWARE, m_UseHardware);
default:
return FALSE;
}
} break;
case WM_HSCROLL: {
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId) {
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_TOP:
case TB_BOTTOM:
wmEvent = (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
case TB_THUMBPOSITION:
case TB_THUMBTRACK: {
wchar_t temp[128];
if (wmEvent < 2)
wmEvent = 2;
if (wmEvent > MAX_BUFFER_COUNT)
wmEvent = MAX_BUFFER_COUNT;
SendMessage((HWND)lParam, TBM_SETPOS, TRUE, wmEvent);
swprintf_s(temp, L"%d (%d ms latency)", wmEvent, 1000 / (96000 / (wmEvent * BufferSize)));
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
break;
}
default:
return FALSE;
}
} break;
default:
return FALSE;
}
return TRUE;
}
static BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK DSEnumCallback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext);
public:
virtual void Configure(uptr parent)
{
INT_PTR ret;
ret = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_DSOUND), (HWND)parent, (DLGPROC)ConfigProc, 1);
if (ret == -1) {
MessageBox((HWND)parent, L"Error Opening the config dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
}
s32 Test() const
{
return 0;
}
int GetEmptySampleCount()
{
DWORD play, write;
buffer->GetCurrentPosition(&play, &write);
// Note: Dsound's write cursor is bogus. Use our own instead:
int empty = play - myLastWrite;
if (empty < 0)
empty = -empty;
return empty / 2;
}
const wchar_t *GetIdent() const
{
return L"dsound";
}
const wchar_t *GetLongName() const
{
return L"DirectSound (Nice)";
}
void ReadSettings()
{
CfgReadStr(L"DSOUNDOUT", L"Device", m_Device, L"default");
m_NumBuffers = CfgReadInt(L"DSOUNDOUT", L"Buffer_Count", 5);
m_DisableGlobalFocus = CfgReadBool(L"DSOUNDOUT", L"Disable_Global_Focus", false);
m_UseHardware = CfgReadBool(L"DSOUNDOUT", L"Use_Hardware", false);
Clampify(m_NumBuffers, (u8)3, (u8)8);
}
void SetApiSettings(wxString api)
{
}
void WriteSettings() const
{
CfgWriteStr(L"DSOUNDOUT", L"Device", m_Device.empty() ? L"default" : m_Device);
CfgWriteInt(L"DSOUNDOUT", L"Buffer_Count", m_NumBuffers);
CfgWriteBool(L"DSOUNDOUT", L"Disable_Global_Focus", m_DisableGlobalFocus);
CfgWriteBool(L"DSOUNDOUT", L"Use_Hardware", m_UseHardware);
}
} static DS;
BOOL CALLBACK DSound::ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DS._ConfigProc(hWnd, uMsg, wParam, lParam);
}
BOOL CALLBACK DSound::DSEnumCallback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext)
{
pxAssume(DSoundOut != NULL);
return DS._DSEnumCallback(lpGuid, lpcstrDescription, lpcstrModule, lpContext);
}
SndOutModule *DSoundOut = &DS;

View File

@ -1,423 +0,0 @@
/* 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 "Dialogs.h"
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0602
#include <xaudio2.h>
#include <atlcomcli.h>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
namespace Exception
{
class XAudio2Error : public std::runtime_error
{
private:
static std::string CreateErrorMessage(const HRESULT result, const std::string &msg)
{
std::stringstream ss;
ss << " (code 0x" << std::hex << result << ")\n\n";
switch (result) {
case XAUDIO2_E_INVALID_CALL:
ss << "Invalid call for the XA2 object state.";
break;
case XAUDIO2_E_DEVICE_INVALIDATED:
ss << "Device is unavailable, unplugged, unsupported, or has been consumed by The Nothing.";
break;
default:
ss << "Unknown error code!";
break;
}
return msg + ss.str();
}
public:
explicit XAudio2Error(const HRESULT result, const std::string &msg)
: std::runtime_error(CreateErrorMessage(result, msg))
{
}
};
}
static const double SndOutNormalizer = (double)(1UL << (SndOutVolumeShift + 16));
class XAudio2Mod : public SndOutModule
{
private:
static const int PacketsPerBuffer = 8;
static const int MAX_BUFFER_COUNT = 3;
class BaseStreamingVoice : public IXAudio2VoiceCallback
{
protected:
IXAudio2SourceVoice *pSourceVoice;
std::unique_ptr<s16[]> m_buffer;
const uint m_nBuffers;
const uint m_nChannels;
const uint m_BufferSize;
const uint m_BufferSizeBytes;
CRITICAL_SECTION cs;
public:
int GetEmptySampleCount()
{
XAUDIO2_VOICE_STATE state;
pSourceVoice->GetState(&state);
return state.SamplesPlayed & (m_BufferSize - 1);
}
virtual ~BaseStreamingVoice()
{
DeleteCriticalSection(&cs);
}
BaseStreamingVoice(uint numChannels)
: pSourceVoice(nullptr)
, m_nBuffers(Config_XAudio2.NumBuffers)
, m_nChannels(numChannels)
, m_BufferSize(SndOutPacketSize * m_nChannels * PacketsPerBuffer)
, m_BufferSizeBytes(m_BufferSize * sizeof(s16))
{
InitializeCriticalSection(&cs);
}
virtual void Init(IXAudio2 *pXAudio2) = 0;
protected:
// Several things must be initialized separate of the constructor, due to the fact that
// virtual calls can't be made from the constructor's context.
void _init(IXAudio2 *pXAudio2, uint chanConfig)
{
WAVEFORMATEXTENSIBLE wfx;
memset(&wfx, 0, sizeof(WAVEFORMATEXTENSIBLE));
wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfx.Format.nSamplesPerSec = SampleRate;
wfx.Format.nChannels = m_nChannels;
wfx.Format.wBitsPerSample = 16;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = SampleRate * wfx.Format.nBlockAlign;
wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
wfx.Samples.wValidBitsPerSample = 16;
wfx.dwChannelMask = chanConfig;
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
HRESULT hr;
if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX *)&wfx,
XAUDIO2_VOICE_NOSRC, 1.0f, this))) {
throw Exception::XAudio2Error(hr, "XAudio2 CreateSourceVoice failure: ");
}
EnterCriticalSection(&cs);
pSourceVoice->FlushSourceBuffers();
pSourceVoice->Start(0, 0);
m_buffer = std::make_unique<s16[]>(m_nBuffers * m_BufferSize);
// Start some buffers.
for (uint i = 0; i < m_nBuffers; i++) {
XAUDIO2_BUFFER buf = {0};
buf.AudioBytes = m_BufferSizeBytes;
buf.pContext = &m_buffer[i * m_BufferSize];
buf.pAudioData = (BYTE *)buf.pContext;
pSourceVoice->SubmitSourceBuffer(&buf);
}
LeaveCriticalSection(&cs);
}
STDMETHOD_(void, OnVoiceProcessingPassStart)
() {}
STDMETHOD_(void, OnVoiceProcessingPassStart)
(UINT32) {}
STDMETHOD_(void, OnVoiceProcessingPassEnd)
() {}
STDMETHOD_(void, OnStreamEnd)
() {}
STDMETHOD_(void, OnBufferStart)
(void *) {}
STDMETHOD_(void, OnLoopEnd)
(void *) {}
STDMETHOD_(void, OnVoiceError)
(THIS_ void *pBufferContext, HRESULT Error) {}
};
template <typename T>
class StreamingVoice : public BaseStreamingVoice
{
public:
StreamingVoice()
: BaseStreamingVoice(sizeof(T) / sizeof(s16))
{
}
virtual ~StreamingVoice()
{
IXAudio2SourceVoice *killMe = pSourceVoice;
// XXX: Potentially leads to a race condition that causes a nullptr
// dereference when SubmitSourceBuffer is called in OnBufferEnd?
pSourceVoice = nullptr;
if (killMe != nullptr) {
killMe->FlushSourceBuffers();
killMe->DestroyVoice();
}
// XXX: Not sure we even need a critical section - DestroyVoice is
// blocking, and the documentation states no callbacks are called
// or audio data is read after it returns, so it's safe to free up
// resources.
EnterCriticalSection(&cs);
m_buffer = nullptr;
LeaveCriticalSection(&cs);
}
void Init(IXAudio2 *pXAudio2)
{
int chanMask = 0;
switch (m_nChannels) {
case 1:
chanMask |= SPEAKER_FRONT_CENTER;
break;
case 2:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
break;
case 3:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY;
break;
case 4:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
break;
case 5:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
break;
case 6:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
break;
case 8:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT | SPEAKER_LOW_FREQUENCY;
break;
}
_init(pXAudio2, chanMask);
}
protected:
STDMETHOD_(void, OnBufferEnd)
(void *context)
{
EnterCriticalSection(&cs);
// All of these checks are necessary because XAudio2 is wonky shizat.
// XXX: The pSourceVoice nullptr check seems a bit self-inflicted
// due to the destructor logic.
if (pSourceVoice == nullptr || context == nullptr) {
LeaveCriticalSection(&cs);
return;
}
T *qb = (T *)context;
for (int p = 0; p < PacketsPerBuffer; p++, qb += SndOutPacketSize)
SndBuffer::ReadSamples(qb);
XAUDIO2_BUFFER buf = {0};
buf.AudioBytes = m_BufferSizeBytes;
buf.pAudioData = (BYTE *)context;
buf.pContext = context;
pSourceVoice->SubmitSourceBuffer(&buf);
LeaveCriticalSection(&cs);
}
};
HMODULE xAudio2DLL = nullptr;
decltype(&XAudio2Create) pXAudio2Create = nullptr;
CComPtr<IXAudio2> pXAudio2;
IXAudio2MasteringVoice *pMasteringVoice = nullptr;
std::unique_ptr<BaseStreamingVoice> m_voiceContext;
public:
s32 Init()
{
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
try {
HRESULT hr;
xAudio2DLL = LoadLibraryEx(XAUDIO2_DLL, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (xAudio2DLL == nullptr)
throw std::runtime_error("Could not load " XAUDIO2_DLL_A ". Error code:" + std::to_string(GetLastError()));
pXAudio2Create = reinterpret_cast<decltype(&XAudio2Create)>(GetProcAddress(xAudio2DLL, "XAudio2Create"));
if (pXAudio2Create == nullptr)
throw std::runtime_error("XAudio2Create not found. Error code: " + std::to_string(GetLastError()));
if (FAILED(hr = pXAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)))
throw Exception::XAudio2Error(hr, "Failed to init XAudio2 engine. Error Details:");
// Stereo Expansion was planned to grab the currently configured number of
// Speakers from Windows's audio config.
// This doesn't always work though, so let it be a user configurable option.
int speakers;
// speakers = (numSpeakers + 1) *2; ?
switch (numSpeakers) {
case 0: // Stereo
speakers = 2;
break;
case 1: // Quadrafonic
speakers = 4;
break;
case 2: // Surround 5.1
speakers = 6;
break;
case 3: // Surround 7.1
speakers = 8;
break;
default:
speakers = 2;
}
if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice, speakers, SampleRate)))
throw Exception::XAudio2Error(hr, "Failed creating mastering voice: ");
switch (speakers) {
case 2:
ConLog("* SPU2 > Using normal 2 speaker stereo output.\n");
m_voiceContext = std::make_unique<StreamingVoice<StereoOut16>>();
break;
case 3:
ConLog("* SPU2 > 2.1 speaker expansion enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo21Out16>>();
break;
case 4:
ConLog("* SPU2 > 4 speaker expansion enabled [quadraphenia]\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo40Out16>>();
break;
case 5:
ConLog("* SPU2 > 4.1 speaker expansion enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo41Out16>>();
break;
case 6:
case 7:
switch (dplLevel) {
case 0: // "normal" stereo upmix
ConLog("* SPU2 > 5.1 speaker expansion enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo51Out16>>();
break;
case 1: // basic Dpl decoder without rear stereo balancing
ConLog("* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo51Out16Dpl>>();
break;
case 2: // gigas PLII
ConLog("* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo51Out16DplII>>();
break;
}
break;
default: // anything 8 or more gets the 7.1 treatment!
ConLog("* SPU2 > 7.1 speaker expansion enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo51Out16>>();
break;
}
m_voiceContext->Init(pXAudio2);
} catch (std::runtime_error &ex) {
SysMessage(ex.what());
Close();
return -1;
}
return 0;
}
void Close()
{
// Clean up?
// All XAudio2 interfaces are released when the engine is destroyed,
// but being tidy never hurt.
// Actually it can hurt. As of DXSDK Aug 2008, doing a full cleanup causes
// XA2 on Vista to crash. Even if you copy/paste code directly from Microsoft.
// But doing no cleanup at all causes XA2 under XP to crash. So after much trial
// and error we found a happy compromise as follows:
m_voiceContext = nullptr;
if (pMasteringVoice != nullptr)
pMasteringVoice->DestroyVoice();
pMasteringVoice = nullptr;
pXAudio2.Release();
CoUninitialize();
if (xAudio2DLL) {
FreeLibrary(xAudio2DLL);
xAudio2DLL = nullptr;
pXAudio2Create = nullptr;
}
}
virtual void Configure(uptr parent)
{
}
s32 Test() const
{
return 0;
}
int GetEmptySampleCount()
{
if (m_voiceContext == nullptr)
return 0;
return m_voiceContext->GetEmptySampleCount();
}
const wchar_t *GetIdent() const
{
return L"xaudio2";
}
const wchar_t *GetLongName() const
{
return L"XAudio 2 (Recommended)";
}
void ReadSettings()
{
}
void SetApiSettings(wxString api)
{
}
void WriteSettings() const
{
}
} static XA2;
SndOutModule *XAudio2Out = &XA2;

View File

@ -1,323 +0,0 @@
/* 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 "Dialogs.h"
class WaveOutModule : public SndOutModule
{
private:
static const uint MAX_BUFFER_COUNT = 8;
static const int PacketsPerBuffer = (1024 / SndOutPacketSize);
static const int BufferSize = SndOutPacketSize * PacketsPerBuffer;
u32 numBuffers;
HWAVEOUT hwodevice;
WAVEFORMATEX wformat;
WAVEHDR whbuffer[MAX_BUFFER_COUNT];
StereoOut16 *qbuffer;
#define QBUFFER(x) (qbuffer + BufferSize * (x))
bool waveout_running;
HANDLE thread;
DWORD tid;
wchar_t ErrText[256];
template <typename T>
DWORD CALLBACK Thread()
{
static const int BufferSizeBytes = BufferSize * sizeof(T);
while (waveout_running) {
bool didsomething = false;
for (u32 i = 0; i < numBuffers; i++) {
if (!(whbuffer[i].dwFlags & WHDR_DONE))
continue;
WAVEHDR *buf = whbuffer + i;
buf->dwBytesRecorded = buf->dwBufferLength;
T *t = (T *)buf->lpData;
for (int p = 0; p < PacketsPerBuffer; p++, t += SndOutPacketSize)
SndBuffer::ReadSamples(t);
whbuffer[i].dwFlags &= ~WHDR_DONE;
waveOutWrite(hwodevice, buf, sizeof(WAVEHDR));
didsomething = true;
}
if (didsomething)
Sleep(1);
else
Sleep(0);
}
return 0;
}
template <typename T>
static DWORD CALLBACK RThread(WaveOutModule *obj)
{
return obj->Thread<T>();
}
public:
s32 Init()
{
numBuffers = Config_WaveOut.NumBuffers;
MMRESULT woores;
if (Test())
return -1;
// TODO : Use dsound to determine the speaker configuration, and expand audio from there.
#if 0
int speakerConfig;
//if( StereoExpansionEnabled )
speakerConfig = 2; // better not mess with this in wavout :p (rama)
// Any windows driver should support stereo at the software level, I should think!
pxAssume( speakerConfig > 1 );
LPTHREAD_START_ROUTINE threadproc;
switch( speakerConfig )
{
case 2:
ConLog( "* SPU2 > Using normal 2 speaker stereo output.\n" );
threadproc = (LPTHREAD_START_ROUTINE)&RThread<StereoOut16>;
speakerConfig = 2;
break;
case 4:
ConLog( "* SPU2 > 4 speaker expansion enabled [quadraphenia]\n" );
threadproc = (LPTHREAD_START_ROUTINE)&RThread<StereoQuadOut16>;
speakerConfig = 4;
break;
case 6:
case 7:
ConLog( "* SPU2 > 5.1 speaker expansion enabled.\n" );
threadproc = (LPTHREAD_START_ROUTINE)&RThread<Stereo51Out16>;
speakerConfig = 6;
break;
default:
ConLog( "* SPU2 > 7.1 speaker expansion enabled.\n" );
threadproc = (LPTHREAD_START_ROUTINE)&RThread<Stereo51Out16>;
speakerConfig = 8;
break;
}
#endif
wformat.wFormatTag = WAVE_FORMAT_PCM;
wformat.nSamplesPerSec = SampleRate;
wformat.wBitsPerSample = 16;
wformat.nChannels = 2;
wformat.nBlockAlign = ((wformat.wBitsPerSample * wformat.nChannels) / 8);
wformat.nAvgBytesPerSec = (wformat.nSamplesPerSec * wformat.nBlockAlign);
wformat.cbSize = 0;
qbuffer = new StereoOut16[BufferSize * numBuffers];
woores = waveOutOpen(&hwodevice, WAVE_MAPPER, &wformat, 0, 0, 0);
if (woores != MMSYSERR_NOERROR) {
waveOutGetErrorText(woores, (wchar_t *)&ErrText, 255);
SysMessage("WaveOut Error: %s", ErrText);
return -1;
}
const int BufferSizeBytes = wformat.nBlockAlign * BufferSize;
for (u32 i = 0; i < numBuffers; i++) {
whbuffer[i].dwBufferLength = BufferSizeBytes;
whbuffer[i].dwBytesRecorded = BufferSizeBytes;
whbuffer[i].dwFlags = 0;
whbuffer[i].dwLoops = 0;
whbuffer[i].dwUser = 0;
whbuffer[i].lpData = (LPSTR)QBUFFER(i);
whbuffer[i].lpNext = 0;
whbuffer[i].reserved = 0;
waveOutPrepareHeader(hwodevice, whbuffer + i, sizeof(WAVEHDR));
whbuffer[i].dwFlags |= WHDR_DONE; //avoid deadlock
}
// Start Thread
// [Air]: The waveout code does not use wait objects, so setting a time critical
// priority level is a bad idea. Standard priority will do fine. The buffer will get the
// love it needs and won't suck resources idling pointlessly. Just don't try to
// run it in uber-low-latency mode.
waveout_running = true;
thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RThread<StereoOut16>, this, 0, &tid);
return 0;
}
void Close()
{
// Stop Thread
fprintf(stderr, "* SPU2-X: Waiting for waveOut thread to finish...");
waveout_running = false;
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
fprintf(stderr, " Done.\n");
//
// Clean up
//
waveOutReset(hwodevice);
for (u32 i = 0; i < numBuffers; i++) {
waveOutUnprepareHeader(hwodevice, &whbuffer[i], sizeof(WAVEHDR));
}
waveOutClose(hwodevice);
safe_delete_array(qbuffer);
}
private:
static BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch (uMsg) {
case WM_INITDIALOG:
wchar_t temp[128];
INIT_SLIDER(IDC_BUFFERS_SLIDER, 3, MAX_BUFFER_COUNT, 2, 1, 1);
SendMessage(GetDlgItem(hWnd, IDC_BUFFERS_SLIDER), TBM_SETPOS, TRUE, Config_WaveOut.NumBuffers);
swprintf_s(temp, 128, L"%d (%d ms latency)", Config_WaveOut.NumBuffers, 1000 / (96000 / (Config_WaveOut.NumBuffers * BufferSize)));
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId) {
case IDOK: {
Config_WaveOut.NumBuffers = (int)SendMessage(GetDlgItem(hWnd, IDC_BUFFERS_SLIDER), TBM_GETPOS, 0, 0);
if (Config_WaveOut.NumBuffers < 3)
Config_WaveOut.NumBuffers = 3;
if (Config_WaveOut.NumBuffers > MAX_BUFFER_COUNT)
Config_WaveOut.NumBuffers = MAX_BUFFER_COUNT;
}
EndDialog(hWnd, 0);
break;
case IDCANCEL:
EndDialog(hWnd, 0);
break;
default:
return FALSE;
}
break;
case WM_HSCROLL:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId) {
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_TOP:
case TB_BOTTOM:
wmEvent = (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
case TB_THUMBPOSITION:
case TB_THUMBTRACK:
if (wmEvent < 3)
wmEvent = 3;
if (wmEvent > MAX_BUFFER_COUNT)
wmEvent = MAX_BUFFER_COUNT;
SendMessage((HWND)lParam, TBM_SETPOS, TRUE, wmEvent);
swprintf_s(temp, L"%d (%d ms latency)", wmEvent, 1000 / (96000 / (wmEvent * BufferSize)));
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
public:
virtual void Configure(uptr parent)
{
INT_PTR ret;
ret = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_WAVEOUT), (HWND)parent, (DLGPROC)ConfigProc, 1);
if (ret == -1) {
MessageBox((HWND)parent, L"Error Opening the config dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
}
s32 Test() const
{
if (waveOutGetNumDevs() == 0) {
SysMessage("No waveOut Devices Present\n");
return -1;
}
return 0;
}
int GetEmptySampleCount()
{
int result = 0;
for (int i = 0; i < MAX_BUFFER_COUNT; i++) {
result += (whbuffer[i].dwFlags & WHDR_DONE) ? BufferSize : 0;
}
return result;
}
const wchar_t *GetIdent() const
{
return L"waveout";
}
const wchar_t *GetLongName() const
{
return L"WaveOut (Laggy)";
}
void ReadSettings()
{
}
void SetApiSettings(wxString api)
{
}
void WriteSettings() const
{
}
} static WO;
SndOutModule *WaveOut = &WO;

View File

@ -1,62 +0,0 @@
; * SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
; * Developed and maintained by the Pcsx2 Development Team.
; *
; * Originally based on SPU2ghz v1.9 beta, by David Quintana.
; *
; * 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/>.
; SPU2-X.def : Declares the module parameters for the DLL.
;LIBRARY "SPU2-X"
EXPORTS
; Explicit exports can go here
PS2EgetLibType @2
PS2EgetLibName @3
PS2EgetLibVersion2 @4
SPU2init @5
SPU2shutdown @6
SPU2open @7
SPU2close @8
SPU2configure @9
SPU2test @10
SPU2freeze @12
SPU2setSettingsDir @13
SPU2setLogDir @14
SPU2write @15
SPU2read @16
SPU2async @17
SPU2readDMA4Mem @18
SPU2writeDMA4Mem @19
SPU2readDMA7Mem @20
SPU2writeDMA7Mem @21
SPU2interruptDMA4 @22
SPU2interruptDMA7 @23
SPU2irqCallback @24
SPU2setupRecording @25
SPU2ReadMemAddr @26
SPU2WriteMemAddr @27
SPU2setClockPtr @28
SPU2setDMABaseAddr @29
SPU2replay = s2r_replay @30
SPU2reset @31
SPU2ps1reset @32

View File

@ -1,359 +0,0 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "svnrev.h"
#include "afxresmw.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_CONFIG DIALOGEX 0, 0, 310, 260
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "SPU2-X Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x0
BEGIN
PUSHBUTTON "OK",IDOK,101,238,50,14,NOT WS_TABSTOP
PUSHBUTTON "Cancel",IDCANCEL,157,238,50,14,NOT WS_TABSTOP
GROUPBOX "Mixing Settings",IDC_STATIC,6,5,145,115
LTEXT "Interpolation:",IDC_STATIC,12,16,61,10,NOT WS_GROUP
COMBOBOX IDC_INTERPOLATE,14,26,129,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CHECKBOX "Disable Effects Processing",IDC_EFFECTS_DISABLE,14,47,126,10
LTEXT "(speedup!) Skips reverb effects processing, but won't sound as good in most games.",IDC_STATIC,26,59,110,36
CONTROL "Use the de-alias filter",IDC_DEALIASFILTER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,92,126,10
LTEXT "(overemphasizes the highs)",IDC_STATIC,26,104,114,12,NOT WS_GROUP
GROUPBOX "",IDC_STATIC,6,123,145,45
CHECKBOX "Enable Debug Options",IDC_DEBUG_ENABLE,14,135,118,10,NOT WS_TABSTOP
PUSHBUTTON "Configure...",IDC_OPEN_CONFIG_DEBUG,14,147,52,13
CONTROL 116,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZECONTROL,6,175,145,55,WS_EX_CLIENTEDGE
GROUPBOX "Output Settings",IDC_STATIC,157,5,145,225
LTEXT "Module:",IDC_STATIC,163,16,50,9,NOT WS_GROUP
COMBOBOX IDC_OUTPUT,165,26,129,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Configure...",IDC_OUTCONF,165,42,52,13
LTEXT "Volume:",IDC_STATIC,192,61,27,8,NOT WS_GROUP
CTEXT "100%",IDC_VOLUME_LABEL,226,61,58,9
CONTROL "",IDC_VOLUME_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,165,72,129,10
LTEXT "Latency:",IDC_STATIC,190,86,29,8,NOT WS_GROUP
CTEXT "100 ms (avg)",IDC_LATENCY_LABEL,227,86,58,9
CONTROL "Slider2",IDC_LATENCY_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,165,96,129,10
CONTROL "Synchronizing Mode:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,163,116,133,8
COMBOBOX IDC_SYNCHMODE,165,126,129,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Advanced...",IDC_OPEN_CONFIG_SOUNDTOUCH,165,142,52,13
LTEXT "Audio Expansion Mode:",IDC_SPEAKERS_TEXT,163,162,137,10,NOT WS_GROUP
COMBOBOX IDC_SPEAKERS,165,172,129,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "Use a Winamp DSP plugin",IDC_DSP_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,165,195,129,11
LTEXT "(currently requires manual configuration via the ini file)",IDC_STATIC,177,207,100,20
END
IDD_DEBUG DIALOGEX 0, 0, 303, 473
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "SPU2-X Debug"
FONT 9, "Lucida Console", 400, 0, 0x0
BEGIN
DEFPUSHBUTTON "Close",IDOK,246,451,50,14
END
IDD_DSOUND DIALOGEX 0, 0, 196, 218
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "DirectSound Output Module Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,45,196,50,14
PUSHBUTTON "Cancel",IDCANCEL,102,196,50,14
COMBOBOX IDC_DS_DEVICE,8,13,180,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "DirectSound Device:",IDC_STATIC,6,3,65,8
CONTROL "",IDC_BUFFERS_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,40,137,108,10
LTEXT "Increase the buffer count if you are experiencing loopy or stuttery audio even when games run at high FPS.",IDC_STATIC,13,157,169,27
CTEXT "8 (80 ms latency)",IDC_LATENCY_LABEL,46,123,95,11
LTEXT "The options above are useful for compatibility with older and/or buggy sound drivers ONLY, and should not be checked unless you experience sound problems (such as crackly audio or silence).",IDC_STATIC,18,68,172,38
CONTROL "Disable Global Focus",IDC_GLOBALFOCUS_DISABLE,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,6,38,140,10
CONTROL "Use a crappy alternate buffering mode",IDC_USE_HARDWARE,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,53,140,10
GROUPBOX "Output Buffers",IDC_STATIC,6,111,183,77
END
IDD_WAVEOUT DIALOGEX 0, 0, 170, 122
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "WaveOut Output Module Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,32,100,50,14
PUSHBUTTON "Cancel",IDCANCEL,88,100,50,14
COMBOBOX IDC_DS_DEVICE,6,13,159,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "WaveOut Device:",IDC_STATIC,4,3,60,8
LTEXT "Number of Buffers",IDC_STATIC,4,39,61,15
CONTROL "",IDC_BUFFERS_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,71,48,94,10
LTEXT "Use extra buffers if you are experiencing loopy or studdery audio even when games run at high FPS.",IDC_STATIC,8,66,151,27
CTEXT "8 (80 ms latency)",IDC_LATENCY_LABEL,70,37,95,11
END
IDD_CONFIG_SOUNDTOUCH DIALOGEX 0, 0, 206, 223
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Soundtouch Advanced Configuration - SPU2-X"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,50,201,50,14
PUSHBUTTON "Cancel",IDCANCEL,106,201,50,14
CTEXT "These are advanced configuration options for fine tuning time stretching behavior. Larger values are better for slowdown, while smaller values are better for speed-up (better than 60fps).\n\nAll options are in milliseconds (ms).",IDC_STATIC,5,5,196,52
CONTROL "",IDC_SEQLEN_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,50,98,105,10
CTEXT "Sequence Length",IDC_STATIC,72,86,64,9
CONTROL "",IDC_SEEKWIN_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,50,134,105,10
CTEXT "Seekwindow Size",IDC_STATIC,70,123,66,9
CONTROL "",IDC_OVERLAP_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,50,168,105,10
CTEXT "Overlap",IDC_STATIC,86,160,34,9
LTEXT "20",IDC_STATIC,50,110,9,8
LTEXT "100",IDC_STATIC,146,110,13,8
LTEXT "10",IDC_STATIC,50,147,9,8
LTEXT "30",IDC_STATIC,146,147,9,8
LTEXT "5",IDC_STATIC,52,182,8,8
LTEXT "15",IDC_STATIC,146,182,9,8
PUSHBUTTON "Reset Defaults",IDC_RESET_DEFAULTS,61,62,82,12
END
IDD_CONFIG_DEBUG DIALOGEX 0, 0, 292, 239
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "SPU2-X Debugging Options"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,93,217,50,14
PUSHBUTTON "Cancel",IDCANCEL,149,217,50,14
GROUPBOX "",IDC_STATIC,5,5,135,93
GROUPBOX "Logfile-only Logs",IDC_STATIC,151,5,136,53
GROUPBOX "Dumps (on close)",IDC_STATIC,151,60,135,54
CONTROL "Show In Console",IDC_MSGSHOW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,5,69,10
CHECKBOX "KeyOn/Off Events",IDC_MSGKEY,17,18,74,9,NOT WS_TABSTOP
CONTROL "Voice Stop Events",IDC_MSGVOICE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,31,75,9
CONTROL "DMA Operations",IDC_MSGDMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,44,68,9
CONTROL "AutoDMA Operations",IDC_MSGADMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,57,83,9
CONTROL "Buffer Over/Underruns",IDC_DBG_OVERRUNS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,70,97,9
CONTROL "ADPCM Cache Statistics",IDC_DBG_CACHE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,83,114,9
CHECKBOX "Dump Core and Voice State",IDC_DUMPCORE,159,74,104,10,NOT WS_TABSTOP
CHECKBOX "Dump Memory Contents",IDC_DUMPMEM,159,87,91,10,NOT WS_TABSTOP
CHECKBOX "Dump Register Data",IDC_DUMPREGS,159,100,80,10,NOT WS_TABSTOP
CHECKBOX "Log Register/DMA Actions",IDC_LOGREGS,159,18,101,10,WS_GROUP | NOT WS_TABSTOP
CHECKBOX "Log DMA Writes",IDC_LOGDMA,159,31,68,10,NOT WS_TABSTOP
CHECKBOX "Log Audio Output",IDC_LOGWAVE,159,44,71,10,NOT WS_TABSTOP
LTEXT "Note: This is a non-devel build. For performance reasons, some logging options are disabled; and only available in devel/debug builds.",IDC_MSG_PUBLIC_BUILD,9,187,174,30
GROUPBOX "Others",IDC_DEBUG_OTHERS,5,104,135,68
CONTROL "Show Core Activity",IDC_DEBUG_VISUAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,116,90,11
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_CONFIG, DIALOG
BEGIN
LEFTMARGIN, 6
RIGHTMARGIN, 314
VERTGUIDE, 218
VERTGUIDE, 282
BOTTOMMARGIN, 292
HORZGUIDE, 268
END
IDD_DEBUG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 296
TOPMARGIN, 7
BOTTOMMARGIN, 465
END
IDD_DSOUND, DIALOG
BEGIN
LEFTMARGIN, 4
RIGHTMARGIN, 191
TOPMARGIN, 3
BOTTOMMARGIN, 214
END
IDD_WAVEOUT, DIALOG
BEGIN
LEFTMARGIN, 4
RIGHTMARGIN, 165
TOPMARGIN, 3
BOTTOMMARGIN, 118
END
IDD_CONFIG_SOUNDTOUCH, DIALOG
BEGIN
LEFTMARGIN, 5
RIGHTMARGIN, 201
TOPMARGIN, 5
BOTTOMMARGIN, 218
END
IDD_CONFIG_DEBUG, DIALOG
BEGIN
LEFTMARGIN, 5
RIGHTMARGIN, 287
TOPMARGIN, 5
BOTTOMMARGIN, 234
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//
IDB_SPU2X_SMALL BITMAP "..\\..\\spu2-x-sm.bmp"
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,0,0,4851
PRODUCTVERSION 2,0,0,4851
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "SPU2 Plugin for PS2 Emulators"
VALUE "CompanyName", "PCSX2 Dev Team"
VALUE "FileDescription", "SPU2-X Plugin (git build)"
VALUE "FileVersion", "2.0.GIT"
VALUE "InternalName", "SPU2-X"
VALUE "LegalCopyright", "Copyright (C) 2011"
VALUE "OriginalFilename", "SPU2-X-2.0.dll"
VALUE "ProductName", "SPU2-X"
VALUE "ProductVersion", "2.0.GIT"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// English (United Kingdom) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_PORTAUDIO DIALOGEX 0, 0, 316, 166
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Portaudio Output Module Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,105,144,50,14
PUSHBUTTON "Cancel",IDCANCEL,161,144,50,14
COMBOBOX IDC_PA_HOSTAPI,7,17,95,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Host API:",IDC_STATIC,7,7,32,8
COMBOBOX IDC_PA_DEVICE,108,17,201,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Device Name:",IDC_STATIC,107,7,45,8
CONTROL "",IDC_LATENCY,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,96,93,155,10
LTEXT "NOTE: Depending on the hardware and drivers, the suggested manual latency might not be used, and portaudio will choose the closest possible value.",IDC_STATIC,12,111,286,19
CTEXT "20ms",IDC_LATENCY_LABEL,264,93,35,11
GROUPBOX "Output Latency",IDC_STATIC,7,57,302,79
CONTROL "Use smallest possible (may cause issues if the actual value is too small)",IDC_MINIMIZE,
"Button",BS_AUTORADIOBUTTON | WS_GROUP,12,75,258,10
CONTROL "Use this latency:",IDC_MANUAL,"Button",BS_AUTORADIOBUTTON,12,93,69,10
CONTROL "WASAPI Exclusive Mode",IDC_EXCLUSIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,39,93,10
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_PORTAUDIO, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 309
TOPMARGIN, 7
BOTTOMMARGIN, 159
END
END
#endif // APSTUDIO_INVOKED
#endif // English (United Kingdom) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Spanish (Spain, International Sort) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESN)
LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_MODERN
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""svnrev.h""\r\n"
"#include ""afxresmw.h""\0"
END
3 TEXTINCLUDE
BEGIN
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // Spanish (Spain, International Sort) resources
/////////////////////////////////////////////////////////////////////////////

View File

@ -1,177 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="DebugStrict|Win32">
<Configuration>DebugStrict</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="DebugStrict|x64">
<Configuration>DebugStrict</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Devel|Win32">
<Configuration>Devel</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Devel|x64">
<Configuration>Devel</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="..\..\..\..\common\vsprops\plugin_svnroot.props" />
<Import Project="..\..\..\..\common\vsprops\BaseProperties.props" />
<Import Project="..\..\..\..\common\vsprops\3rdpartyDeps.props" />
<Import Project="..\..\..\..\common\vsprops\pthreads.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\..\..\common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\..\..\common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\..\..\common\vsprops\CodeGen_Release.props" />
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\..\..\common\vsprops\IncrementalLinking.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions Condition="'$(Configuration)'=='Debug'">DEBUG_FAST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\portaudio\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<ExceptionHandling>Async</ExceptionHandling>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>Global.h</PrecompiledHeaderFile>
<CompileAs>Default</CompileAs>
</ClCompile>
<Link>
<AdditionalDependencies>rpcrt4.lib;winmm.lib;dsound.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>.\Spu2-X.def</ModuleDefinitionFile>
<TargetMachine Condition="'$(Platform)'=='Win32'">MachineX86</TargetMachine>
<TargetMachine Condition="'$(Platform)'=='x64'">MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\Config.h" />
<ClInclude Include="..\Global.h" />
<ClInclude Include="..\spu2replay.h" />
<ClInclude Include="..\Lowpass.h" />
<ClInclude Include="..\SndOut.h" />
<ClInclude Include="..\Linux\Alsa.h" />
<ClInclude Include="..\spdif.h" />
<ClInclude Include="..\defs.h" />
<ClInclude Include="..\Dma.h" />
<ClInclude Include="..\regs.h" />
<ClInclude Include="..\Mixer.h" />
<ClInclude Include="dsp.h" />
<ClInclude Include="..\Linux\Config.h" />
<ClInclude Include="..\Linux\Dialogs.h" />
<ClInclude Include="Dialogs.h" />
<ClInclude Include="WinConfig.h" />
<ClInclude Include="..\PS2E-spu2.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\DplIIdecoder.cpp" />
<ClCompile Include="..\PrecompiledHeader.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\debug.cpp" />
<ClCompile Include="..\RegLog.cpp" />
<ClCompile Include="..\spu2replay.cpp" />
<ClCompile Include="..\wavedump_wav.cpp" />
<ClCompile Include="..\Lowpass.cpp" />
<ClCompile Include="..\SndOut.cpp" />
<ClCompile Include="..\Timestretcher.cpp" />
<ClCompile Include="SndOut_DSound.cpp" />
<ClCompile Include="SndOut_waveOut.cpp" />
<ClCompile Include="SndOut_XAudio2.cpp" />
<ClCompile Include="..\Linux\Alsa.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\SndOut_Portaudio.cpp" />
<ClCompile Include="..\dma.cpp" />
<ClCompile Include="..\RegTable.cpp" />
<ClCompile Include="..\spu2freeze.cpp" />
<ClCompile Include="..\spu2sys.cpp" />
<ClCompile Include="..\ADSR.cpp" />
<ClCompile Include="..\Mixer.cpp" />
<ClCompile Include="..\ReadInput.cpp" />
<ClCompile Include="..\Reverb.cpp" />
<ClCompile Include="dsp.cpp" />
<ClCompile Include="..\Linux\Config.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\Linux\Dialogs.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="CfgHelpers.cpp" />
<ClCompile Include="Config.cpp" />
<ClCompile Include="ConfigDebug.cpp" />
<ClCompile Include="ConfigSoundtouch.cpp" />
<ClCompile Include="RealtimeDebugger.cpp" />
<ClCompile Include="UIHelpers.cpp" />
<ClCompile Include="..\PS2E-spu2.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\LGPL.txt" />
<None Include="..\..\License.txt" />
<None Include="..\..\spu2-x-sm.bmp" />
<None Include="Spu2-X.def" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Spu2-X.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\3rdparty\portaudio\build\msvc\portaudio.vcxproj">
<Project>{0a18a071-125e-442f-aff7-a3f68abecf99}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\..\..\..\3rdparty\pthreads4w\build\pthreads4w.vcxproj">
<Project>{0fae817d-9a32-4830-857e-81da57246e16}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\..\..\..\3rdparty\soundtouch\SoundTouch.vcxproj">
<Project>{e9b51944-7e6d-4bcd-83f2-7bbd5a46182d}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\..\..\..\3rdparty\wxwidgets3.0\build\msw\wx30_base.vcxproj">
<Project>{3fcc50c2-81e9-5db2-b8d8-2129427568b1}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\common\build\Utilities\utilities.vcxproj">
<Project>{4639972e-424e-4e13-8b07-ca403c481346}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

View File

@ -1,233 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{21596259-72f4-41c0-b499-40839e39f043}</UniqueIdentifier>
<Extensions>h;hpp;cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
</Filter>
<Filter Include="Source Files\debug">
<UniqueIdentifier>{30e5b8dd-2015-4c3d-a663-992fb42627b5}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Sound Output">
<UniqueIdentifier>{ed4df93e-4e4b-4675-a181-c5084146df7c}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Sound Output\Windows">
<UniqueIdentifier>{1cb77247-dec9-4a0a-867f-7353b14decac}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Sound Output\Linux">
<UniqueIdentifier>{f87cf8e1-d654-4214-b7f4-6fb697f3941a}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Sound Output\Crossplatform">
<UniqueIdentifier>{10ccccc1-642a-42ec-900c-801f707bd776}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\decoder">
<UniqueIdentifier>{03be4765-f627-4c0a-9d40-f3c0f86f1e57}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\decoder\ac3%28a/52%29">
<UniqueIdentifier>{ea7e8889-2015-40b9-ac77-b4a3a58c41af}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\SPU2">
<UniqueIdentifier>{63ac2d88-b5c3-41a3-bd2c-a04c80acd35f}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\SPU2\Mixer">
<UniqueIdentifier>{825046cd-874f-45f4-8622-14c146a97b46}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Winamp DSP">
<UniqueIdentifier>{3924e038-9ec9-4f1c-89b9-6d03c46566ac}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\GUI">
<UniqueIdentifier>{efaf786c-f09d-49f7-b5f3-8bb7078e9c44}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\GUI\Linux">
<UniqueIdentifier>{00c53f28-fde8-4f60-88d2-d223584f1db5}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\GUI\Linux\Include">
<UniqueIdentifier>{95111121-7e1f-4624-8765-a17e8f13827f}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\GUI\Windows">
<UniqueIdentifier>{70e9653e-fba5-4c6e-ad9b-185006096d49}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\PluginInterface">
<UniqueIdentifier>{6fcf6c91-7afe-4ade-bb30-79d63901d590}</UniqueIdentifier>
</Filter>
<Filter Include="Documents">
<UniqueIdentifier>{381a6e5e-bdd5-48b0-81f8-e2775eff9585}</UniqueIdentifier>
</Filter>
<Filter Include="Resources">
<UniqueIdentifier>{d26e57df-a97e-4ba5-801a-c0c52b5d061f}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Config.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\Global.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\spu2replay.h">
<Filter>Source Files\debug</Filter>
</ClInclude>
<ClInclude Include="..\Lowpass.h">
<Filter>Source Files\Sound Output</Filter>
</ClInclude>
<ClInclude Include="..\SndOut.h">
<Filter>Source Files\Sound Output</Filter>
</ClInclude>
<ClInclude Include="..\Linux\Alsa.h">
<Filter>Source Files\Sound Output\Linux</Filter>
</ClInclude>
<ClInclude Include="..\spdif.h">
<Filter>Source Files\decoder</Filter>
</ClInclude>
<ClInclude Include="..\defs.h">
<Filter>Source Files\SPU2</Filter>
</ClInclude>
<ClInclude Include="..\Dma.h">
<Filter>Source Files\SPU2</Filter>
</ClInclude>
<ClInclude Include="..\regs.h">
<Filter>Source Files\SPU2</Filter>
</ClInclude>
<ClInclude Include="..\Mixer.h">
<Filter>Source Files\SPU2\Mixer</Filter>
</ClInclude>
<ClInclude Include="dsp.h">
<Filter>Source Files\Winamp DSP</Filter>
</ClInclude>
<ClInclude Include="..\Linux\Config.h">
<Filter>Source Files\GUI\Linux\Include</Filter>
</ClInclude>
<ClInclude Include="..\Linux\Dialogs.h">
<Filter>Source Files\GUI\Linux\Include</Filter>
</ClInclude>
<ClInclude Include="Dialogs.h">
<Filter>Source Files\GUI\Windows</Filter>
</ClInclude>
<ClInclude Include="WinConfig.h">
<Filter>Source Files\GUI\Windows</Filter>
</ClInclude>
<ClInclude Include="..\PS2E-spu2.h">
<Filter>Source Files\PluginInterface</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Resources</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\PrecompiledHeader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\debug.cpp">
<Filter>Source Files\debug</Filter>
</ClCompile>
<ClCompile Include="..\RegLog.cpp">
<Filter>Source Files\debug</Filter>
</ClCompile>
<ClCompile Include="..\spu2replay.cpp">
<Filter>Source Files\debug</Filter>
</ClCompile>
<ClCompile Include="..\wavedump_wav.cpp">
<Filter>Source Files\debug</Filter>
</ClCompile>
<ClCompile Include="..\Lowpass.cpp">
<Filter>Source Files\Sound Output</Filter>
</ClCompile>
<ClCompile Include="..\SndOut.cpp">
<Filter>Source Files\Sound Output</Filter>
</ClCompile>
<ClCompile Include="..\Timestretcher.cpp">
<Filter>Source Files\Sound Output</Filter>
</ClCompile>
<ClCompile Include="SndOut_DSound.cpp">
<Filter>Source Files\Sound Output\Windows</Filter>
</ClCompile>
<ClCompile Include="SndOut_waveOut.cpp">
<Filter>Source Files\Sound Output\Windows</Filter>
</ClCompile>
<ClCompile Include="..\Linux\Alsa.cpp">
<Filter>Source Files\Sound Output\Linux</Filter>
</ClCompile>
<ClCompile Include="..\SndOut_Portaudio.cpp">
<Filter>Source Files\Sound Output\Crossplatform</Filter>
</ClCompile>
<ClCompile Include="..\dma.cpp">
<Filter>Source Files\SPU2</Filter>
</ClCompile>
<ClCompile Include="..\RegTable.cpp">
<Filter>Source Files\SPU2</Filter>
</ClCompile>
<ClCompile Include="..\spu2freeze.cpp">
<Filter>Source Files\SPU2</Filter>
</ClCompile>
<ClCompile Include="..\spu2sys.cpp">
<Filter>Source Files\SPU2</Filter>
</ClCompile>
<ClCompile Include="..\ADSR.cpp">
<Filter>Source Files\SPU2\Mixer</Filter>
</ClCompile>
<ClCompile Include="..\Mixer.cpp">
<Filter>Source Files\SPU2\Mixer</Filter>
</ClCompile>
<ClCompile Include="..\ReadInput.cpp">
<Filter>Source Files\SPU2\Mixer</Filter>
</ClCompile>
<ClCompile Include="..\Reverb.cpp">
<Filter>Source Files\SPU2\Mixer</Filter>
</ClCompile>
<ClCompile Include="dsp.cpp">
<Filter>Source Files\Winamp DSP</Filter>
</ClCompile>
<ClCompile Include="..\Linux\Config.cpp">
<Filter>Source Files\GUI\Linux</Filter>
</ClCompile>
<ClCompile Include="..\Linux\Dialogs.cpp">
<Filter>Source Files\GUI\Linux</Filter>
</ClCompile>
<ClCompile Include="CfgHelpers.cpp">
<Filter>Source Files\GUI\Windows</Filter>
</ClCompile>
<ClCompile Include="Config.cpp">
<Filter>Source Files\GUI\Windows</Filter>
</ClCompile>
<ClCompile Include="ConfigDebug.cpp">
<Filter>Source Files\GUI\Windows</Filter>
</ClCompile>
<ClCompile Include="ConfigSoundtouch.cpp">
<Filter>Source Files\GUI\Windows</Filter>
</ClCompile>
<ClCompile Include="RealtimeDebugger.cpp">
<Filter>Source Files\GUI\Windows</Filter>
</ClCompile>
<ClCompile Include="UIHelpers.cpp">
<Filter>Source Files\GUI\Windows</Filter>
</ClCompile>
<ClCompile Include="..\PS2E-spu2.cpp">
<Filter>Source Files\PluginInterface</Filter>
</ClCompile>
<ClCompile Include="..\DplIIdecoder.cpp">
<Filter>Source Files\Sound Output</Filter>
</ClCompile>
<ClCompile Include="SndOut_XAudio2.cpp">
<Filter>Source Files\Sound Output\Windows</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\LGPL.txt">
<Filter>Documents</Filter>
</None>
<None Include="..\..\License.txt">
<Filter>Documents</Filter>
</None>
<None Include="..\..\spu2-x-sm.bmp">
<Filter>Resources</Filter>
</None>
<None Include="Spu2-X.def">
<Filter>Resources</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Spu2-X.rc">
<Filter>Resources</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -1,79 +0,0 @@
/* 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 "Dialogs.h"
int SendDialogMsg(HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam)
{
return SendMessage(GetDlgItem(hwnd, dlgId), code, wParam, lParam);
}
__forceinline void Verifyc(HRESULT hr, const char *fn)
{
if (FAILED(hr)) {
assert(0);
throw std::runtime_error("DirectSound returned an error from %s");
}
}
void AssignSliderValue(HWND idcwnd, HWND hwndDisplay, int value)
{
value = std::min(std::max(value, 0), 512);
SendMessage(idcwnd, TBM_SETPOS, TRUE, value);
wchar_t tbox[32];
swprintf_s(tbox, L"%d", value);
SetWindowText(hwndDisplay, tbox);
}
void AssignSliderValue(HWND hWnd, int idc, int editbox, int value)
{
AssignSliderValue(GetDlgItem(hWnd, idc), GetDlgItem(hWnd, editbox), value);
}
// Generic slider/scroller message handler. This is succient so long as you
// don't need some kind of secondary event handling functionality, such as
// updating a custom label.
BOOL DoHandleScrollMessage(HWND hwndDisplay, WPARAM wParam, LPARAM lParam)
{
int wmId = LOWORD(wParam);
int wmEvent = HIWORD(wParam);
switch (wmId) {
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
wmEvent = (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
case TB_THUMBTRACK:
AssignSliderValue((HWND)lParam, hwndDisplay, wmEvent);
break;
default:
return FALSE;
}
return TRUE;
}
int GetSliderValue(HWND hWnd, int idc)
{
int retval = (int)SendMessage(GetDlgItem(hWnd, idc), TBM_GETPOS, 0, 0);
return GetClamped(retval, 0, 512);
}

View File

@ -1,86 +0,0 @@
/* 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
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif
#include <windows.h>
#include <mmsystem.h>
#include <commctrl.h>
#include <initguid.h>
#include <tchar.h>
#include <VersionHelpers.h>
#include "resource.h"
extern HINSTANCE hInstance;
#define SET_CHECK(idc, value) SendMessage(GetDlgItem(hWnd, idc), BM_SETCHECK, ((value) == 0) ? BST_UNCHECKED : BST_CHECKED, 0)
#define HANDLE_CHECK(idc, hvar) \
case idc: \
(hvar) = !(hvar); \
SendMessage(GetDlgItem(hWnd, idc), BM_SETCHECK, (hvar) ? BST_CHECKED : BST_UNCHECKED, 0); \
break
#define HANDLE_CHECKNB(idc, hvar) \
case idc: \
(hvar) = !(hvar); \
SendMessage(GetDlgItem(hWnd, idc), BM_SETCHECK, (hvar) ? BST_CHECKED : BST_UNCHECKED, 0)
#define ENABLE_CONTROL(idc, value) EnableWindow(GetDlgItem(hWnd, idc), value)
#define INIT_SLIDER(idc, minrange, maxrange, tickfreq, pagesize, linesize) \
SendMessage(GetDlgItem(hWnd, idc), TBM_SETRANGEMIN, FALSE, minrange); \
SendMessage(GetDlgItem(hWnd, idc), TBM_SETRANGEMAX, FALSE, maxrange); \
SendMessage(GetDlgItem(hWnd, idc), TBM_SETTICFREQ, tickfreq, 0); \
SendMessage(GetDlgItem(hWnd, idc), TBM_SETPAGESIZE, 0, pagesize); \
SendMessage(GetDlgItem(hWnd, idc), TBM_SETLINESIZE, 0, linesize)
#define HANDLE_SCROLL_MESSAGE(idc, idcDisplay) \
if ((HWND)lParam == GetDlgItem(hWnd, idc)) \
return DoHandleScrollMessage(GetDlgItem(hWnd, idcDisplay), wParam, lParam)
// *** BEGIN DRIVER-SPECIFIC CONFIGURATION ***
// -------------------------------------------
struct CONFIG_XAUDIO2
{
wxString Device;
s8 NumBuffers;
CONFIG_XAUDIO2()
: Device()
, NumBuffers(2)
{
}
};
struct CONFIG_WAVEOUT
{
wxString Device;
s8 NumBuffers;
CONFIG_WAVEOUT()
: Device()
, NumBuffers(4)
{
}
};
extern CONFIG_WAVEOUT Config_WaveOut;
extern CONFIG_XAUDIO2 Config_XAudio2;

View File

@ -1,179 +0,0 @@
//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"
#define _WIN32_WINNT 0x0600
#include <windows.h>
#include <mmsystem.h>
extern "C" {
#include "dsp.h"
typedef winampDSPHeader *(*pWinampDSPGetHeader2)();
}
HMODULE hLib = NULL;
pWinampDSPGetHeader2 pGetHeader = NULL;
winampDSPHeader *pHeader = NULL;
winampDSPModule *pModule = NULL;
HWND hTemp;
#define USE_A_THREAD
#ifdef USE_A_THREAD
HANDLE hUpdateThread;
DWORD UpdateThreadId;
bool running;
DWORD WINAPI DspUpdateThread(PVOID param);
#endif
s32 DspLoadLibrary(wchar_t *fileName, int modNum)
#ifdef USE_A_THREAD
{
if (!dspPluginEnabled)
return -1;
running = true;
hUpdateThread = CreateThread(NULL, 0, DspUpdateThread, NULL, 0, &UpdateThreadId);
return (hUpdateThread == INVALID_HANDLE_VALUE);
}
s32 DspLoadLibrary2(wchar_t *fileName, int modNum)
#endif
{
if (!dspPluginEnabled)
return -1;
hLib = LoadLibraryW(fileName);
if (!hLib) {
return 1;
}
pGetHeader = (pWinampDSPGetHeader2)GetProcAddress(hLib, "winampDSPGetHeader2");
if (!pGetHeader) {
FreeLibrary(hLib);
hLib = NULL;
return 1;
}
pHeader = pGetHeader();
pModule = pHeader->getModule(modNum);
if (!pModule) {
pGetHeader = NULL;
pHeader = NULL;
FreeLibrary(hLib);
hLib = NULL;
return -1;
}
pModule->hDllInstance = hLib;
pModule->hwndParent = 0;
pModule->Init(pModule);
return 0;
}
void DspCloseLibrary()
#ifdef USE_A_THREAD
{
if (!dspPluginEnabled)
return;
PostThreadMessage(UpdateThreadId, WM_QUIT, 0, 0);
running = false;
if (WaitForSingleObject(hUpdateThread, 1000) == WAIT_TIMEOUT) {
ConLog("SPU2-X: WARNING: DSP Thread did not close itself in time. Assuming hung. Terminating.\n");
TerminateThread(hUpdateThread, 1);
}
}
void DspCloseLibrary2()
#endif
{
if (!dspPluginEnabled)
return;
if (hLib) {
pModule->Quit(pModule);
FreeLibrary(hLib);
}
pModule = NULL;
pHeader = NULL;
pGetHeader = NULL;
hLib = NULL;
}
int DspProcess(s16 *buffer, int samples)
{
if (!dspPluginEnabled)
return samples;
if (hLib) {
return pModule->ModifySamples(pModule, buffer, samples, 16, 2, SampleRate);
}
return samples;
}
void DspUpdate()
#ifdef USE_A_THREAD
{
}
DWORD WINAPI DspUpdateThread(PVOID param)
{
if (!dspPluginEnabled)
return -1;
if (DspLoadLibrary2(dspPlugin, dspPluginModule))
return -1;
MSG msg;
while (running) {
GetMessage(&msg, 0, 0, 0);
if ((msg.hwnd == NULL) && (msg.message == WM_QUIT)) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DspCloseLibrary2();
return 0;
}
#else
{
if (!dspPluginEnabled)
return;
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#endif

View File

@ -1,60 +0,0 @@
//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
//
// DSP plugin interface
// notes:
// any window that remains in foreground should optimally pass unused
// keystrokes to the parent (winamp's) window, so that the user
// can still control it. As for storing configuration,
// Configuration data should be stored in <dll directory>\plugin.ini
// (look at the vis plugin for configuration code)
#pragma once
typedef struct winampDSPModule
{
char *description; // description
HWND hwndParent; // parent window (filled in by calling app)
HINSTANCE hDllInstance; // instance handle to this DLL (filled in by calling app)
void (*Config)(struct winampDSPModule *this_mod); // configuration dialog (if needed)
int (*Init)(struct winampDSPModule *this_mod); // 0 on success, creates window, etc (if needed)
// modify waveform samples: returns number of samples to actually write
// (typically numsamples, but no more than twice numsamples, and no less than half numsamples)
// numsamples should always be at least 128. should, but I'm not sure
int (*ModifySamples)(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate);
void (*Quit)(struct winampDSPModule *this_mod); // called when unloading
void *userData; // user data, optional
} winampDSPModule;
typedef struct
{
int version; // DSP_HDRVER
char *description; // description of library
winampDSPModule *(*getModule)(int); // module retrieval function
} winampDSPHeader;
// exported symbols
typedef winampDSPHeader *(*winampDSPGetHeaderType)();
// header version: 0x20 == 0.20 == winamp 2.0
#define DSP_HDRVER 0x20

View File

@ -1,73 +0,0 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Spu2-X.rc
//
#define IDD_CONFIG 9
#define IDD_DEBUG 105
#define IDD_DSOUND 106
#define IDD_WAVEOUT 109
#define IDB_SPU2X_SMALL 116
#define IDD_CONFIG_SOUNDTOUCH 117
#define IDD_CONFIG_DEBUG 118
#define IDD_PORTAUDIO 119
#define IDC_EFFECTS_DISABLE 1001
#define IDC_DUMPREGS 1003
#define IDC_DUMPMEM 1004
#define IDC_DUMPCORE 1005
#define IDC_LOGWAVE 1006
#define IDC_LOGDMA 1007
#define IDC_LOGREGS 1008
#define IDC_DEBUG 1009
#define IDC_DEBUG_ENABLE 1010
#define IDC_INTERPOLATE 1011
#define IDC_DEALIASFILTER 1012
#define IDC_OUTPUT 1013
#define IDC_BUFFERS_SLIDER 1014
#define IDC_SPEAKERS 1015
#define IDC_SPEAKERS_TEXT 1016
#define IDC_MSGKEY 1020
#define IDC_MSGDMA 1021
#define IDC_MSGADMA 1022
#define IDC_MSGVOICE 1023
#define IDC_MSGSHOW 1024
#define IDC_OUTCONF 1028
#define IDC_DSP_ENABLE 1029
#define IDC_DS_DEVICE 1032
#define IDC_PA_DEVICE 1033
#define IDC_DBG_OVERRUNS 1038
#define IDC_DBG_CACHE 1039
#define IDC_LATENCY_SLIDER 1040
#define IDC_LATENCY_LABEL 1041
#define ICD_LR_CENTER_SLIDER 1042
#define IDC_SEQLEN_SLIDER 1043
#define IDC_SEEKWIN_SLIDER 1044
#define IDC_OVERLAP_SLIDER 1045
#define IDC_MSG_PUBLIC_BUILD 1048
#define IDC_RESET_DEFAULTS 1057
#define IDC_OPEN_CONFIG_SOUNDTOUCH 1058
#define IDC_OPEN_CONFIG_DEBUG 1059
#define IDC_GLOBALFOCUS_DISABLE 1060
#define IDC_GLOBALFOCUS_DISABLE2 1061
#define IDC_USE_HARDWARE 1062
#define IDC_COMBO1 1063
#define IDC_SYNCHMODE 1064
#define IDC_DEBUG_OTHERS 1065
#define IDC_DEBUG_VISUAL 1066
#define IDC_VOLUME_LABEL 1067
#define IDC_VOLUME_SLIDER 1068
#define IDC_MINIMIZE 1069
#define IDC_MANUAL 1070
#define IDC_PA_HOSTAPI 1071
#define IDC_LATENCY 1072
#define IDC_EXCLUSIVE 1073
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 120
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1074
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -1,589 +0,0 @@
/* 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 "Mixer.h"
#include "SndOut.h"
// --------------------------------------------------------------------------------------
// SPU2 Memory Indexers
// --------------------------------------------------------------------------------------
#define spu2Rs16(mmem) (*(s16 *)((s8 *)spu2regs + ((mmem)&0x1fff)))
#define spu2Ru16(mmem) (*(u16 *)((s8 *)spu2regs + ((mmem)&0x1fff)))
extern s16 *GetMemPtr(u32 addr);
extern s16 spu2M_Read(u32 addr);
extern void spu2M_Write(u32 addr, s16 value);
extern void spu2M_Write(u32 addr, u16 value);
struct V_VolumeLR
{
static V_VolumeLR Max;
s32 Left;
s32 Right;
V_VolumeLR() = default;
V_VolumeLR(s32 both)
: Left(both)
, Right(both)
{
}
void DebugDump(FILE *dump, const char *title);
};
struct V_VolumeSlide
{
// Holds the "original" value of the volume for this voice, prior to slides.
// (ie, the volume as written to the register)
s16 Reg_VOL;
s32 Value;
s8 Increment;
s8 Mode;
public:
V_VolumeSlide() = default;
V_VolumeSlide(s16 regval, s32 fullvol)
: Reg_VOL(regval)
, Value(fullvol)
, Increment(0)
, Mode(0)
{
}
void Update();
void RegSet(u16 src); // used to set the volume from a register source (16 bit signed)
void DebugDump(FILE *dump, const char *title, const char *nameLR);
};
struct V_VolumeSlideLR
{
static V_VolumeSlideLR Max;
V_VolumeSlide Left;
V_VolumeSlide Right;
public:
V_VolumeSlideLR() = default;
V_VolumeSlideLR(s16 regval, s32 bothval)
: Left(regval, bothval)
, Right(regval, bothval)
{
}
void Update()
{
Left.Update();
Right.Update();
}
void DebugDump(FILE *dump, const char *title);
};
struct V_ADSR
{
union
{
u32 reg32;
struct
{
u16 regADSR1;
u16 regADSR2;
};
struct
{
u32 SustainLevel : 4,
DecayRate : 4,
AttackRate : 7,
AttackMode : 1, // 0 for linear (+lin), 1 for pseudo exponential (+exp)
ReleaseRate : 5,
ReleaseMode : 1, // 0 for linear (-lin), 1 for exponential (-exp)
SustainRate : 7,
SustainMode : 3; // 0 = +lin, 1 = -lin, 2 = +exp, 3 = -exp
};
};
s32 Value; // Ranges from 0 to 0x7fffffff (signed values are clamped to 0) [Reg_ENVX]
u8 Phase; // monitors current phase of ADSR envelope
bool Releasing; // Ready To Release, triggered by Voice.Stop();
public:
bool Calculate();
};
struct V_Voice
{
u32 PlayCycle; // SPU2 cycle where the Playing started
V_VolumeSlideLR Volume;
// Envelope
V_ADSR ADSR;
// Pitch (also Reg_PITCH)
u16 Pitch;
// Loop Start address (also Reg_LSAH/L)
u32 LoopStartA;
// Sound Start address (also Reg_SSAH/L)
u32 StartA;
// Next Read Data address (also Reg_NAXH/L)
u32 NextA;
// Voice Decoding State
s32 Prev1;
s32 Prev2;
// Pitch Modulated by previous voice
bool Modulated;
// Source (Wave/Noise)
bool Noise;
s8 LoopMode;
s8 LoopFlags;
// Sample pointer (19:12 bit fixed point)
s32 SP;
// Sample pointer for Cubic Interpolation
// Cubic interpolation mixes a sample behind Linear, so that it
// can have sample data to either side of the end points from which
// to extrapolate. This SP represents that late sample position.
s32 SPc;
// Previous sample values - used for interpolation
// Inverted order of these members to match the access order in the
// code (might improve cache hits).
s32 PV4;
s32 PV3;
s32 PV2;
s32 PV1;
// Last outputted audio value, used for voice modulation.
s32 OutX;
s32 NextCrest; // temp value for Crest calculation
// SBuffer now points directly to an ADPCM cache entry.
s16 *SBuffer;
// sample position within the current decoded packet.
s32 SCurrent;
// it takes a few ticks for voices to start on the real SPU2?
void QueueStart();
bool Start();
void Stop();
};
// ** Begin Debug-only variables section **
// Separated from the V_Voice struct to improve cache performance of
// the Public Release build.
struct V_VoiceDebug
{
s8 FirstBlock;
s32 SampleData;
s32 PeakX;
s32 displayPeak;
s32 lastSetStartA;
};
struct V_CoreDebug
{
V_VoiceDebug Voices[24];
// Last Transfer Size
u32 lastsize;
// draw adma waveform in the visual debugger
s32 admaWaveformL[0x100];
s32 admaWaveformR[0x100];
// Enabled when a dma write starts, disabled when the visual debugger showed it once
s32 dmaFlag;
};
// Debug tracking information - 24 voices and 2 cores.
extern V_CoreDebug DebugCores[2];
struct V_Reverb
{
s16 IN_COEF_L;
s16 IN_COEF_R;
u32 APF1_SIZE;
u32 APF2_SIZE;
s16 APF1_VOL;
s16 APF2_VOL;
u32 SAME_L_SRC;
u32 SAME_R_SRC;
u32 DIFF_L_SRC;
u32 DIFF_R_SRC;
u32 SAME_L_DST;
u32 SAME_R_DST;
u32 DIFF_L_DST;
u32 DIFF_R_DST;
s16 IIR_VOL;
s16 WALL_VOL;
u32 COMB1_L_SRC;
u32 COMB1_R_SRC;
u32 COMB2_L_SRC;
u32 COMB2_R_SRC;
u32 COMB3_L_SRC;
u32 COMB3_R_SRC;
u32 COMB4_L_SRC;
u32 COMB4_R_SRC;
s16 COMB1_VOL;
s16 COMB2_VOL;
s16 COMB3_VOL;
s16 COMB4_VOL;
u32 APF1_L_DST;
u32 APF1_R_DST;
u32 APF2_L_DST;
u32 APF2_R_DST;
};
struct V_ReverbBuffers
{
s32 SAME_L_SRC;
s32 SAME_R_SRC;
s32 DIFF_R_SRC;
s32 DIFF_L_SRC;
s32 SAME_L_DST;
s32 SAME_R_DST;
s32 DIFF_L_DST;
s32 DIFF_R_DST;
s32 COMB1_L_SRC;
s32 COMB1_R_SRC;
s32 COMB2_L_SRC;
s32 COMB2_R_SRC;
s32 COMB3_L_SRC;
s32 COMB3_R_SRC;
s32 COMB4_L_SRC;
s32 COMB4_R_SRC;
s32 APF1_L_DST;
s32 APF1_R_DST;
s32 APF2_L_DST;
s32 APF2_R_DST;
s32 SAME_L_PRV;
s32 SAME_R_PRV;
s32 DIFF_L_PRV;
s32 DIFF_R_PRV;
s32 APF1_L_SRC;
s32 APF1_R_SRC;
s32 APF2_L_SRC;
s32 APF2_R_SRC;
bool NeedsUpdated;
};
struct V_SPDIF
{
u16 Out;
u16 Info;
u16 Unknown1;
u16 Mode;
u16 Media;
u16 Unknown2;
u16 Protection;
};
struct V_CoreRegs
{
u32 PMON;
u32 NON;
u32 VMIXL;
u32 VMIXR;
u32 VMIXEL;
u32 VMIXER;
u32 ENDX;
u16 MMIX;
u16 STATX;
u16 ATTR;
u16 _1AC;
};
struct V_VoiceGates
{
s16 DryL; // 'AND Gate' for Direct Output to Left Channel
s16 DryR; // 'AND Gate' for Direct Output for Right Channel
s16 WetL; // 'AND Gate' for Effect Output for Left Channel
s16 WetR; // 'AND Gate' for Effect Output for Right Channel
};
struct V_CoreGates
{
union
{
u128 v128;
struct
{
s16 InpL; // Sound Data Input to Direct Output (Left)
s16 InpR; // Sound Data Input to Direct Output (Right)
s16 SndL; // Voice Data to Direct Output (Left)
s16 SndR; // Voice Data to Direct Output (Right)
s16 ExtL; // External Input to Direct Output (Left)
s16 ExtR; // External Input to Direct Output (Right)
};
};
};
struct VoiceMixSet
{
static const VoiceMixSet Empty;
StereoOut32 Dry, Wet;
VoiceMixSet() {}
VoiceMixSet(const StereoOut32 &dry, const StereoOut32 &wet)
: Dry(dry)
, Wet(wet)
{
}
};
struct V_Core
{
static const uint NumVoices = 24;
int Index; // Core index identifier.
// Voice Gates -- These are SSE-related values, and must always be
// first to ensure 16 byte alignment
V_VoiceGates VoiceGates[NumVoices];
V_CoreGates DryGate;
V_CoreGates WetGate;
V_VolumeSlideLR MasterVol; // Master Volume
V_VolumeLR ExtVol; // Volume for External Data Input
V_VolumeLR InpVol; // Volume for Sound Data Input
V_VolumeLR FxVol; // Volume for Output from Effects
V_Voice Voices[NumVoices];
u32 IRQA; // Interrupt Address
u32 TSA; // DMA Transfer Start Address
bool IRQEnable; // Interrupt Enable
bool FxEnable; // Effect Enable
bool Mute; // Mute
bool AdmaInProgress;
s8 DMABits; // DMA related?
s8 NoiseClk; // Noise Clock
u16 AutoDMACtrl; // AutoDMA Status
s32 DMAICounter; // DMA Interrupt Counter
u32 InputDataLeft; // Input Buffer
u32 InputPosRead;
u32 InputPosWrite;
u32 InputDataProgress;
V_Reverb Revb; // Reverb Registers
V_ReverbBuffers RevBuffers; // buffer pointers for reverb, pre-calculated and pre-clipped.
u32 EffectsStartA;
u32 EffectsEndA;
u32 ExtEffectsStartA;
u32 ExtEffectsEndA;
u32 ReverbX;
// Current size of and position of the effects buffer. Pre-caculated when the effects start
// or end position registers are written. CAN BE NEGATIVE OR ZERO, in which
// case reverb should be disabled.
s32 EffectsBufferSize;
u32 EffectsBufferStart;
V_CoreRegs Regs; // Registers
// Preserves the channel processed last cycle
StereoOut32 LastEffect;
u8 CoreEnabled;
u8 AttrBit0;
u8 DmaMode;
// new dma only
bool DmaStarted;
u32 AutoDmaFree;
// old dma only
u16 *DMAPtr;
u32 MADR;
u32 TADR;
u32 KeyOn; // not the KON register (though maybe it is)
// psxmode caches
u16 psxSoundDataTransferControl;
u16 psxSPUSTAT;
// HACK -- This is a temp buffer which is (or isn't?) used to circumvent some memory
// corruption that originates elsewhere in the plugin. >_< The actual ADMA buffer
// is an area mapped to SPU2 main memory.
//s16 ADMATempBuffer[0x1000];
// ----------------------------------------------------------------------------------
// V_Core Methods
// ----------------------------------------------------------------------------------
// uninitialized constructor
V_Core()
: Index(-1)
, DMAPtr(NULL)
{
}
V_Core(int idx); // our badass constructor
~V_Core() throw();
void Init(int index);
void UpdateEffectsBufferSize();
void AnalyzeReverbPreset();
s32 EffectsBufferIndexer(s32 offset) const;
void WriteRegPS1(u32 mem, u16 value);
u16 ReadRegPS1(u32 mem);
// --------------------------------------------------------------------------------------
// Mixer Section
// --------------------------------------------------------------------------------------
StereoOut32 Mix(const VoiceMixSet &inVoices, const StereoOut32 &Input, const StereoOut32 &Ext);
void Reverb_AdvanceBuffer();
StereoOut32 DoReverb(const StereoOut32 &Input);
s32 RevbGetIndexer(s32 offset);
StereoOut32 ReadInput();
StereoOut32 ReadInput_HiFi();
// --------------------------------------------------------------------------
// DMA Section
// --------------------------------------------------------------------------
// Returns the index of the DMA channel (4 for Core 0, or 7 for Core 1)
int GetDmaIndex() const
{
return (Index == 0) ? 4 : 7;
}
// returns either '4' or '7'
char GetDmaIndexChar() const
{
return 0x30 + GetDmaIndex();
}
__forceinline u16 DmaRead()
{
const u16 ret = (u16)spu2M_Read(TSA);
++TSA;
TSA &= 0xfffff;
return ret;
}
__forceinline void DmaWrite(u16 value)
{
spu2M_Write(TSA, value);
++TSA;
TSA &= 0xfffff;
}
void LogAutoDMA(FILE *fp);
s32 NewDmaRead(u32 *data, u32 bytesLeft, u32 *bytesProcessed);
s32 NewDmaWrite(u32 *data, u32 bytesLeft, u32 *bytesProcessed);
void NewDmaInterrupt();
// old dma only
void DoDMAwrite(u16 *pMem, u32 size);
void DoDMAread(u16 *pMem, u32 size);
void AutoDMAReadBuffer(int mode);
void StartADMAWrite(u16 *pMem, u32 sz);
void PlainDMAWrite(u16 *pMem, u32 sz);
};
extern V_Core Cores[2];
extern V_SPDIF Spdif;
// Output Buffer Writing Position (the same for all data);
extern s16 OutPos;
// Input Buffer Reading Position (the same for all data);
extern s16 InputPos;
// SPU Mixing Cycles ("Ticks mixed" counter)
extern u32 Cycles;
extern s16 *spu2regs;
extern s16 *_spu2mem;
extern int PlayMode;
extern void SetIrqCall(int core);
extern void StartVoices(int core, u32 value);
extern void StopVoices(int core, u32 value);
extern void InitADSR();
extern void CalculateADSR(V_Voice &vc);
extern void UpdateSpdifMode();
namespace Savestate
{
struct DataBlock;
extern s32 __fastcall FreezeIt(DataBlock &spud);
extern s32 __fastcall ThawIt(DataBlock &spud);
extern s32 __fastcall SizeIt();
}
// --------------------------------------------------------------------------------------
// ADPCM Decoder Cache
// --------------------------------------------------------------------------------------
// The SPU2 has a dynamic memory range which is used for several internal operations, such as
// registers, CORE 1/2 mixing, AutoDMAs, and some other fancy stuff. We exclude this range
// from the cache here:
static const s32 SPU2_DYN_MEMLINE = 0x2800;
// 8 short words per encoded PCM block. (as stored in SPU2 ram)
static const int pcm_WordsPerBlock = 8;
// number of cachable ADPCM blocks (any blocks above the SPU2_DYN_MEMLINE)
static const int pcm_BlockCount = 0x100000 / pcm_WordsPerBlock;
// 28 samples per decoded PCM block (as stored in our cache)
static const int pcm_DecodedSamplesPerBlock = 28;
struct PcmCacheEntry
{
bool Validated;
s16 Sampledata[pcm_DecodedSamplesPerBlock];
};
extern PcmCacheEntry *pcm_cache_data;

View File

@ -1,195 +0,0 @@
/* 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
#define SPU2_CORE0 0x00000000
#define SPU2_CORE1 0x00000400
#define SPU2_VP(voice) ((voice)*16)
#define SPU2_VA(voice) ((voice)*12)
#define REG_VP_VOLL 0x0000 // Voice Volume Left
#define REG_VP_VOLR 0x0002 // Voice Volume Right
#define REG_VP_PITCH 0x0004 // Pitch
#define REG_VP_ADSR1 0x0006 // Envelope 1 (Attack-Decay-Sustain-Release)
#define REG_VP_ADSR2 0x0008 // Envelope 2 (Attack-Decay-Sustain-Release)
#define REG_VP_ENVX 0x000A // Current Envelope
#define REG_VP_VOLXL 0x000C // Current Voice Volume Left
#define REG_VP_VOLXR 0x000E // Current Voice Volume Right
// .. repeated for each voice ..
#define REG_S_PMON 0x0180 // Pitch Modulation Spec.
#define REG_S_NON 0x0184 // Alloc Noise Generator
#define REG_S_VMIXL 0x0188 // Voice Output Mix Left (Dry)
#define REG_S_VMIXEL 0x018C // Voice Output Mix Left (Wet)
#define REG_S_VMIXR 0x0190 // Voice Output Mix Right (Dry)
#define REG_S_VMIXER 0x0194 // Voice Output Mix Right (Wet)
#define REG_P_MMIX 0x0198 // Output Spec. After Voice Mix
#define REG_C_ATTR 0x019A // Core X Attrib
#define REG_A_IRQA 0x019C // Interrupt Address Spec.
#define REG_S_KON 0x01A0 // Key On 0/1
#define REG_S_KOFF 0x01A4 // Key Off 0/1
#define REG_A_TSA 0x01A8 // Transfer starting address
#define REG__1AC 0x01AC // Transfer data
#define REG__1AE 0x01AE
#define REG_S_ADMAS 0x01B0 // AutoDMA Status
// 1b2, 1b4, 1b6, 1b8, 1ba, 1bc, 1be are unknown
#define REG_VA_SSA 0x01C0 // Waveform data starting address
#define REG_VA_LSAX 0x01C4 // Loop point address
#define REG_VA_NAX 0x01C8 // Waveform data that should be read next
// .. repeated for each voice ..
#define REG_A_ESA 0x02E0 //Address: Top address of working area for effects processing
#define R_APF1_SIZE 0x02E4 // Feedback Source A
#define R_APF2_SIZE 0x02E8 // Feedback Source B
#define R_SAME_L_DST 0x02EC
#define R_SAME_R_DST 0x02F0
#define R_COMB1_L_SRC 0x02F4
#define R_COMB1_R_SRC 0x02F8
#define R_COMB2_L_SRC 0x02FC
#define R_COMB2_R_SRC 0x0300
#define R_SAME_L_SRC 0x0304
#define R_SAME_R_SRC 0x0308
#define R_DIFF_L_DST 0x030C
#define R_DIFF_R_DST 0x0310
#define R_COMB3_L_SRC 0x0314
#define R_COMB3_R_SRC 0x0318
#define R_COMB4_L_SRC 0x031C
#define R_COMB4_R_SRC 0x0320
#define R_DIFF_L_SRC 0x0324 // Some sources have R_DIFF_R_SRC and R_DIFF_L_SRC swapped ><
#define R_DIFF_R_SRC 0x0328
#define R_APF1_L_DST 0x032C
#define R_APF1_R_DST 0x0330
#define R_APF2_L_DST 0x0334
#define R_APF2_R_DST 0x0338
#define REG_A_EEA 0x033C // Address: End address of working area for effects processing (upper part of address only!)
#define REG_S_ENDX 0x0340 // End Point passed flag
#define REG_P_STATX 0x0344 // Status register?
// 0x346 .. 0x3fe are unknown (unused?)
// core 1 has the same registers with 0x400 added.
// core 1 ends at 0x746
// 0x746 .. 0x75e are unknown
// "Different" register area
#define REG_P_MVOLL 0x0760 // Master Volume Left
#define REG_P_MVOLR 0x0762 // Master Volume Right
#define REG_P_EVOLL 0x0764 // Effect Volume Left
#define REG_P_EVOLR 0x0766 // Effect Volume Right
#define REG_P_AVOLL 0x0768 // Core External Input Volume Left (Only Core 1)
#define REG_P_AVOLR 0x076A // Core External Input Volume Right (Only Core 1)
#define REG_P_BVOLL 0x076C // Sound Data Volume Left
#define REG_P_BVOLR 0x076E // Sound Data Volume Right
#define REG_P_MVOLXL 0x0770 // Current Master Volume Left
#define REG_P_MVOLXR 0x0772 // Current Master Volume Right
#define R_IIR_VOL 0x0774
#define R_COMB1_VOL 0x0776
#define R_COMB2_VOL 0x0778
#define R_COMB3_VOL 0x077A
#define R_COMB4_VOL 0x077C
#define R_WALL_VOL 0x077E
#define R_APF1_VOL 0x0780
#define R_APF2_VOL 0x0782
#define R_IN_COEF_L 0x0784
#define R_IN_COEF_R 0x0786
// values repeat for core1
// End OF "Different" register area
// SPDIF interface
#define SPDIF_OUT 0x07C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass
#define SPDIF_IRQINFO 0x07C2
#define SPDIF_MODE 0x07C6
#define SPDIF_MEDIA 0x07C8 // SPDIF Media: 'CD'/DVD
#define SPDIF_PROTECT 0x07CC // SPDIF Copy Protection
/*********************************************************************
Core attributes (SD_C)
bit 1 - Unknown (this bit is sometimes set)
bit 2..3 - Unknown (usually never set)
bit 4..5 - DMA related
bit 6 - IRQ? DMA mode? wtf?
bit 7 - effect enable (reverb enable)
bit 8 - IRQ enable?
bit 9..14 - noise clock
bit 15 - mute
bit 16 - reset
*********************************************************************/
#define SPDIF_OUT_OFF 0x0000 // no spdif output
#define SPDIF_OUT_PCM 0x0020 // encode spdif from spu2 pcm output
#define SPDIF_OUT_BYPASS 0x0100 // bypass spu2 processing
#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 // bypass mode for digital bitstream data
#define SPDIF_MODE_BYPASS_PCM 0x0000 // bypass mode for pcm data (using analog output)
#define SPDIF_MODE_MEDIA_CD 0x0800 // source media is a CD
#define SPDIF_MODE_MEDIA_DVD 0x0000 // source media is a DVD
#define SPDIF_MEDIA_CDVD 0x0200
#define SPDIF_MEDIA_400 0x0000
#define SPDIF_PROTECT_NORMAL 0x0000 // spdif stream is not protected
#define SPDIF_PROTECT_PROHIBIT 0x8000 // spdif stream can't be copied
/********************************************************************/
#define VOICE_PARAM_VOLL 0x0 // Voice Volume Left
#define VOICE_PARAM_VOLR 0x2 // Voice Volume Right
#define VOICE_PARAM_PITCH 0x4 // Pitch
#define VOICE_PARAM_ADSR1 0x6 // Envelope 1 (Attack-Delay-Sustain-Release)
#define VOICE_PARAM_ADSR2 0x8 // Envelope 2 (Attack-Delay-Sustain-Release)
#define VOICE_PARAM_ENVX 0xA // Current Envelope
#define VOICE_PARAM_VOLXL 0xC // Current Voice Volume Left
#define VOICE_PARAM_VOLXR 0xE // Current Voice Volume Right
/********************************************************************/
#define VOICE_ADDR_SSA 0x0 // Waveform data starting address
#define VOICE_ADDR_LSAX 0x4 // Loop point address
#define VOICE_ADDR_NAX 0x8 // Waveform data that should be read next
// --------------------------------------------------------------------------------------
// SPU2-X Register Table LUT
// --------------------------------------------------------------------------------------
#define U16P(x) ((u16 *)&(x))
// Returns the hiword of a 32 bit integer.
#define U16P_HI(x) (((u16 *)&(x)) + 1)
extern u16 *regtable[0x401];
extern u16 const *const regtable_original[0x401];

View File

@ -1,110 +0,0 @@
//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
#ifndef u32
typedef unsigned int u32;
#endif
/*
Preamble cell-order cell-order
(last cell "0") (last cell "1")
----------------------------------------------
"B" 11101000 00010111
"M" 11100010 00011101
"W" 11100100 00011011
Only the lower 4 bits are used.
Preamble B: Marks a word containing data for channel A (left)
at the start of the data-block.
Preamble M: Marks a word with data for channel A that isn't
at the start of the data-block.
Preamble W: Marks a word containing data for channel B.
(right, for stereo). When using more than 2
channels, this could also be any other channel
(except for A).
bits meaning
----------------------------------------------------------
0-3 Preamble (see above; special structure)
4-7 Auxillary-audio-databits
8-27 Sample
(A 24-bit sample can be used (using bits 4-27).
A CD-player uses only 16 bits, so only bits
13 (LSB) to 27 (MSB) are used. Bits 4-12 are
set to 0).
28 Validity
(When this bit is set, the sample should not
be used by the receiver. A CD-player uses
the 'error-flag' to set this bit).
29 Subcode-data
30 Channel-status-information
31 Parity (bit 0-3 are not included)
*/
typedef struct _subframe
{
u32 preamble : 4;
u32 aux_data : 4;
u32 snd_data : 20;
u32 validity : 1;
u32 subcode : 1;
u32 chstatus : 1;
u32 parity : 1;
} subframe;
/*
bit meaning
-------------------------------------------------------------
0-3 controlbits:
bit 0: 0 (is set to 1 during 4 channel transmission)
bit 1: 0=Digital audio, 1=Non-audio (reserved to be 0 on old S/PDIF specs)
bit 2: copy-protection. Copying is allowed when this bit is set.
bit 3: is set when pre-emphasis is used.
4-7 0 (reserved)
9-15 catagory-code:
0 = common 2-channel format
1 = 2-channel CD-format
(set by a CD-player when a subcode is transmitted)
2 = 2-channel PCM-encoder-decoder format
others are not used
19-191 0 (reserved)
*/
typedef struct _chstatus
{
u8 ctrlbits : 4;
u8 reservd1 : 4;
u8 category;
u8 reservd2[22];
} chstatus:

View File

@ -1,147 +0,0 @@
/* 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 "PS2E-spu2.h" // hopefully temporary, until I resolve lClocks depdendency
namespace Savestate
{
// Arbitrary ID to identify SPU2-X saves.
static const u32 SAVE_ID = 0x1227521;
// versioning for saves.
// Increment this when changes to the savestate system are made.
static const u32 SAVE_VERSION = 0x000e;
static void wipe_the_cache()
{
memset(pcm_cache_data, 0, pcm_BlockCount * sizeof(PcmCacheEntry));
}
}
struct Savestate::DataBlock
{
u32 spu2id; // SPU2-X state identifier lets ZeroGS/PeopsSPU2 know this isn't their state)
u8 unkregs[0x10000]; // SPU2 raw register memory
u8 mem[0x200000]; // SPU2 raw sample memory
u32 version; // SPU2-X version identifier
V_Core Cores[2];
V_SPDIF Spdif;
s16 OutPos;
s16 InputPos;
u32 Cycles;
u32 lClocks;
int PlayMode;
};
s32 __fastcall Savestate::FreezeIt(DataBlock &spud)
{
spud.spu2id = SAVE_ID;
spud.version = SAVE_VERSION;
pxAssertMsg(spu2regs && _spu2mem, "Looks like PCSX2 is trying to savestate while pluigns are shut down. That's a no-no! It shouldn't crash, but the savestate will probably be corrupted.");
if (spu2regs != NULL)
memcpy(spud.unkregs, spu2regs, sizeof(spud.unkregs));
if (_spu2mem != NULL)
memcpy(spud.mem, _spu2mem, sizeof(spud.mem));
memcpy(spud.Cores, Cores, sizeof(Cores));
memcpy(&spud.Spdif, &Spdif, sizeof(Spdif));
spud.OutPos = OutPos;
spud.InputPos = InputPos;
spud.Cycles = Cycles;
spud.lClocks = lClocks;
spud.PlayMode = PlayMode;
// note: Don't save the cache. PCSX2 doesn't offer a safe method of predicting
// the required size of the savestate prior to saving, plus this is just too
// "implementation specific" for the intended spec of a savestate. Let's just
// force the user to rebuild their cache instead.
return 0;
}
s32 __fastcall Savestate::ThawIt(DataBlock &spud)
{
if (spud.spu2id != SAVE_ID || spud.version < SAVE_VERSION) {
fprintf(stderr, "\n*** SPU2-X Warning:\n");
if (spud.spu2id == SAVE_ID)
fprintf(stderr, "\tSavestate version is from an older version of this plugin.\n");
else
fprintf(stderr, "\tThe savestate you are trying to load was not made with this plugin.\n");
fprintf(stderr,
"\tAudio may not recover correctly. Save your game to memorycard, reset,\n\n"
"\tand then continue from there.\n\n");
// Do *not* reset the cores.
// We'll need some "hints" as to how the cores should be initialized, and the
// only way to get that is to use the game's existing core settings and hope
// they kinda match the settings for the savestate (IRQ enables and such).
// adpcm cache : Clear all the cache flags and buffers.
wipe_the_cache();
} else {
SndBuffer::ClearContents();
pxAssertMsg(spu2regs && _spu2mem, "Looks like PCSX2 is trying to loadstate while pluigns are shut down. That's a no-no! It shouldn't crash, but the savestate will probably be corrupted.");
// base stuff
if (spu2regs)
memcpy(spu2regs, spud.unkregs, sizeof(spud.unkregs));
if (_spu2mem)
memcpy(_spu2mem, spud.mem, sizeof(spud.mem));
memcpy(Cores, spud.Cores, sizeof(Cores));
memcpy(&Spdif, &spud.Spdif, sizeof(Spdif));
OutPos = spud.OutPos;
InputPos = spud.InputPos;
Cycles = spud.Cycles;
lClocks = spud.lClocks;
PlayMode = spud.PlayMode;
wipe_the_cache();
// Go through the V_Voice structs and recalculate SBuffer pointer from
// the NextA setting.
for (int c = 0; c < 2; c++) {
for (int v = 0; v < 24; v++) {
const int cacheIdx = Cores[c].Voices[v].NextA / pcm_WordsPerBlock;
Cores[c].Voices[v].SBuffer = pcm_cache_data[cacheIdx].Sampledata;
}
}
// HACKFIX!! DMAPtr can be invalid after a savestate load, so force it to NULL and
// ignore it on any pending ADMA writes. (the DMAPtr concept used to work in old VM
// editions of PCSX2 with fixed addressing, but new PCSX2s have dynamic memory
// addressing).
Cores[0].DMAPtr = Cores[1].DMAPtr = NULL;
}
return 0;
}
s32 __fastcall Savestate::SizeIt()
{
return sizeof(DataBlock);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,503 +0,0 @@
/* 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 "wxConfig.h"
MixerTab::MixerTab(wxWindow* parent)
: wxPanel(parent, wxID_ANY)
{
auto* top_box = new wxBoxSizer(wxVERTICAL);
// Mixing Settings
top_box->Add(new wxStaticText(this, wxID_ANY, "Interpolation"), wxSizerFlags().Centre());
m_interpolation.Add("Nearest (Fastest/bad quality)");
m_interpolation.Add("Linear (Simple/okay sound)");
m_interpolation.Add("Cubic (Artificial highs)");
m_interpolation.Add("Hermite (Better highs)");
m_interpolation.Add("Catmull-Rom (PS2-like/slow)");
m_inter_select = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_interpolation);
effect_check = new wxCheckBox(this, wxID_ANY, "Disable Effects Processing (Speedup)");
dealias_check = new wxCheckBox(this, wxID_ANY, "Use the de-alias filter (Overemphasizes the highs) ");
// Latency Slider
const int min_latency = SynchMode == 0 ? LATENCY_MIN_TIMESTRETCH : LATENCY_MIN;
m_latency_box = new wxStaticBoxSizer(wxVERTICAL, this, "Latency");
m_latency_slider = new wxSlider(this, wxID_ANY, SndOutLatencyMS, min_latency, LATENCY_MAX, wxDefaultPosition, wxDefaultSize, wxSL_LABELS);
m_latency_box->Add(m_latency_slider, wxSizerFlags().Expand());
// Volume Slider
m_volume_box = new wxStaticBoxSizer(wxVERTICAL, this, "Volume");
m_volume_slider = new wxSlider(this, wxID_ANY, FinalVolume * 100, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_LABELS);
m_volume_box->Add(m_volume_slider, wxSizerFlags().Expand());
m_audio_box = new wxBoxSizer(wxVERTICAL);
m_audio_box->Add(new wxStaticText(this, wxID_ANY, "Audio Expansion Mode"), wxSizerFlags().Centre());
m_audio.Add("Stereo (None, Default)");
m_audio.Add("Quadrafonic");
m_audio.Add("Surround 5.1");
m_audio.Add("Surround 7.1");
m_audio_select = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_audio);
m_audio_box->Add(m_audio_select, wxSizerFlags().Expand());
top_box->Add(m_inter_select, wxSizerFlags().Centre());
top_box->Add(effect_check, wxSizerFlags().Centre());
top_box->Add(dealias_check, wxSizerFlags().Centre());
top_box->Add(m_latency_box, wxSizerFlags().Expand());
top_box->Add(m_volume_box, wxSizerFlags().Expand());
top_box->Add(m_audio_box, wxSizerFlags().Expand());
SetSizerAndFit(top_box);
}
void MixerTab::Load()
{
m_inter_select->SetSelection(Interpolation);
effect_check->SetValue(EffectsDisabled);
dealias_check->SetValue(postprocess_filter_dealias);
m_audio_select->SetSelection(numSpeakers);
m_volume_slider->SetValue(FinalVolume * 100);
m_latency_slider->SetValue(SndOutLatencyMS);
}
void MixerTab::Save()
{
Interpolation = m_inter_select->GetSelection();
EffectsDisabled = effect_check->GetValue();
postprocess_filter_dealias = dealias_check->GetValue();
numSpeakers = m_audio_select->GetSelection();
FinalVolume = m_volume_slider->GetValue() / 100.0;
SndOutLatencyMS = m_latency_slider->GetValue();
}
void MixerTab::Update()
{
}
void MixerTab::CallUpdate(wxCommandEvent& /*event*/)
{
Update();
}
SyncTab::SyncTab(wxWindow* parent)
: wxPanel(parent, wxID_ANY)
{
auto* top_box = new wxBoxSizer(wxVERTICAL);
top_box->Add(new wxStaticText(this, wxID_ANY, "Synchronization"), wxSizerFlags().Centre());
m_sync.Add("TimeStretch (Recommended)");
m_sync.Add("Async Mix (Breaks some games!)");
m_sync.Add("None (Audio can skip.)");
m_sync_select = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_sync);
auto* adv_box = new wxStaticBoxSizer(wxVERTICAL, this, "Advanced");
auto* babble_label = new wxStaticText(this, wxID_ANY, \
"For fine-tuning time stretching.\n"\
"Larger is better for slowdown, && smaller for speedup (60+ fps).\n"\
"All options in microseconds.",\
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL);
babble_label->Wrap(300);
adv_box->Add(babble_label, wxSizerFlags().Centre());
auto* soundtouch_grid = new wxFlexGridSizer(2, 10, 50);
seq_spin = new wxSpinCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT, SoundtouchCfg::SequenceLen_Min, SoundtouchCfg::SequenceLen_Max, SoundtouchCfg::SequenceLenMS);
auto* seq_label = new wxStaticText(this, wxID_ANY, "Sequence Length");
seek_spin = new wxSpinCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT, SoundtouchCfg::SeekWindow_Min, SoundtouchCfg::SeekWindow_Max, SoundtouchCfg::SeekWindowMS);
auto* seek_label = new wxStaticText(this, wxID_ANY, "Seek Window Size");
overlap_spin = new wxSpinCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT, SoundtouchCfg::Overlap_Min, SoundtouchCfg::Overlap_Max, SoundtouchCfg::OverlapMS);
auto* overlap_label = new wxStaticText(this, wxID_ANY, "Overlap");
soundtouch_grid->Add(seq_label, wxSizerFlags().Border(wxALL, 5));
soundtouch_grid->Add(seq_spin, wxSizerFlags().Expand().Right());
soundtouch_grid->Add(seek_label, wxSizerFlags().Border(wxALL, 5));
soundtouch_grid->Add(seek_spin, wxSizerFlags().Expand().Right());
soundtouch_grid->Add(overlap_label, wxSizerFlags().Border(wxALL, 5));
soundtouch_grid->Add(overlap_spin, wxSizerFlags().Expand().Right());
adv_box->Add(soundtouch_grid);
reset_button = new wxButton(this, wxID_ANY, "Reset To Defaults");
adv_box->Add(reset_button, wxSizerFlags().Centre().Border(wxALL, 5));
top_box->Add(m_sync_select, wxSizerFlags().Centre());
top_box->Add(adv_box, wxSizerFlags().Expand().Centre());
SetSizerAndFit(top_box);
Bind(wxEVT_BUTTON, &SyncTab::OnButtonClicked, this);
Bind(wxEVT_CHOICE, &SyncTab::CallUpdate, this);
}
void SyncTab::Load()
{
m_sync_select->SetSelection(SynchMode);
SoundtouchCfg::ReadSettings();
seq_spin->SetValue(SoundtouchCfg::SequenceLenMS);
seek_spin->SetValue(SoundtouchCfg::SeekWindowMS);
overlap_spin->SetValue(SoundtouchCfg::OverlapMS);
}
void SyncTab::Save()
{
SynchMode = m_sync_select->GetSelection();
SoundtouchCfg::SequenceLenMS = seq_spin->GetValue();
SoundtouchCfg::SeekWindowMS = seek_spin->GetValue();
SoundtouchCfg::OverlapMS = overlap_spin->GetValue();
SoundtouchCfg::WriteSettings();
}
void SyncTab::Update()
{
seq_spin->Enable(m_sync_select->GetCurrentSelection() == 0);
seek_spin->Enable(m_sync_select->GetCurrentSelection() == 0);
overlap_spin->Enable(m_sync_select->GetCurrentSelection() == 0);
}
void SyncTab::CallUpdate(wxCommandEvent& /*event*/)
{
Update();
}
void SyncTab::OnButtonClicked(wxCommandEvent& event)
{
seq_spin->SetValue(30);
seek_spin->SetValue(20);
overlap_spin->SetValue(10);
}
DebugTab::DebugTab(wxWindow* parent)
: wxPanel(parent, wxID_ANY)
{
auto* top_box = new wxBoxSizer(wxVERTICAL);
debug_check = new wxCheckBox(this, wxID_ANY, "Enable Debug Options");
show_check = new wxCheckBox(this, wxID_ANY, "Show in console");
top_box->Add(debug_check, wxSizerFlags().Expand());
top_box->Add(show_check);
m_console_box = new wxStaticBoxSizer(wxVERTICAL, this, "Events");
auto* console_grid = new wxFlexGridSizer(2, 0, 0);
key_check = new wxCheckBox(this, wxID_ANY, "Key On/Off");
voice_check = new wxCheckBox(this, wxID_ANY, "Voice Stop");
dma_check = new wxCheckBox(this, wxID_ANY, "DMA Operations");
autodma_check = new wxCheckBox(this, wxID_ANY, "AutoDMA Operations");
buffer_check = new wxCheckBox(this, wxID_ANY, "Buffer Over/Underruns");
adpcm_check = new wxCheckBox(this, wxID_ANY, "ADPCM Cache");
console_grid->Add(key_check);
console_grid->Add(voice_check);
console_grid->Add(dma_check);
console_grid->Add(autodma_check);
console_grid->Add(buffer_check);
console_grid->Add(adpcm_check);
m_console_box->Add(console_grid);
m_log_only_box = new wxStaticBoxSizer(wxVERTICAL, this, "Log Only");
auto* log_grid = new wxFlexGridSizer(2, 0, 0);
dma_actions_check = new wxCheckBox(this, wxID_ANY, "Register/DMA Actions");
dma_writes_check = new wxCheckBox(this, wxID_ANY, "DMA Writes");
auto_output_check = new wxCheckBox(this, wxID_ANY, "Audio Output");
log_grid->Add(dma_actions_check);
log_grid->Add(dma_writes_check);
log_grid->Add(auto_output_check);
m_log_only_box->Add(log_grid);
dump_box = new wxStaticBoxSizer(wxVERTICAL, this, "Dump on Close");
auto* dump_grid = new wxFlexGridSizer(2, 0, 0);
core_voice_check = new wxCheckBox(this, wxID_ANY, "Core && Voice Stats");
memory_check = new wxCheckBox(this, wxID_ANY, "Memory Contents");
register_check = new wxCheckBox(this, wxID_ANY, "Register Data");
dump_grid->Add(core_voice_check);
dump_grid->Add(memory_check);
dump_grid->Add(register_check);
dump_box->Add(dump_grid);
top_box->Add(m_console_box, wxSizerFlags().Expand());
top_box->Add(m_log_only_box, wxSizerFlags().Expand());
top_box->Add(dump_box, wxSizerFlags().Expand());
SetSizerAndFit(top_box);
Bind(wxEVT_CHECKBOX, &DebugTab::CallUpdate, this);
}
void DebugTab::Load()
{
debug_check->SetValue(DebugEnabled);
show_check->SetValue(_MsgToConsole);
key_check->SetValue(_MsgKeyOnOff);
voice_check->SetValue(_MsgVoiceOff);
dma_check->SetValue(_MsgDMA);
autodma_check->SetValue(_MsgAutoDMA);
buffer_check->SetValue(_MsgOverruns);
adpcm_check->SetValue(_MsgCache);
dma_actions_check->SetValue(_AccessLog);
dma_writes_check->SetValue(_DMALog);
auto_output_check->SetValue(_WaveLog);
core_voice_check->SetValue(_CoresDump);
memory_check->SetValue(_MemDump);
register_check->SetValue(_RegDump);
Update();
}
void DebugTab::Save()
{
DebugEnabled = debug_check->GetValue();
_MsgToConsole = show_check->GetValue();
_MsgKeyOnOff = key_check->GetValue();
_MsgVoiceOff = voice_check->GetValue();
_MsgDMA = dma_check->GetValue();
_MsgAutoDMA = autodma_check->GetValue();
_MsgOverruns = buffer_check->GetValue();
_MsgCache = adpcm_check->GetValue();
_AccessLog = dma_actions_check->GetValue();
_DMALog = dma_writes_check->GetValue();
_WaveLog = auto_output_check->GetValue();
_CoresDump = core_voice_check->GetValue();
_MemDump = memory_check->GetValue();
_RegDump = register_check->GetValue();
}
void DebugTab::Update()
{
if (debug_check->GetValue())
{
show_check->Enable();
key_check->Enable();
voice_check->Enable();
dma_check->Enable();
autodma_check->Enable();
buffer_check->Enable();
adpcm_check->Enable();
dma_actions_check->Enable();
dma_writes_check->Enable();
auto_output_check->Enable();
core_voice_check->Enable();
memory_check->Enable();
register_check->Enable();
}
else
{
show_check->Disable();
key_check->Disable();
voice_check->Disable();
dma_check->Disable();
autodma_check->Disable();
buffer_check->Disable();
adpcm_check->Disable();
dma_actions_check->Disable();
dma_writes_check->Disable();
auto_output_check->Disable();
core_voice_check->Disable();
memory_check->Disable();
register_check->Disable();
}
}
void DebugTab::CallUpdate(wxCommandEvent& /*event*/)
{
Update();
}
Dialog::Dialog()
: wxDialog(nullptr, wxID_ANY, "SPU2 Config", wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
{
m_top_box = new wxBoxSizer(wxVERTICAL);
auto* module_box = new wxBoxSizer(wxVERTICAL);
// Module
module_box->Add(new wxStaticText(this, wxID_ANY, "Module"), wxSizerFlags().Centre());
m_module.Add("No Sound (Emulate SPU2 only)");
#ifdef SPU2X_PORTAUDIO
m_module.Add("PortAudio (Cross-platform)");
#endif
m_module.Add("SDL Audio (Recommended for PulseAudio)");
m_module_select = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_module);
module_box->Add(m_module_select, wxSizerFlags().Centre());
#ifdef SPU2X_PORTAUDIO
// Portaudio
m_portaudio_box = new wxBoxSizer(wxVERTICAL);
m_portaudio_text = new wxStaticText(this, wxID_ANY, "Portaudio API");
m_portaudio_box->Add(m_portaudio_text, wxSizerFlags().Centre());
#ifdef __linux__
m_portaudio.Add("ALSA (recommended)");
m_portaudio.Add("OSS (legacy)");
m_portaudio.Add("JACK");
#elif defined(__APPLE__)
m_portaudio.Add("CoreAudio");
#else
m_portaudio.Add("OSS");
#endif
m_portaudio_select = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_portaudio);
m_portaudio_box->Add(m_portaudio_select, wxSizerFlags().Centre());
#endif
// SDL
m_sdl_box = new wxBoxSizer(wxVERTICAL);
m_sdl_text = new wxStaticText(this, wxID_ANY, "SDL API");
m_sdl_box->Add(m_sdl_text, wxSizerFlags().Centre());
for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i)
m_sdl.Add(SDL_GetAudioDriver(i));
m_sdl_select = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_sdl);
m_sdl_box->Add(m_sdl_select, wxSizerFlags().Centre());
#ifdef SPU2X_PORTAUDIO
module_box->Add(m_portaudio_box, wxSizerFlags().Expand());
#endif
module_box->Add(m_sdl_box, wxSizerFlags().Expand());
m_top_box->Add(module_box, wxSizerFlags().Centre().Border(wxALL, 5));
auto* book = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_mixer_panel = new MixerTab(book);
m_sync_panel = new SyncTab(book);
m_debug_panel = new DebugTab(book);
book->AddPage(m_mixer_panel, "Mixing", true);
book->AddPage(m_sync_panel, "Sync");
book->AddPage(m_debug_panel, "Debug");
m_top_box->Add(book, wxSizerFlags().Centre());
m_top_box->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), wxSizerFlags().Right());
SetSizerAndFit(m_top_box);
Bind(wxEVT_CHOICE, &Dialog::CallReconfigure, this);
Bind(wxEVT_CHECKBOX, &Dialog::CallReconfigure, this);
}
Dialog::~Dialog()
{
}
void Dialog::Reconfigure()
{
const int mod = m_module_select->GetCurrentSelection();
bool show_portaudio = false, show_sdl = false;
switch (mod)
{
case 0:
show_portaudio = false;
show_sdl = false;
break;
case 1:
show_portaudio = true;
show_sdl = false;
break;
case 2:
show_portaudio = false;
show_sdl = true;
break;
default:
show_portaudio = false;
show_sdl = false;
break;
}
#ifdef SPU2X_PORTAUDIO
m_top_box->Show(m_portaudio_box, show_portaudio, true);
#endif
m_top_box->Show(m_sdl_box, show_sdl, true);
// Recalculating both of these accounts for if neither was showing initially.
m_top_box->Layout();
SetSizerAndFit(m_top_box);
}
void Dialog::CallReconfigure(wxCommandEvent& event)
{
Reconfigure();
}
void Dialog::Load()
{
m_module_select->SetSelection(OutputModule);
#ifdef SPU2X_PORTAUDIO
m_portaudio_select->SetSelection(OutputAPI);
#endif
m_sdl_select->SetSelection(SdlOutputAPI);
m_mixer_panel->Load();
m_sync_panel->Load();
m_debug_panel->Load();
Reconfigure();
}
void Dialog::Save()
{
OutputModule = m_module_select->GetSelection();
#ifdef SPU2X_PORTAUDIO
OutputAPI = m_portaudio_select->GetSelection();
wxString p_api(m_portaudio_select->GetStringSelection());
if (p_api.Find("ALSA") != wxNOT_FOUND)
p_api = "ALSA";
if (p_api.Find("OSS") != wxNOT_FOUND)
p_api = "OSS";
PortaudioOut->SetApiSettings(p_api);
#endif
SdlOutputAPI = m_sdl_select->GetSelection();
SDLOut->SetApiSettings(m_sdl_select->GetStringSelection());
m_mixer_panel->Save();
m_sync_panel->Save();
m_debug_panel->Save();
}
// Main
void Dialog::Display()
{
Load();
if (ShowModal() == wxID_OK)
Save();
}

View File

@ -1,110 +0,0 @@
/* 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 <wx/wx.h>
#include <wx/panel.h>
#include <wx/wrapsizer.h>
#include <wx/notebook.h>
#include <wx/spinctrl.h>
#if defined(__unix__) || defined(__APPLE__)
#include <SDL.h>
#include <SDL_audio.h>
#include "Linux/Config.h"
#endif
class MixerTab : public wxPanel
{
public:
wxArrayString m_interpolation;
wxChoice* m_inter_select;
wxCheckBox *effect_check, *dealias_check;
wxSlider *m_latency_slider, *m_volume_slider;
wxArrayString m_audio;
wxChoice* m_audio_select;
wxStaticBoxSizer *m_mix_box, *m_volume_box, *m_latency_box;
wxBoxSizer* m_audio_box;
MixerTab(wxWindow* parent);
void Load();
void Save();
void Update();
void CallUpdate(wxCommandEvent& event);
};
class SyncTab : public wxPanel
{
public:
wxStaticBoxSizer* m_sync_box;
wxArrayString m_sync;
wxChoice* m_sync_select;
wxButton* launch_adv_dialog;
wxButton* reset_button;
wxSpinCtrl *seq_spin, *seek_spin, *overlap_spin;
SyncTab(wxWindow* parent);
void Load();
void Save();
void Update();
void CallUpdate(wxCommandEvent& event);
void OnButtonClicked(wxCommandEvent& event);
};
class DebugTab : public wxPanel
{
public:
wxCheckBox* debug_check;
wxButton* launch_debug_dialog;
wxBoxSizer* m_together_box;
wxStaticBoxSizer *m_console_box, *m_log_only_box, *dump_box;
wxCheckBox* show_check;
wxCheckBox *key_check, *voice_check, *dma_check, *autodma_check, *buffer_check, *adpcm_check;
wxCheckBox *dma_actions_check, *dma_writes_check, *auto_output_check;
wxCheckBox *core_voice_check, *memory_check, *register_check;
DebugTab(wxWindow* parent);
void Load();
void Save();
void Update();
void CallUpdate(wxCommandEvent& event);
};
class Dialog : public wxDialog
{
wxBoxSizer *m_top_box, *m_left_box, *m_right_box;
wxBoxSizer *m_portaudio_box, *m_sdl_box;
wxStaticBoxSizer* m_output_box;
wxArrayString m_module, m_portaudio, m_sdl;
wxChoice *m_module_select, *m_portaudio_select, *m_sdl_select;
wxStaticText *m_portaudio_text, *m_sdl_text;
MixerTab* m_mixer_panel;
SyncTab* m_sync_panel;
DebugTab* m_debug_panel;
public:
Dialog();
~Dialog();
void Display();
void Load();
void Save();
void Reconfigure();
void CallReconfigure(wxCommandEvent& event);
};