mirror of https://github.com/PCSX2/pcsx2.git
SPU2: remove initial plugin references
This commit is contained in:
parent
cf58a32583
commit
b8c3bd4fae
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
#---------------------------------------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -23,7 +23,6 @@ enum PluginsEnum_t
|
|||
{
|
||||
PluginId_GS = 0,
|
||||
PluginId_PAD,
|
||||
PluginId_SPU2,
|
||||
PluginId_USB,
|
||||
PluginId_DEV9,
|
||||
PluginId_Count,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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 ))
|
||||
};
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
||||
|
|
@ -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.
|
||||
|
||||
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
|
@ -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
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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 :)
|
||||
}
|
|
@ -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
|
|
@ -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>.
|
|
@ -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.
|
|
@ -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 |
|
@ -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;
|
||||
}
|
|
@ -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)
|
|
@ -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();
|
|
@ -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
|
||||
}
|
|
@ -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 //
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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__
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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"
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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};
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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;
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
|
@ -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];
|
|
@ -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:
|
|
@ -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
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
};
|
Loading…
Reference in New Issue