* Potential Bugfix: Core1's DMA IRQ trigger was being ignored in some instances; might fix some hangs.
 * Major code cleanups, using C++ structure member methods and functions.
 * Improved gui / plugin api / core emulation code separation -- hoping to switch to wxWidgets eventually.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1930 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-09-29 19:18:50 +00:00
parent 15d2824d1b
commit 158b01b58d
51 changed files with 2421 additions and 2294 deletions

View File

@ -15,7 +15,7 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Spu2.h" #include "Global.h"
static const s32 ADSR_MAX_VOL = 0x7fffffff; static const s32 ADSR_MAX_VOL = 0x7fffffff;
@ -34,7 +34,7 @@ void InitADSR() // INIT ADSR
else else
rate <<= shift; rate <<= shift;
PsxRates[i] = (int)min( rate, 0x3fffffffLL ); PsxRates[i] = (int)std::min( rate, 0x3fffffffLL );
} }
} }

View File

@ -1,119 +0,0 @@
#ifndef _BASETYPES_H_
#define _BASETYPES_H_
#include "PS2Edefs.h"
//system defines
#ifdef __LINUX__
# undef __LINUX__ // supress gtk's warnings on redefinition
# include <gtk/gtk.h>
#else
# define WINVER 0x0501
# define _WIN32_WINNT 0x0501
# include <windows.h>
# include <mmsystem.h>
# include <tchar.h>
# include "resource.h"
#endif
#include <assert.h>
#include <cstdlib>
#include <cstdio>
#include <cstdarg>
#include <cmath>
#include <ctime>
#include <stdexcept>
#include <string>
using std::string;
using std::wstring;
//////////////////////////////////////////////////////////////////////////
// Override Win32 min/max macros with the STL's type safe and macro
// free varieties (much safer!)
#undef min
#undef max
#include <algorithm>
using std::min;
using std::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 );
}
extern void SysMessage(const char *fmt, ...);
//////////////////////////////////////////////////////////////
// Dev / Debug conditionals --
// Consts for using if() statements instead of uglier #ifdef macros.
// Abbreviated macros for dev/debug only consoles and msgboxes.
#ifdef SPU2X_DEVBUILD
# define DevCon Console
# define DevMsg MsgBox
#else
# define DevCon 0&&Console
# define DevMsg
#endif
#ifdef PCSX2_DEBUG
# define DbgCon Console
#else
# define DbgCon 0&&Console
#endif
struct StereoOut16;
struct StereoOutFloat;
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 StereoOut32& right ) const
{
return StereoOut32(
Left + right.Left,
Right + right.Right
);
}
StereoOut32 operator/( int src ) const
{
return StereoOut32( Left / src, Right / src );
}
};
#endif

View File

@ -0,0 +1,88 @@
/* 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;
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 u32 OutputModule;
extern int SndOutLatencyMS;
extern wchar_t dspPlugin[];
extern int dspPluginModule;
extern bool dspPluginEnabled;
extern bool timeStretchDisabled;
extern bool StereoExpansionEnabled;
namespace SoundtouchCfg
{
extern void ApplySettings( soundtouch::SoundTouch& sndtouch );
}
//////
extern void ReadSettings();
extern void WriteSettings();
extern void configure();
extern void AboutBox();

View File

@ -38,13 +38,9 @@
------------------------------------------------------------------------ */ ------------------------------------------------------------------------ */
#include "PS2Etypes.h" #include "Global.h"
#include <stdexcept>
#include <string>
#include "ConvertUTF.h" #include "ConvertUTF.h"
using std::string; using std::string;
using std::wstring; using std::wstring;

View File

@ -15,7 +15,7 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Spu2.h" #include "Global.h"
int crazy_debug=0; int crazy_debug=0;

View File

@ -15,7 +15,8 @@
//License along with this library; if not, write to the Free Software //License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
#include "Spu2.h"
#include "Global.h"
extern "C" { extern "C" {
#include "liba52/inttypes.h" #include "liba52/inttypes.h"
@ -129,12 +130,13 @@ s32 stoi(sample_t n) //input: [-1..1]
void spdif_update() void spdif_update()
{ {
StereoOut32 Data;
for(int i=0;i<data_rate;i++) for(int i=0;i<data_rate;i++)
{ {
// Right side data should be zero / ignored // Source is Core 0
ReadInput( 0, Data ); // read from core 0 // .. and Right side data should be zero / ignored
StereoOut32 Data( Cores[0].ReadInput() );
if(fSpdifDump) if(fSpdifDump)
{ {

View File

@ -15,23 +15,20 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Spu2.h" #include "Global.h"
#include "dma.h"
#include "PS2E-spu2.h" // temporary until I resolve cyclePtr/TimeUpdate dependencies.
extern u8 callirq; extern u8 callirq;
FILE *DMA4LogFile=0; static FILE *DMA4LogFile = NULL;
FILE *DMA7LogFile=0; static FILE *DMA7LogFile = NULL;
FILE *ADMA4LogFile=0; static FILE *ADMA4LogFile = NULL;
FILE *ADMA7LogFile=0; static FILE *ADMA7LogFile = NULL;
FILE *ADMAOutLogFile=0; static FILE *ADMAOutLogFile = NULL;
FILE *REGWRTLogFile[2]={0,0}; static FILE *REGWRTLogFile[2] = {0,0};
int packcount=0;
u16* MBASE[2] = {0,0};
u16* DMABaseAddr;
void DMALogOpen() void DMALogOpen()
{ {
@ -56,16 +53,6 @@ void DMA7LogWrite(void *lpData, u32 ulSize) {
fwrite(lpData,ulSize,1,DMA7LogFile); fwrite(lpData,ulSize,1,DMA7LogFile);
} }
void ADMA4LogWrite(void *lpData, u32 ulSize) {
if(!DMALog()) return;
if (!ADMA4LogFile) return;
fwrite(lpData,ulSize,1,ADMA4LogFile);
}
void ADMA7LogWrite(void *lpData, u32 ulSize) {
if(!DMALog()) return;
if (!ADMA7LogFile) return;
fwrite(lpData,ulSize,1,ADMA7LogFile);
}
void ADMAOutLogWrite(void *lpData, u32 ulSize) { void ADMAOutLogWrite(void *lpData, u32 ulSize) {
if(!DMALog()) return; if(!DMALog()) return;
if (!ADMAOutLogFile) return; if (!ADMAOutLogFile) return;
@ -79,118 +66,110 @@ void RegWriteLog(u32 core,u16 value)
fwrite(&value,2,1,REGWRTLogFile[core]); fwrite(&value,2,1,REGWRTLogFile[core]);
} }
void DMALogClose() { void DMALogClose()
if(!DMALog()) return; {
if (DMA4LogFile) fclose(DMA4LogFile); safe_fclose(DMA4LogFile);
if (DMA7LogFile) fclose(DMA7LogFile); safe_fclose(DMA7LogFile);
if (REGWRTLogFile[0]) fclose(REGWRTLogFile[0]); safe_fclose(REGWRTLogFile[0]);
if (REGWRTLogFile[1]) fclose(REGWRTLogFile[1]); safe_fclose(REGWRTLogFile[1]);
if (ADMA4LogFile) fclose(ADMA4LogFile); safe_fclose(ADMA4LogFile);
if (ADMA7LogFile) fclose(ADMA7LogFile); safe_fclose(ADMA7LogFile);
if (ADMAOutLogFile) fclose(ADMAOutLogFile); safe_fclose(ADMAOutLogFile);
} }
void V_Core::LogAutoDMA( FILE* fp )
__forceinline u16 DmaRead(u32 core)
{ {
const u16 ret = (u16)spu2M_Read(Cores[core].TDA); if( !DMALog() || !fp ) return;
Cores[core].TDA++; fwrite( DMAPtr+InputDataProgress, 0x400, 1, fp );
Cores[core].TDA&=0xfffff;
return ret;
} }
__forceinline void DmaWrite(u32 core, u16 value) void V_Core::AutoDMAReadBuffer(int mode) //mode: 0= split stereo; 1 = do not split stereo
{ {
spu2M_Write( Cores[core].TSA, value ); int spos = ((InputPos+0xff)&0x100); //starting position of the free buffer
Cores[core].TSA++;
Cores[core].TSA&=0xfffff;
}
void AutoDMAReadBuffer(int core, int mode) //mode: 0= split stereo; 1 = do not split stereo LogAutoDMA( Index ? ADMA7LogFile : ADMA4LogFile );
{
int spos=((Cores[core].InputPos+0xff)&0x100); //starting position of the free buffer
if(core==0) // HACKFIX!! DMAPtr can be invalid after a savestate load, so the savestate just forces it
ADMA4LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400); // to NULL and we ignore it here. (used to work in old VM editions of PCSX2 with fixed
else // addressing, but new PCSX2s have dynamic memory addressing).
ADMA7LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400);
if(mode) if(mode)
{ {
//hacky :p if( DMAPtr != NULL )
memcpy((ADMATempBuffer+(spos<<1)),DMAPtr+InputDataProgress,0x400);
memcpy((Cores[core].ADMATempBuffer+(spos<<1)),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400); MADR+=0x400;
Cores[core].MADR+=0x400; InputDataLeft-=0x200;
Cores[core].InputDataLeft-=0x200; InputDataProgress+=0x200;
Cores[core].InputDataProgress+=0x200;
} }
else else
{ {
memcpy((Cores[core].ADMATempBuffer+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); if( DMAPtr != NULL )
//memcpy((spu2mem+0x2000+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); memcpy((ADMATempBuffer+spos),DMAPtr+InputDataProgress,0x200);
Cores[core].MADR+=0x200; //memcpy((spu2mem+0x2000+(core<<10)+spos),DMAPtr+InputDataProgress,0x200);
Cores[core].InputDataLeft-=0x100; MADR+=0x200;
Cores[core].InputDataProgress+=0x100; InputDataLeft-=0x100;
InputDataProgress+=0x100;
memcpy((Cores[core].ADMATempBuffer+spos+0x200),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); if( DMAPtr != NULL )
//memcpy((spu2mem+0x2200+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); memcpy((ADMATempBuffer+spos+0x200),DMAPtr+InputDataProgress,0x200);
Cores[core].MADR+=0x200; //memcpy((spu2mem+0x2200+(core<<10)+spos),DMAPtr+InputDataProgress,0x200);
Cores[core].InputDataLeft-=0x100; MADR+=0x200;
Cores[core].InputDataProgress+=0x100; InputDataLeft-=0x100;
InputDataProgress+=0x100;
} }
// See ReadInput at mixer.cpp for explanation on the commented out lines // See ReadInput at mixer.cpp for explanation on the commented out lines
// //
} }
void StartADMAWrite(int core,u16 *pMem, u32 sz) void V_Core::StartADMAWrite(u16 *pMem, u32 sz)
{ {
int size=(sz)&(~511); int size = (sz)&(~511);
if(MsgAutoDMA()) ConLog(" * SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n", if(MsgAutoDMA()) ConLog(" * SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n",
(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff); GetDmaIndexChar(), size<<1, TSA, DMABits, AutoDMACtrl, (~Regs.ATTR)&0x7fff);
Cores[core].InputDataProgress=0; InputDataProgress=0;
if((Cores[core].AutoDMACtrl&(core+1))==0) if((AutoDMACtrl&(Index+1))==0)
{ {
Cores[core].TSA=0x2000+(core<<10); TSA=0x2000+(Index<<10);
Cores[core].DMAICounter=size; DMAICounter=size;
} }
else if(size>=512) else if(size>=512)
{ {
Cores[core].InputDataLeft=size; InputDataLeft=size;
if(Cores[core].AdmaInProgress==0) if(AdmaInProgress==0)
{ {
#ifdef PCM24_S1_INTERLEAVE #ifdef PCM24_S1_INTERLEAVE
if((core==1)&&((PlayMode&8)==8)) if((Index==1)&&((PlayMode&8)==8))
{ {
AutoDMAReadBuffer(core,1); AutoDMAReadBuffer(Index,1);
} }
else else
{ {
AutoDMAReadBuffer(core,0); AutoDMAReadBuffer(Index,0);
} }
#else #else
if(((PlayMode&4)==4)&&(core==0)) if(((PlayMode&4)==4)&&(Index==0))
Cores[0].InputPos=0; Cores[0].InputPos=0;
AutoDMAReadBuffer(core,0); AutoDMAReadBuffer(0);
#endif #endif
if(size==512) if(size==512)
Cores[core].DMAICounter=size; DMAICounter=size;
} }
Cores[core].AdmaInProgress=1; AdmaInProgress=1;
} }
else else
{ {
Cores[core].InputDataLeft=0; InputDataLeft=0;
Cores[core].DMAICounter=1; DMAICounter=1;
} }
Cores[core].TADR=Cores[core].MADR+(size<<1); TADR=MADR+(size<<1);
} }
void DoDMAWrite(int core,u16 *pMem,u32 size) void V_Core::PlainDMAWrite(u16 *pMem, u32 size)
{ {
// Perform an alignment check. // Perform an alignment check.
// Not really important. Everything should work regardless, // Not really important. Everything should work regardless,
@ -198,29 +177,29 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
#if 0 #if 0
uptr pa = ((uptr)pMem)&7; uptr pa = ((uptr)pMem)&7;
uptr pm = Cores[core].TSA&0x7; uptr pm = TSA&0x7;
if( pa ) if( pa )
{ {
fprintf(stderr, "* SPU2 DMA Write > Missaligned SOURCE! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size); fprintf(stderr, "* SPU2 DMA Write > Missaligned SOURCE! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, TSA, TDA, size);
} }
if( pm ) if( pm )
{ {
fprintf(stderr, "* SPU2 DMA Write > Missaligned TARGET! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size ); fprintf(stderr, "* SPU2 DMA Write > Missaligned TARGET! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, TSA, TDA, size );
} }
#endif #endif
if(core==0) if(Index==0)
DMA4LogWrite(pMem,size<<1); DMA4LogWrite(pMem,size<<1);
else else
DMA7LogWrite(pMem,size<<1); DMA7LogWrite(pMem,size<<1);
if(MsgDMA()) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff); if(MsgDMA()) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",GetDmaIndexChar(),size<<1,TSA,DMABits,AutoDMACtrl,(~Regs.ATTR)&0x7fff);
Cores[core].TSA &= 0xfffff; TSA &= 0xfffff;
u32 buff1end = Cores[core].TSA + size; u32 buff1end = TSA + size;
u32 buff2end=0; u32 buff2end=0;
if( buff1end > 0x100000 ) if( buff1end > 0x100000 )
{ {
@ -228,7 +207,7 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
buff1end = 0x100000; buff1end = 0x100000;
} }
const int cacheIdxStart = Cores[core].TSA / pcm_WordsPerBlock; const int cacheIdxStart = TSA / pcm_WordsPerBlock;
const int cacheIdxEnd = (buff1end+pcm_WordsPerBlock-1) / pcm_WordsPerBlock; const int cacheIdxEnd = (buff1end+pcm_WordsPerBlock-1) / pcm_WordsPerBlock;
PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart]; PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart];
PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd]; PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd];
@ -240,14 +219,14 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
} while ( cacheLine != &cacheEnd ); } while ( cacheLine != &cacheEnd );
//ConLog( " * SPU2 : Cache Clear Range! TSA=0x%x, TDA=0x%x (low8=0x%x, high8=0x%x, len=0x%x)\n", //ConLog( " * SPU2 : Cache Clear Range! TSA=0x%x, TDA=0x%x (low8=0x%x, high8=0x%x, len=0x%x)\n",
// Cores[core].TSA, buff1end, flagTSA, flagTDA, clearLen ); // TSA, buff1end, flagTSA, flagTDA, clearLen );
// First Branch needs cleared: // First Branch needs cleared:
// It starts at TSA and goes to buff1end. // It starts at TSA and goes to buff1end.
const u32 buff1size = (buff1end-Cores[core].TSA); const u32 buff1size = (buff1end-TSA);
memcpy( GetMemPtr( Cores[core].TSA ), pMem, buff1size*2 ); memcpy( GetMemPtr( TSA ), pMem, buff1size*2 );
if( buff2end > 0 ) if( buff2end > 0 )
{ {
@ -263,57 +242,50 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
// 0x2800? Hard to know for usre (almost no games depend on this) // 0x2800? Hard to know for usre (almost no games depend on this)
memcpy( GetMemPtr( 0 ), &pMem[buff1size], buff2end*2 ); memcpy( GetMemPtr( 0 ), &pMem[buff1size], buff2end*2 );
Cores[core].TDA = (buff2end+1) & 0xfffff; TDA = (buff2end+1) & 0xfffff;
if(Cores[core].IRQEnable)
{
// Flag interrupt?
// If IRQA occurs between start and dest, flag it.
// Since the buffer wraps, the conditional might seem odd, but it works.
if( ( Cores[core].IRQA >= Cores[core].TSA ) ||
( Cores[core].IRQA < Cores[core].TDA ) )
{
Spdif.Info = 4 << core;
SetIrqCall();
}
}
} }
else else
{ {
// Buffer doesn't wrap/overflow! // Buffer doesn't wrap/overflow!
// Just set the TDA and check for an IRQ... // Just set the TDA and check for an IRQ...
Cores[core].TDA = buff1end; TDA = buff1end;
}
if(Cores[core].IRQEnable) // 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++ )
{
// Note: (start is inclusive, dest exclusive -- fixes DMC1 FMVs)
if( Cores[i].IRQEnable && (Cores[i].IRQA >= Cores[i].TSA) && (Cores[i].IRQA < Cores[i].TDA) )
{ {
// Flag interrupt? Spdif.Info = 4 << i;
// If IRQA occurs between start and dest, flag it. SetIrqCall();
// (start is inclusive, dest exclusive -- fixes DMC1 and hopefully won't break
// other games. ;)
if( ( Cores[core].IRQA >= Cores[core].TSA ) &&
( Cores[core].IRQA < Cores[core].TDA ) )
{
Spdif.Info = 4 << core;
SetIrqCall();
}
} }
} }
Cores[core].TSA=Cores[core].TDA&0xFFFF0; if(IRQEnable)
Cores[core].DMAICounter=size; {
Cores[core].TADR=Cores[core].MADR+(size<<1);
if( ( IRQA >= TSA ) && ( IRQA < TDA ) )
{
Spdif.Info = 4 << Index;
SetIrqCall();
}
}
TSA = TDA & 0xFFFF0;
DMAICounter = size;
TADR = MADR + (size<<1);
} }
void SPU2readDMA(int core, u16* pMem, u32 size) void V_Core::DoDMAread(u16* pMem, u32 size)
{ {
if( cyclePtr != NULL ) TimeUpdate( *cyclePtr ); TSA &= 0xffff8;
Cores[core].TSA &= 0xffff8; u32 buff1end = TSA + size;
u32 buff1end = Cores[core].TSA + size;
u32 buff2end = 0; u32 buff2end = 0;
if( buff1end > 0x100000 ) if( buff1end > 0x100000 )
{ {
@ -321,8 +293,8 @@ void SPU2readDMA(int core, u16* pMem, u32 size)
buff1end = 0x100000; buff1end = 0x100000;
} }
const u32 buff1size = (buff1end-Cores[core].TSA); const u32 buff1size = (buff1end-TSA);
memcpy( pMem, GetMemPtr( Cores[core].TSA ), buff1size*2 ); memcpy( pMem, GetMemPtr( TSA ), buff1size*2 );
// Note on TSA's position after our copy finishes: // Note on TSA's position after our copy finishes:
// IRQA should be measured by the end of the writepos+0x20. But the TDA // IRQA should be measured by the end of the writepos+0x20. But the TDA
@ -335,146 +307,65 @@ void SPU2readDMA(int core, u16* pMem, u32 size)
memcpy( &pMem[buff1size], GetMemPtr( 0 ), buff2end*2 ); memcpy( &pMem[buff1size], GetMemPtr( 0 ), buff2end*2 );
Cores[core].TDA = (buff2end+0x20) & 0xfffff; TDA = (buff2end+0x20) & 0xfffff;
for( int i=0; i<2; i++ )
{
if(Cores[i].IRQEnable)
{
// Flag interrupt?
// If IRQA occurs between start and dest, flag it.
// Since the buffer wraps, the conditional might seem odd, but it works.
if( ( Cores[i].IRQA >= Cores[core].TSA ) ||
( Cores[i].IRQA <= Cores[core].TDA ) )
{
Spdif.Info=4<<i;
SetIrqCall();
}
}
}
} }
else else
{ {
// Buffer doesn't wrap/overflow! // Buffer doesn't wrap/overflow!
// Just set the TDA and check for an IRQ... // Just set the TDA and check for an IRQ...
Cores[core].TDA = (buff1end + 0x20) & 0xfffff; TDA = (buff1end + 0x20) & 0xfffff;
}
for( int i=0; i<2; i++ ) // 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 >= Cores[i].TSA) && (Cores[i].IRQA < Cores[i].TDA) )
{ {
if(Cores[i].IRQEnable) Spdif.Info = 4 << i;
{ SetIrqCall();
// Flag interrupt?
// If IRQA occurs between start and dest, flag it:
if( ( Cores[i].IRQA >= Cores[i].TSA ) &&
( Cores[i].IRQA < Cores[i].TDA ) )
{
Spdif.Info=4<<i;
SetIrqCall();
}
}
} }
} }
TSA = TDA & 0xFFFFF;
Cores[core].TSA=Cores[core].TDA & 0xFFFFF; DMAICounter = size;
Regs.STATX &= ~0x80;
Cores[core].DMAICounter=size; //Regs.ATTR |= 0x30;
Cores[core].Regs.STATX &= ~0x80; TADR = MADR + (size<<1);
//Cores[core].Regs.ATTR |= 0x30;
Cores[core].TADR=Cores[core].MADR+(size<<1);
} }
void SPU2writeDMA(int core, u16* pMem, u32 size) void V_Core::DoDMAwrite(u16* pMem, u32 size)
{ {
if(cyclePtr != NULL) TimeUpdate(*cyclePtr); DMAPtr = pMem;
Cores[core].DMAPtr=pMem;
if(size<2) { if(size<2) {
//if(dma7callback) dma7callback(); //if(dma7callback) dma7callback();
Cores[core].Regs.STATX &= ~0x80; Regs.STATX &= ~0x80;
//Cores[core].Regs.ATTR |= 0x30; //Regs.ATTR |= 0x30;
Cores[core].DMAICounter=1; DMAICounter=1;
return; return;
} }
if( IsDevBuild ) if( IsDevBuild )
DebugCores[core].lastsize = size; DebugCores[Index].lastsize = size;
Cores[core].TSA&=~7; TSA &= ~7;
bool adma_enable = ((Cores[core].AutoDMACtrl&(core+1))==(core+1)); bool adma_enable = ((AutoDMACtrl&(Index+1))==(Index+1));
if(adma_enable) if(adma_enable)
{ {
Cores[core].TSA&=0x1fff; TSA&=0x1fff;
StartADMAWrite(core,pMem,size); StartADMAWrite(pMem,size);
} }
else else
{ {
DoDMAWrite(core,pMem,size); PlainDMAWrite(pMem,size);
} }
Cores[core].Regs.STATX &= ~0x80; Regs.STATX &= ~0x80;
//Cores[core].Regs.ATTR |= 0x30; //Regs.ATTR |= 0x30;
} }
u32 CALLBACK SPU2ReadMemAddr(int core)
{
return Cores[core].MADR;
}
void CALLBACK SPU2WriteMemAddr(int core,u32 value)
{
Cores[core].MADR=value;
}
void CALLBACK SPU2setDMABaseAddr(uptr baseaddr)
{
DMABaseAddr = (u16*)baseaddr;
}
void CALLBACK SPU2readDMA4Mem(u16 *pMem, u32 size) { //size now in 16bit units
FileLog("[%10d] SPU2 readDMA4Mem size %x\n",Cycles, size<<1);
SPU2readDMA(0,pMem,size);
}
void CALLBACK SPU2writeDMA4Mem(u16* pMem, u32 size) { //size now in 16bit units
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
SPU2writeDMA(0,pMem,size);
}
void CALLBACK SPU2interruptDMA4() {
FileLog("[%10d] SPU2 interruptDMA4\n",Cycles);
Cores[0].Regs.STATX |= 0x80;
//Cores[0].Regs.ATTR &= ~0x30;
}
void CALLBACK SPU2readDMA7Mem(u16* pMem, u32 size) {
FileLog("[%10d] SPU2 readDMA7Mem size %x\n",Cycles, size<<1);
SPU2readDMA(1,pMem,size);
}
void CALLBACK SPU2writeDMA7Mem(u16* pMem, u32 size) {
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
SPU2writeDMA(1,pMem,size);
}
void CALLBACK SPU2interruptDMA7() {
FileLog("[%10d] SPU2 interruptDMA7\n",Cycles);
Cores[1].Regs.STATX |= 0x80;
//Cores[1].Regs.ATTR &= ~0x30;
}

View File

@ -1,31 +1,23 @@
//GiGaHeRz's SPU2 Driver /* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com> * Developed and maintained by the Pcsx2 Development Team.
// *
//This library is free software; you can redistribute it and/or * Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
//modify it under the terms of the GNU Lesser General Public *
//License as published by the Free Software Foundation; either * SPU2-X is free software: you can redistribute it and/or modify it under the terms
//version 2.1 of the License, or (at your option) any later version. * 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.
//This library is distributed in the hope that it will be useful, *
//but WITHOUT ANY WARRANTY; without even the implied warranty of * SPU2-X is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//Lesser General Public License for more details. * PURPOSE. See the GNU Lesser General Public License for more details.
// *
//You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public License
//License along with this library; if not, write to the Free Software * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
//
#ifndef DMA_H_INCLUDED
#define DMA_H_INCLUDED
void DMALogOpen(); #pragma once
void DMA4LogWrite(void *lpData, u32 ulSize);
void DMA7LogWrite(void *lpData, u32 ulSize);
void DMALogClose();
extern void DmaWrite(u32 core, u16 data); extern void DMALogOpen();
extern u16 DmaRead(u32 core); extern void DMA4LogWrite(void *lpData, u32 ulSize);
extern void DMA7LogWrite(void *lpData, u32 ulSize);
extern void AutoDMAReadBuffer(int core, int mode); extern void DMALogClose();
#endif // DMA_H_INCLUDED //

110
plugins/spu2-x/src/Global.h Normal file
View File

@ -0,0 +1,110 @@
/* 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_
struct StereoOut16;
struct StereoOut32;
struct StereoOutFloat;
struct V_Core;
namespace soundtouch
{
class SoundTouch;
}
#include <assert.h>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cstdarg>
#include <cmath>
#include <ctime>
#include <stdexcept>
#include <string>
#include <algorithm>
using std::string;
using std::wstring;
#include "Pcsx2Types.h"
namespace VersionInfo
{
static const u8 Release = 1;
static const u8 Revision = 3; // 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 );
}
extern void SysMessage(const char *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 DevCon Console
# define DevMsg MsgBox
#else
# define DevCon 0&&Console
# define DevMsg
#endif
#ifdef PCSX2_DEBUG
# define DbgCon Console
#else
# define DbgCon 0&&Console
#endif
#ifdef PCSX2_DEVBUILD
# define SPU2_LOG
#endif
#include "Utilities/Exceptions.h"
#include "Utilities/SafeArray.h"
#include "ConvertUTF.h"
#include "defs.h"
#include "regs.h"
#include "Config.h"
#include "Debug.h"
#include "SndOut.h"
#endif

View File

@ -1,8 +1,8 @@
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2 /* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
* Developed and maintained by the Pcsx2 Development Team. * Developed and maintained by the Pcsx2 Development Team.
* *
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz] * 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 * 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- * 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. * ation, either version 3 of the License, or (at your option) any later version.
@ -14,95 +14,95 @@
* You should have received a copy of the GNU Lesser General Public License * 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/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Spu2.h" #include "Spu2.h"
#include "Dialogs.h" #include "Dialogs.h"
bool DebugEnabled=false; bool DebugEnabled=false;
bool _MsgToConsole=false; bool _MsgToConsole=false;
bool _MsgKeyOnOff=false; bool _MsgKeyOnOff=false;
bool _MsgVoiceOff=false; bool _MsgVoiceOff=false;
bool _MsgDMA=false; bool _MsgDMA=false;
bool _MsgAutoDMA=false; bool _MsgAutoDMA=false;
bool _MsgOverruns=false; bool _MsgOverruns=false;
bool _MsgCache=false; bool _MsgCache=false;
bool _AccessLog=false; bool _AccessLog=false;
bool _DMALog=false; bool _DMALog=false;
bool _WaveLog=false; bool _WaveLog=false;
bool _CoresDump=false; bool _CoresDump=false;
bool _MemDump=false; bool _MemDump=false;
bool _RegDump=false; bool _RegDump=false;
wchar_t AccessLogFileName[255]; wchar_t AccessLogFileName[255];
wchar_t WaveLogFileName[255]; wchar_t WaveLogFileName[255];
wchar_t DMA4LogFileName[255]; wchar_t DMA4LogFileName[255];
wchar_t DMA7LogFileName[255]; wchar_t DMA7LogFileName[255];
wchar_t CoresDumpFileName[255]; wchar_t CoresDumpFileName[255];
wchar_t MemDumpFileName[255]; wchar_t MemDumpFileName[255];
wchar_t RegDumpFileName[255]; wchar_t RegDumpFileName[255];
#ifdef SPU2X_DEVBUILD #ifdef PCSX2_DEVBUILD
static const int LATENCY_MAX = 3000; static const int LATENCY_MAX = 3000;
#else #else
static const int LATENCY_MAX = 750; static const int LATENCY_MAX = 750;
#endif #endif
static const int LATENCY_MIN = 40; static const int LATENCY_MIN = 40;
int AutoDMAPlayRate[2] = {0,0}; int AutoDMAPlayRate[2] = {0,0};
// MIXING // MIXING
int Interpolation = 1; int Interpolation = 1;
/* values: /* values:
0: no interpolation (use nearest) 0: no interpolation (use nearest)
1. linear interpolation 1. linear interpolation
2. cubic interpolation 2. cubic interpolation
*/ */
bool EffectsDisabled = false; bool EffectsDisabled = false;
// OUTPUT // OUTPUT
int SndOutLatencyMS = 160; int SndOutLatencyMS = 160;
bool timeStretchDisabled = false; bool timeStretchDisabled = false;
u32 OutputModule = 0; u32 OutputModule = 0;
CONFIG_DSOUNDOUT Config_DSoundOut; CONFIG_DSOUNDOUT Config_DSoundOut;
CONFIG_WAVEOUT Config_WaveOut; CONFIG_WAVEOUT Config_WaveOut;
CONFIG_XAUDIO2 Config_XAudio2; CONFIG_XAUDIO2 Config_XAudio2;
// DSP // DSP
bool dspPluginEnabled = false; bool dspPluginEnabled = false;
int dspPluginModule = 0; int dspPluginModule = 0;
wchar_t dspPlugin[256]; wchar_t dspPlugin[256];
bool StereoExpansionEnabled = false; bool StereoExpansionEnabled = false;
/*****************************************************************************/ /*****************************************************************************/
void ReadSettings() void ReadSettings()
{ {
} }
/*****************************************************************************/ /*****************************************************************************/
void WriteSettings() void WriteSettings()
{ {
} }
void configure() void configure()
{ {
ReadSettings(); ReadSettings();
} }
void MessageBox(char const*, ...) void MessageBox(char const*, ...)
{ {
} }

View File

@ -103,8 +103,6 @@ public:
protected: protected:
static void ClampValues(); static void ClampValues();
//static bool CALLBACK DialogProc(uptr hWnd,u32 uMsg,WPARAM wParam,LPARAM lParam);
}; };

View File

@ -1,8 +1,8 @@
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2 /* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
* Developed and maintained by the Pcsx2 Development Team. * Developed and maintained by the Pcsx2 Development Team.
* *
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz] * 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 * 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- * 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. * ation, either version 3 of the License, or (at your option) any later version.
@ -14,46 +14,46 @@
* You should have received a copy of the GNU Lesser General Public License * 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/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Linux.h" #include "Linux.h"
void SysMessage(char *fmt, ...) { void SysMessage(char *fmt, ...) {
GtkWidget *Ok,*Txt; GtkWidget *Ok,*Txt;
GtkWidget *Box,*Box1; GtkWidget *Box,*Box1;
va_list list; va_list list;
char msg[512]; char msg[512];
va_start(list, fmt); va_start(list, fmt);
vsprintf(msg, fmt, list); vsprintf(msg, fmt, list);
va_end(list); va_end(list);
if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0;
MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(MsgDlg), "SPU2null Msg"); gtk_window_set_title(GTK_WINDOW(MsgDlg), "SPU2null Msg");
gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5);
Box = gtk_vbox_new(5, 0); Box = gtk_vbox_new(5, 0);
gtk_container_add(GTK_CONTAINER(MsgDlg), Box); gtk_container_add(GTK_CONTAINER(MsgDlg), Box);
gtk_widget_show(Box); gtk_widget_show(Box);
Txt = gtk_label_new(msg); Txt = gtk_label_new(msg);
gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5);
gtk_widget_show(Txt); gtk_widget_show(Txt);
Box1 = gtk_hbutton_box_new(); Box1 = gtk_hbutton_box_new();
gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0);
gtk_widget_show(Box1); gtk_widget_show(Box1);
Ok = gtk_button_new_with_label("Ok"); Ok = gtk_button_new_with_label("Ok");
gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL);
gtk_container_add(GTK_CONTAINER(Box1), Ok); gtk_container_add(GTK_CONTAINER(Box1), Ok);
GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT);
gtk_widget_show(Ok); gtk_widget_show(Ok);
gtk_widget_show(MsgDlg); gtk_widget_show(MsgDlg);
gtk_main(); gtk_main();
} }

View File

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

View File

@ -1,30 +1,44 @@
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2 /* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
* Developed and maintained by the Pcsx2 Development Team. * Developed and maintained by the Pcsx2 Development Team.
* *
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz] * 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 * 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- * 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. * 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; * 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 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more details. * PURPOSE. See the GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * 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/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "BaseTypes.h" template< typename FloatType >
struct LowPassFilter
struct LPF_data
{ {
double coef[9]; FloatType coef[9];
double d[4]; FloatType d[4];
LPF_data( double freq, double srate ); LowPassFilter( FloatType freq, FloatType srate );
double sample( double inval ); FloatType sample( FloatType inval );
}; };
struct LowPassFilter32
{
LowPassFilter<float> impl_lpf;
LowPassFilter32( float freq, float srate );
float sample( float inval );
};
struct LowPassFilter64
{
LowPassFilter<double> impl_lpf;
LowPassFilter64( double freq, double srate );
double sample( double inval );
};

View File

@ -15,8 +15,8 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Spu2.h" #include "Global.h"
#include <float.h> //#include <float.h>
extern void spdif_update(); extern void spdif_update();
@ -477,22 +477,9 @@ static s32 __forceinline __fastcall GetNoiseValues( V_Core& thiscore, uint voice
///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////
// // // //
static __forceinline StereoOut32 ReadInputPV( uint core ) __forceinline StereoOut32 V_Core::ReadInputPV()
{ {
V_Core& thiscore( Cores[core] ); return ApplyVolume( ReadInput(), InpVol );
u32 pitch = AutoDMAPlayRate[core];
if(pitch==0) pitch=48000;
thiscore.ADMAPV += pitch;
while(thiscore.ADMAPV>=48000)
{
ReadInput( core, thiscore.ADMAP );
thiscore.ADMAPV -= 48000;
}
// Apply volumes:
return ApplyVolume( thiscore.ADMAP, thiscore.InpVol );
} }
///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////
@ -547,7 +534,7 @@ static __forceinline StereoOut32 MixVoice( uint coreidx, uint voiceidx )
vc.OutX = Value; vc.OutX = Value;
if( IsDevBuild ) if( IsDevBuild )
DebugCores[coreidx].Voices[voiceidx].displayPeak = max(DebugCores[coreidx].Voices[voiceidx].displayPeak,abs(vc.OutX)); DebugCores[coreidx].Voices[voiceidx].displayPeak = std::max(DebugCores[coreidx].Voices[voiceidx].displayPeak,abs(vc.OutX));
// Write-back of raw voice data (post ADSR applied) // Write-back of raw voice data (post ADSR applied)
@ -567,19 +554,6 @@ static __forceinline StereoOut32 MixVoice( uint coreidx, uint voiceidx )
} }
} }
struct VoiceMixSet
{
static const VoiceMixSet Empty;
StereoOut32 Dry, Wet;
VoiceMixSet() {}
VoiceMixSet( const StereoOut32& dry, const StereoOut32& wet ) :
Dry( dry ),
Wet( wet )
{
}
};
const VoiceMixSet VoiceMixSet::Empty( (StereoOut32()), (StereoOut32()) ); // Don't use SteroOut32::Empty because C++ doesn't make any dep/order checks on global initializers. 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 ) static __forceinline void MixCoreVoices( VoiceMixSet& dest, const uint coreidx )
@ -599,61 +573,60 @@ static __forceinline void MixCoreVoices( VoiceMixSet& dest, const uint coreidx )
} }
} }
static StereoOut32 __fastcall MixCore( const uint coreidx, const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext ) StereoOut32 V_Core::Mix( const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext )
{ {
V_Core& thiscore( Cores[coreidx] ); MasterVol.Update();
thiscore.MasterVol.Update();
// Saturate final result to standard 16 bit range. // Saturate final result to standard 16 bit range.
const VoiceMixSet Voices( clamp_mix( inVoices.Dry ), clamp_mix( inVoices.Wet ) ); const VoiceMixSet Voices( clamp_mix( inVoices.Dry ), clamp_mix( inVoices.Wet ) );
// Write Mixed results To Output Area // Write Mixed results To Output Area
spu2M_WriteFast( 0x1000 + (coreidx<<12) + OutPos, Voices.Dry.Left ); spu2M_WriteFast( 0x1000 + (Index<<12) + OutPos, Voices.Dry.Left );
spu2M_WriteFast( 0x1200 + (coreidx<<12) + OutPos, Voices.Dry.Right ); spu2M_WriteFast( 0x1200 + (Index<<12) + OutPos, Voices.Dry.Right );
spu2M_WriteFast( 0x1400 + (coreidx<<12) + OutPos, Voices.Wet.Left ); spu2M_WriteFast( 0x1400 + (Index<<12) + OutPos, Voices.Wet.Left );
spu2M_WriteFast( 0x1600 + (coreidx<<12) + OutPos, Voices.Wet.Right ); spu2M_WriteFast( 0x1600 + (Index<<12) + OutPos, Voices.Wet.Right );
// Write mixed results to logfile (if enabled) // Write mixed results to logfile (if enabled)
WaveDump::WriteCore( coreidx, CoreSrc_DryVoiceMix, Voices.Dry ); WaveDump::WriteCore( Index, CoreSrc_DryVoiceMix, Voices.Dry );
WaveDump::WriteCore( coreidx, CoreSrc_WetVoiceMix, Voices.Wet ); WaveDump::WriteCore( Index, CoreSrc_WetVoiceMix, Voices.Wet );
// Mix in the Input data // Mix in the Input data
StereoOut32 TD( StereoOut32 TD(
Input.Left & thiscore.DryGate.InpL, Input.Left & DryGate.InpL,
Input.Right & thiscore.DryGate.InpR Input.Right & DryGate.InpR
); );
// Mix in the Voice data // Mix in the Voice data
TD.Left += Voices.Dry.Left & thiscore.DryGate.SndL; TD.Left += Voices.Dry.Left & DryGate.SndL;
TD.Right += Voices.Dry.Right & thiscore.DryGate.SndR; TD.Right += Voices.Dry.Right & DryGate.SndR;
// Mix in the External (nothing/core0) data // Mix in the External (nothing/core0) data
TD.Left += Ext.Left & thiscore.DryGate.ExtL; TD.Left += Ext.Left & DryGate.ExtL;
TD.Right += Ext.Right & thiscore.DryGate.ExtR; TD.Right += Ext.Right & DryGate.ExtR;
if( !EffectsDisabled ) if( !EffectsDisabled )
{ {
//Reverb pointer advances regardless of the FxEnable bit... //Reverb pointer advances regardless of the FxEnable bit...
Reverb_AdvanceBuffer( thiscore ); Reverb_AdvanceBuffer();
if( thiscore.FxEnable ) if( FxEnable )
{ {
// Mix Input, Voice, and External data: // Mix Input, Voice, and External data:
StereoOut32 TW( StereoOut32 TW(
Input.Left & thiscore.WetGate.InpL, Input.Left & WetGate.InpL,
Input.Right & thiscore.WetGate.InpR Input.Right & WetGate.InpR
); );
TW.Left += Voices.Wet.Left & thiscore.WetGate.SndL; TW.Left += Voices.Wet.Left & WetGate.SndL;
TW.Right += Voices.Wet.Right & thiscore.WetGate.SndR; TW.Right += Voices.Wet.Right & WetGate.SndR;
TW.Left += Ext.Left & thiscore.WetGate.ExtL; TW.Left += Ext.Left & WetGate.ExtL;
TW.Right += Ext.Right & thiscore.WetGate.ExtR; TW.Right += Ext.Right & WetGate.ExtR;
WaveDump::WriteCore( coreidx, CoreSrc_PreReverb, TW ); WaveDump::WriteCore( Index, CoreSrc_PreReverb, TW );
StereoOut32 RV( DoReverb( thiscore, TW ) ); StereoOut32 RV( DoReverb( TW ) );
// Volume boost after effects application. Boosting volume prior to effects // Volume boost after effects application. Boosting volume prior to effects
// causes slight overflows in some games, and the volume boost is required. // causes slight overflows in some games, and the volume boost is required.
@ -663,15 +636,15 @@ static StereoOut32 __fastcall MixCore( const uint coreidx, const VoiceMixSet& in
RV.Left *= 2; RV.Left *= 2;
RV.Right *= 2; RV.Right *= 2;
WaveDump::WriteCore( coreidx, CoreSrc_PostReverb, RV ); WaveDump::WriteCore( Index, CoreSrc_PostReverb, RV );
// Mix Dry+Wet // Mix Dry+Wet
return TD + ApplyVolume( RV, thiscore.FxVol ); return TD + ApplyVolume( RV, FxVol );
} }
else else
{ {
WaveDump::WriteCore( coreidx, CoreSrc_PreReverb, 0, 0 ); WaveDump::WriteCore( Index, CoreSrc_PreReverb, 0, 0 );
WaveDump::WriteCore( coreidx, CoreSrc_PostReverb, 0, 0 ); WaveDump::WriteCore( Index, CoreSrc_PostReverb, 0, 0 );
} }
} }
return TD; return TD;
@ -685,8 +658,8 @@ __forceinline void Mix()
// Note: Playmode 4 is SPDIF, which overrides other inputs. // Note: Playmode 4 is SPDIF, which overrides other inputs.
StereoOut32 InputData[2] = StereoOut32 InputData[2] =
{ {
(PlayMode&4) ? StereoOut32::Empty : ReadInputPV( 0 ), (PlayMode&4) ? StereoOut32::Empty : Cores[0].ReadInputPV(),
(PlayMode&8) ? StereoOut32::Empty : ReadInputPV( 1 ) (PlayMode&8) ? StereoOut32::Empty : Cores[1].ReadInputPV()
}; };
WaveDump::WriteCore( 0, CoreSrc_Input, InputData[0] ); WaveDump::WriteCore( 0, CoreSrc_Input, InputData[0] );
@ -697,7 +670,7 @@ __forceinline void Mix()
MixCoreVoices( VoiceData[0], 0 ); MixCoreVoices( VoiceData[0], 0 );
MixCoreVoices( VoiceData[1], 1 ); MixCoreVoices( VoiceData[1], 1 );
StereoOut32 Ext( MixCore( 0, VoiceData[0], InputData[0], StereoOut32::Empty ) ); StereoOut32 Ext( Cores[0].Mix( VoiceData[0], InputData[0], StereoOut32::Empty ) );
if( (PlayMode & 4) || (Cores[0].Mute!=0) ) if( (PlayMode & 4) || (Cores[0].Mute!=0) )
Ext = StereoOut32::Empty; Ext = StereoOut32::Empty;
@ -714,14 +687,14 @@ __forceinline void Mix()
WaveDump::WriteCore( 0, CoreSrc_External, Ext ); WaveDump::WriteCore( 0, CoreSrc_External, Ext );
ApplyVolume( Ext, Cores[1].ExtVol ); ApplyVolume( Ext, Cores[1].ExtVol );
StereoOut32 Out( MixCore( 1, VoiceData[1], InputData[1], Ext ) ); StereoOut32 Out( Cores[1].Mix( VoiceData[1], InputData[1], Ext ) );
if( PlayMode & 8 ) if( PlayMode & 8 )
{ {
// Experimental CDDA support // Experimental CDDA support
// The CDDA overrides all other mixer output. It's a direct feed! // The CDDA overrides all other mixer output. It's a direct feed!
ReadInput( 1, Out ); Out = Cores[1].ReadInput();
//WaveLog::WriteCore( 1, "CDDA-32", OutL, OutR ); //WaveLog::WriteCore( 1, "CDDA-32", OutL, OutR );
} }
else else

View File

@ -0,0 +1,62 @@
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
* Developed and maintained by the Pcsx2 Development Team.
*
* 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
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 StereoOut32& right ) const
{
return StereoOut32(
Left + right.Left,
Right + right.Right
);
}
StereoOut32 operator/( int src ) const
{
return StereoOut32( Left / src, Right / src );
}
};
extern void Mix();
extern s32 clamp_mix( s32 x, u8 bitshift=0 );
extern s32 MulShr32( s32 srcval, s32 mulval );
extern StereoOut32 clamp_mix( const StereoOut32& sample, u8 bitshift=0 );

View File

@ -15,33 +15,40 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Spu2.h" #include "Global.h"
#include "PS2E-spu2.h"
#include "dma.h"
#include "Dialogs.h" #include "Dialogs.h"
#include "RegTable.h" #include "RegTable.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#include "svnrev.h" # include "svnrev.h"
#else
#include <stdio.h>
#include <string.h>
#endif #endif
// [Air]: Adding the spu2init boolean wasn't necessary except to help me in // PCSX2 expects ASNI, not unicode, so this MUST always be char...
// debugging the spu2 suspend/resume behavior (when user hits escape).
static bool spu2open=false; // has spu2open plugin interface been called?
static bool spu2init=false; // has spu2init plugin interface been called?
//static s32 logvolume[16384];
static u32 pClocks=0;
// Pcsx2 expects ASNI, not unicode, so this MUST always be char...
static char libraryName[256]; static char libraryName[256];
static bool IsOpened = false;
static bool IsInitialized = false;
static u32 pClocks = 0;
u32* cyclePtr = NULL;
u32 lClocks = 0;
#ifdef _MSC_VER #ifdef _MSC_VER
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD dwReason,LPVOID lpvReserved) HINSTANCE hInstance;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{ {
if( dwReason == DLL_PROCESS_ATTACH ) if( dwReason == DLL_PROCESS_ATTACH )
hInstance = hinstDLL; hInstance = hinstDLL;
else if( dwReason == DLL_PROCESS_DETACH )
{
// TODO : perform shutdown procedure, just in case PCSX2 itself failed
// to for some reason..
}
return TRUE; return TRUE;
} }
#endif #endif
@ -106,7 +113,7 @@ EXPORT_C_(char*) PS2EgetLibName()
EXPORT_C_(u32) PS2EgetLibVersion2(u32 type) EXPORT_C_(u32) PS2EgetLibVersion2(u32 type)
{ {
return (VersionInfo::PluginApi<<16) | (VersionInfo::Release<<8) | VersionInfo::Revision; return (PS2E_SPU2_VERSION<<16) | (VersionInfo::Release<<8) | VersionInfo::Revision;
} }
EXPORT_C_(void) SPU2configure() EXPORT_C_(void) SPU2configure()
@ -126,6 +133,87 @@ EXPORT_C_(s32) SPU2test()
return SndBuffer::Test(); return SndBuffer::Test();
} }
// --------------------------------------------------------------------------------------
// 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 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()
{
if( cyclePtr != NULL ) TimeUpdate( *cyclePtr );
FileLog("[%10d] SPU2 interruptDMA4\n",Cycles);
Cores[0].Regs.STATX |= 0x80;
//Cores[0].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_(void) CALLBACK SPU2interruptDMA7()
{
if( cyclePtr != NULL ) TimeUpdate( *cyclePtr );
FileLog("[%10d] SPU2 interruptDMA7\n",Cycles);
Cores[1].Regs.STATX |= 0x80;
//Cores[1].Regs.ATTR &= ~0x30;
}
EXPORT_C_(s32) SPU2init() EXPORT_C_(s32) SPU2init()
{ {
#define MAKESURE(a,b) \ #define MAKESURE(a,b) \
@ -147,13 +235,13 @@ EXPORT_C_(s32) SPU2init()
#endif #endif
srand((unsigned)time(NULL)); srand((unsigned)time(NULL));
if (spu2init) if (IsInitialized)
{ {
ConLog( " * SPU2: Already initialized - Ignoring SPU2init signal." ); ConLog( " * SPU2: Already initialized - Ignoring SPU2init signal." );
return 0; return 0;
} }
spu2init=true; IsInitialized = true;
spu2regs = (short*)malloc(0x010000); spu2regs = (short*)malloc(0x010000);
_spu2mem = (short*)malloc(0x200000); _spu2mem = (short*)malloc(0x200000);
@ -181,8 +269,8 @@ EXPORT_C_(s32) SPU2init()
} }
} }
memset(spu2regs,0,0x010000); memset(spu2regs, 0, 0x010000);
memset(_spu2mem,0,0x200000); memset(_spu2mem, 0, 0x200000);
Cores[0].Reset(); Cores[0].Reset();
Cores[1].Reset(); Cores[1].Reset();
@ -217,7 +305,7 @@ EXPORT_C_(s32) SPU2init()
EXPORT_C_(s32) SPU2open(void *pDsp) EXPORT_C_(s32) SPU2open(void *pDsp)
{ {
if( spu2open ) return 0; if( IsOpened ) return 0;
FileLog("[%10d] SPU2 Open\n",Cycles); FileLog("[%10d] SPU2 Open\n",Cycles);
@ -229,7 +317,7 @@ EXPORT_C_(s32) SPU2open(void *pDsp)
debugDialogOpen=1; debugDialogOpen=1;
}*/ }*/
spu2open = true; IsOpened = true;
try try
{ {
SndBuffer::Init(); SndBuffer::Init();
@ -247,7 +335,9 @@ EXPORT_C_(s32) SPU2open(void *pDsp)
EXPORT_C_(void) SPU2close() EXPORT_C_(void) SPU2close()
{ {
if( !spu2open ) return; if( !IsOpened ) return;
IsOpened = false;
FileLog("[%10d] SPU2 Close\n",Cycles); FileLog("[%10d] SPU2 Close\n",Cycles);
#ifndef __LINUX__ #ifndef __LINUX__
@ -255,13 +345,12 @@ EXPORT_C_(void) SPU2close()
#endif #endif
spdif_shutdown(); spdif_shutdown();
SndBuffer::Cleanup(); SndBuffer::Cleanup();
spu2open = false;
} }
EXPORT_C_(void) SPU2shutdown() EXPORT_C_(void) SPU2shutdown()
{ {
if(!spu2init) return; if(!IsInitialized) return;
IsInitialized = false;
ConLog( " * SPU2: Shutting down.\n" ); ConLog( " * SPU2: Shutting down.\n" );
@ -285,12 +374,9 @@ EXPORT_C_(void) SPU2shutdown()
DMALogClose(); DMALogClose();
spu2init = false; safe_free(spu2regs);
safe_free(_spu2mem);
SAFE_FREE(spu2regs); safe_free( pcm_cache_data );
SAFE_FREE(_spu2mem);
SAFE_FREE( pcm_cache_data );
spu2regs = NULL; spu2regs = NULL;
_spu2mem = NULL; _spu2mem = NULL;
@ -312,32 +398,8 @@ bool numpad_plus = false, numpad_plus_old = false;
EXPORT_C_(void) SPU2async(u32 cycles) EXPORT_C_(void) SPU2async(u32 cycles)
{ {
if( IsDevBuild )
{
u32 oldClocks = lClocks;
static u32 timer=0,time1=0,time2=0;
timer++;
if (timer == 1){
time1=timeGetTime();
}
if (timer == 3000){
time2 = timeGetTime()-time1 ;
timer=0;
}
}
DspUpdate(); DspUpdate();
if( IsDevBuild )
{
/*numpad_plus = (GetAsyncKeyState(VK_ADD)&0x8000)!=0;
if(numpad_plus && !numpad_plus_old)
{
DoFullDump();
}
numpad_plus_old = numpad_plus;*/
}
if(cyclePtr != NULL) if(cyclePtr != NULL)
{ {
TimeUpdate( *cyclePtr ); TimeUpdate( *cyclePtr );
@ -366,7 +428,7 @@ EXPORT_C_(u16) SPU2read(u32 rmem)
if(rmem==0x1f9001AC) if(rmem==0x1f9001AC)
{ {
ret = DmaRead(core); ret = Cores[core].DmaRead();
} }
else else
{ {
@ -375,7 +437,7 @@ EXPORT_C_(u16) SPU2read(u32 rmem)
if (rmem>>16 == 0x1f80) if (rmem>>16 == 0x1f80)
{ {
ret = SPU_ps1_read(rmem); ret = Cores[0].ReadRegPS1(rmem);
} }
else if( (mem&0xFFFF) >= 0x800 ) else if( (mem&0xFFFF) >= 0x800 )
{ {
@ -400,44 +462,19 @@ EXPORT_C_(void) SPU2write(u32 rmem, u16 value)
s2r_writereg(Cycles,rmem,value); s2r_writereg(Cycles,rmem,value);
#endif #endif
if(rmem==0x1f9001ac) // 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
//RegWriteLog(0,value); // incorrect pitches and loop lengths.
if((Cores[0].IRQEnable)&&(Cores[0].TSA==Cores[0].IRQA))
{ if( cyclePtr != NULL )
Spdif.Info=4; TimeUpdate( *cyclePtr );
SetIrqCall();
} if (rmem>>16 == 0x1f80)
spu2M_Write( Cores[0].TSA++, value ); Cores[0].WriteRegPS1(rmem,value);
Cores[0].TSA&=0xfffff;
}
else if(rmem==0x1f9005ac)
{
//RegWriteLog(1,value);
if((Cores[0].IRQEnable)&&(Cores[0].TSA==Cores[0].IRQA))
{
Spdif.Info=4;
SetIrqCall();
}
spu2M_Write( Cores[1].TSA++, value );
Cores[1].TSA&=0xfffff;
}
else else
{ {
// Note: Reverb/Effects are very sensitive to having precise update timings. SPU2writeLog( "write", rmem, value );
// If the SPU2 isn't in in sync with the IOP, samples can end up playing at rather SPU2_FastWrite( rmem, value );
// incorrect pitches and loop lengths.
if( cyclePtr != NULL )
TimeUpdate( *cyclePtr );
if (rmem>>16 == 0x1f80)
SPU_ps1_write(rmem,value);
else
{
SPU2writeLog( "write", rmem, value );
SPU2_FastWrite( rmem, value );
}
} }
} }
@ -453,3 +490,29 @@ EXPORT_C_(int) SPU2setupRecording(int start, void* pData)
return 0; return 0;
} }
EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data)
{
if( mode == FREEZE_SIZE )
{
data->size = Savestate::SizeIt();
return 0;
}
jASSUME( mode == FREEZE_LOAD || mode == FREEZE_SAVE );
jASSUME( data != NULL );
if( data->data == NULL ) return -1;
Savestate::DataBlock& spud = (Savestate::DataBlock&)*(data->data);
switch( mode )
{
case FREEZE_LOAD: return Savestate::ThawIt( spud );
case FREEZE_SAVE: return Savestate::FreezeIt( spud );
jNO_DEFAULT;
}
// technically unreachable, but kills a warning:
return 0;
}

View File

@ -0,0 +1,92 @@
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
* Developed and maintained by the Pcsx2 Development Team.
*
* 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 __LINUX__
//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" __declspec(dllexport) type CALLBACK
#else
#define EXPORT_C_(type) extern "C" type
#endif
// We have our own versions that have the DLLExport attribute configured:
EXPORT_C_(s32) SPU2init();
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);
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);
// 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_(void) SPU2setDMABaseAddr(uptr baseaddr);
EXPORT_C_(void) SPU2interruptDMA7();
EXPORT_C_(u32) SPU2ReadMemAddr(int core);
EXPORT_C_(void) SPU2WriteMemAddr(int core,u32 value);
EXPORT_C_(void) 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
EXPORT_C_(int) SPU2setupRecording(int start, void* pData);
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 double srate_pv;
extern s16 *input_data;
extern u32 input_data_ptr;
extern int recording;
extern u32 lClocks;
extern u32* cyclePtr;
extern void SPU2writeLog( const char* action, u32 rmem, u16 value );
extern void TimeUpdate(u32 cClocks);
extern void SPU2_FastWrite( u32 rmem, u16 value );
extern void LowPassFilterInit();
//#define PCM24_S1_INTERLEAVE

View File

@ -0,0 +1,2 @@
#include "Global.h"

View File

@ -15,172 +15,138 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Spu2.h" #include "Global.h"
#include "dma.h"
void __fastcall ReadInput( uint core, StereoOut32& PData ) // 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.
//
__forceinline StereoOut32 V_Core::ReadInput_HiFi( bool isCDDA )
{ {
V_Core& thiscore( Cores[core] ); InputPos &= ~1;
if((thiscore.AutoDMACtrl&(core+1))==(core+1)) #ifdef PCM24_S1_INTERLEAVE
StereoOut32 retval(
*((s32*)(ADMATempBuffer+(InputPos<<1))),
*((s32*)(ADMATempBuffer+(InputPos<<1)+2))
);
#else
StereoOut32 retval(
(s32&)(ADMATempBuffer[InputPos]),
(s32&)(ADMATempBuffer[InputPos+0x200])
);
#endif
if( isCDDA )
{ {
s32 tl,tr; //give 30 bit data (SndOut downsamples the rest of the way)
retval.Left >>= 2;
if((core==1)&&((PlayMode&8)==8)) retval.Right >>= 2;
}
InputPos += 2;
//if( (InputPos==0x100) || (InputPos>=0x200) ) // CDDA mode?
if( InputPos >= 0x200 )
{
AdmaInProgress = 0;
if(InputDataLeft >= 0x200)
{ {
thiscore.InputPos&=~1; u8 k = (InputDataLeft >= InputDataProgress);
// CDDA mode
// Source audio data is 32 bits.
// We don't yet have the capability to handle this high res input data
// so we just downgrade it to 16 bits for now.
#ifdef PCM24_S1_INTERLEAVE #ifdef PCM24_S1_INTERLEAVE
*PData.Left=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)))); AutoDMAReadBuffer(1);
*PData.Right=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)+2)));
#else #else
s32 *pl=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos]); AutoDMAReadBuffer(0);
s32 *pr=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos+0x200]);
PData.Left = *pl;
PData.Right = *pr;
#endif #endif
AdmaInProgress = 1;
PData.Left >>= 2; //give 30 bit data (SndOut downsamples the rest of the way) TSA = (Index<<10) + InputPos;
PData.Right >>= 2;
thiscore.InputPos+=2; if (InputDataLeft < 0x200)
if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) {
thiscore.AdmaInProgress=0;
if(thiscore.InputDataLeft>=0x200)
{
u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress;
#ifdef PCM24_S1_INTERLEAVE
AutoDMAReadBuffer(core,1);
#else
AutoDMAReadBuffer(core,0);
#endif
thiscore.AdmaInProgress=1;
thiscore.TSA=(core<<10)+thiscore.InputPos;
if (thiscore.InputDataLeft<0x200)
{
FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7');
if( IsDevBuild )
{
if(thiscore.InputDataLeft>0)
{
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
}
thiscore.InputDataLeft=0;
thiscore.DMAICounter=1;
}
}
thiscore.InputPos&=0x1ff;
}
}
else if((core==0)&&((PlayMode&4)==4))
{
thiscore.InputPos&=~1;
s32 *pl=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos]);
s32 *pr=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos+0x200]);
PData.Left = *pl;
PData.Right = *pr;
thiscore.InputPos+=2;
if(thiscore.InputPos>=0x200) {
thiscore.AdmaInProgress=0;
if(thiscore.InputDataLeft>=0x200)
{
u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress;
AutoDMAReadBuffer(core,0);
thiscore.AdmaInProgress=1;
thiscore.TSA=(core<<10)+thiscore.InputPos;
if (thiscore.InputDataLeft<0x200)
{
FileLog("[%10d] Spdif AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7');
if( IsDevBuild )
{
if(thiscore.InputDataLeft>0)
{
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
}
thiscore.InputDataLeft=0;
thiscore.DMAICounter=1;
}
}
thiscore.InputPos&=0x1ff;
}
}
else
{
if((core==1)&&((PlayMode&2)!=0))
{ {
tl=0; FileLog("[%10d] %s AutoDMA%c block end.\n", isCDDA ? "CDDA" : "SPDIF", Cycles, GetDmaIndexChar());
tr=0;
}
else
{
// Using the temporary buffer because this area gets overwritten by some other code.
//*PData.Left = (s32)*(s16*)(spu2mem+0x2000+(core<<10)+thiscore.InputPos);
//*PData.Right = (s32)*(s16*)(spu2mem+0x2200+(core<<10)+thiscore.InputPos);
tl = (s32)thiscore.ADMATempBuffer[thiscore.InputPos]; if( IsDevBuild )
tr = (s32)thiscore.ADMATempBuffer[thiscore.InputPos+0x200];
}
PData.Left = tl;
PData.Right = tr;
thiscore.InputPos++;
if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) {
thiscore.AdmaInProgress=0;
if(thiscore.InputDataLeft>=0x200)
{ {
u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress; if(InputDataLeft > 0)
AutoDMAReadBuffer(core,0);
thiscore.AdmaInProgress=1;
thiscore.TSA=(core<<10)+thiscore.InputPos;
if (thiscore.InputDataLeft<0x200)
{ {
thiscore.AutoDMACtrl |= ~3; if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
if( IsDevBuild )
{
FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7');
if(thiscore.InputDataLeft>0)
{
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
}
thiscore.InputDataLeft = 0;
thiscore.DMAICounter = 1;
} }
} }
thiscore.InputPos&=0x1ff; InputDataLeft = 0;
DMAICounter = 1;
} }
} }
InputPos &= 0x1ff;
}
return retval;
}
StereoOut32 V_Core::ReadInput()
{
if((AutoDMACtrl&(Index+1)) != (Index+1))
return StereoOut32();
if( (Index==1) && ((PlayMode&8)==8) )
{
return ReadInput_HiFi( false );
}
else if( (Index==0) && ((PlayMode&4)==4) )
{
return ReadInput_HiFi( true );
} }
else else
{ {
PData.Left = 0; StereoOut32 retval;
PData.Right = 0;
if( (Index!=1) || ((PlayMode&2)==0) )
{
// Using the temporary buffer because this area gets overwritten by some other code.
//*PData.Left = (s32)*(s16*)(spu2mem+0x2000+(core<<10)+InputPos);
//*PData.Right = (s32)*(s16*)(spu2mem+0x2200+(core<<10)+InputPos);
retval = StereoOut32(
(s32)ADMATempBuffer[InputPos],
(s32)ADMATempBuffer[InputPos+0x200]
);
}
InputPos++;
if( (InputPos==0x100) || (InputPos>=0x200) )
{
AdmaInProgress = 0;
if(InputDataLeft >= 0x200)
{
u8 k=InputDataLeft>=InputDataProgress;
AutoDMAReadBuffer(0);
AdmaInProgress = 1;
TSA = (Index<<10) + InputPos;
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;
DMAICounter = 1;
}
}
InputPos&=0x1ff;
}
return retval;
} }
} }

View File

@ -15,7 +15,7 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Spu2.h" #include "Global.h"
#include "RegTable.h" #include "RegTable.h"
const char *ParamNames[8]={"VOLL","VOLR","PITCH","ADSR1","ADSR2","ENVX","VOLXL","VOLXR"}; const char *ParamNames[8]={"VOLL","VOLR","PITCH","ADSR1","ADSR2","ENVX","VOLXL","VOLXR"};

View File

@ -15,14 +15,13 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Global.h"
#include "Spu2.h"
#include "RegTable.h" #include "RegTable.h"
// This var is used to confirm that our lookup table is "correct" // This var is used to confirm that our lookup table is "correct"
// If the assertion in DllMain fails, it means the table has too too few entries. // If the assertion in DllMain fails, it means the table has too too few entries.
// (it can't have too many because that would generate a compiler error). // (it can't have too many because that would generate a compiler error).
const u16 zero=0; const u16 zero = 0;
#define PCORE(c,p) \ #define PCORE(c,p) \
U16P(Cores[c].p) U16P(Cores[c].p)

View File

@ -19,10 +19,10 @@
#ifndef _REGTABLE_H_ #ifndef _REGTABLE_H_
#define _REGTABLE_H_ #define _REGTABLE_H_
#define U16P(x) ( (u16*)&(x) ) #define U16P(x) ( (u16*)&(x) )
// Returns the hiword of a 32 bit integer. // Returns the hiword of a 32 bit integer.
#define U16P_HI(x) ( ((u16*)&(x))+1 ) #define U16P_HI(x) ( ((u16*)&(x))+1 )
// Yay! Global namespace pollution 101! // Yay! Global namespace pollution 101!
extern const u16 zero; extern const u16 zero;

View File

@ -15,52 +15,56 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Spu2.h" #include "Global.h"
#include "Lowpass.h"
static LPF_data lowpass_left( 11000, SampleRate ); // Low pass filters: Change these to 32 for a speedup (benchmarks needed to see if
static LPF_data lowpass_right( 11000, SampleRate ); // the speed gain is worth the quality drop)
static __forceinline s32 RevbGetIndexer( V_Core& thiscore, s32 offset ) static LowPassFilter64 lowpass_left( 11000, SampleRate );
static LowPassFilter64 lowpass_right( 11000, SampleRate );
__forceinline s32 V_Core::RevbGetIndexer( s32 offset )
{ {
u32 pos = thiscore.ReverbX + offset; u32 pos = ReverbX + offset;
// Need to use modulus here, because games can and will drop the buffer size // Need to use modulus here, because games can and will drop the buffer size
// without notice, and it leads to offsets several times past the end of the buffer. // without notice, and it leads to offsets several times past the end of the buffer.
if( pos > thiscore.EffectsEndA ) if( pos > EffectsEndA )
{ {
//pos = thiscore.EffectsStartA + ((thiscore.ReverbX + offset) % (u32)thiscore.EffectsBufferSize); //pos = EffectsStartA + ((ReverbX + offset) % (u32)EffectsBufferSize);
pos -= thiscore.EffectsEndA+1; pos -= EffectsEndA+1;
pos += thiscore.EffectsStartA; pos += EffectsStartA;
} }
return pos; return pos;
} }
void Reverb_AdvanceBuffer( V_Core& thiscore ) void V_Core::Reverb_AdvanceBuffer()
{ {
if( (Cycles & 1) && (thiscore.EffectsBufferSize > 0) ) if( (Cycles & 1) && (EffectsBufferSize > 0) )
{ {
//thiscore.ReverbX = RevbGetIndexer( thiscore, 1 ); //ReverbX = RevbGetIndexer( thiscore, 1 );
thiscore.ReverbX += 1; ReverbX += 1;
if( thiscore.ReverbX >= (u32)thiscore.EffectsBufferSize ) thiscore.ReverbX = 0; if( ReverbX >= (u32)EffectsBufferSize ) ReverbX = 0;
//thiscore.ReverbX += 1; //ReverbX += 1;
//if(thiscore.ReverbX >= (u32)thiscore.EffectsBufferSize ) //if(ReverbX >= (u32)EffectsBufferSize )
// thiscore.ReverbX %= (u32)thiscore.EffectsBufferSize; // ReverbX %= (u32)EffectsBufferSize;
} }
} }
///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////
StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input ) StereoOut32 V_Core::DoReverb( const StereoOut32& Input )
{ {
// Reverb processing occurs at 24khz, so we skip processing every other sample, // Reverb processing occurs at 24khz, so we skip processing every other sample,
// and use the previous calculation for this core instead. // and use the previous calculation for this core instead.
if( (Cycles&1)==0 ) if( (Cycles&1)==0 )
{ {
StereoOut32 retval( thiscore.LastEffect ); StereoOut32 retval( LastEffect );
// Make sure and pass input through the LPF. The result can be discarded. // Make sure and pass input through the LPF. The result can be discarded.
// This gives the LPF a better sampling from which to kill offending frequencies. // This gives the LPF a better sampling from which to kill offending frequencies.
@ -68,15 +72,15 @@ StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input )
lowpass_left.sample( Input.Left / 32768.0 ); lowpass_left.sample( Input.Left / 32768.0 );
lowpass_right.sample( Input.Right / 32768.0 ); lowpass_right.sample( Input.Right / 32768.0 );
//thiscore.LastEffect = Input; //LastEffect = Input;
return retval; return retval;
} }
else else
{ {
if( thiscore.RevBuffers.NeedsUpdated ) if( RevBuffers.NeedsUpdated )
thiscore.UpdateEffectsBufferSize(); UpdateEffectsBufferSize();
if( thiscore.EffectsBufferSize <= 0 ) if( EffectsBufferSize <= 0 )
{ {
// StartA is past EndA, so effects are disabled. // StartA is past EndA, so effects are disabled.
//ConLog( " * SPU2: Effects disabled due to leapfrogged EffectsStart." ); //ConLog( " * SPU2: Effects disabled due to leapfrogged EffectsStart." );
@ -91,54 +95,54 @@ StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input )
// Advance the current reverb buffer pointer, and cache the read/write addresses we'll be // Advance the current reverb buffer pointer, and cache the read/write addresses we'll be
// needing for this session of reverb. // needing for this session of reverb.
const u32 src_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_SRC_A0 ); const u32 src_a0 = RevbGetIndexer( RevBuffers.IIR_SRC_A0 );
const u32 src_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_SRC_A1 ); const u32 src_a1 = RevbGetIndexer( RevBuffers.IIR_SRC_A1 );
const u32 src_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_SRC_B0 ); const u32 src_b0 = RevbGetIndexer( RevBuffers.IIR_SRC_B0 );
const u32 src_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_SRC_B1 ); const u32 src_b1 = RevbGetIndexer( RevBuffers.IIR_SRC_B1 );
const u32 dest_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_A0 ); const u32 dest_a0 = RevbGetIndexer( RevBuffers.IIR_DEST_A0 );
const u32 dest_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_A1 ); const u32 dest_a1 = RevbGetIndexer( RevBuffers.IIR_DEST_A1 );
const u32 dest_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_B0 ); const u32 dest_b0 = RevbGetIndexer( RevBuffers.IIR_DEST_B0 );
const u32 dest_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_B1 ); const u32 dest_b1 = RevbGetIndexer( RevBuffers.IIR_DEST_B1 );
const u32 dest2_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_A0 + 1 ); const u32 dest2_a0 = RevbGetIndexer( RevBuffers.IIR_DEST_A0 + 1 );
const u32 dest2_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_A1 + 1 ); const u32 dest2_a1 = RevbGetIndexer( RevBuffers.IIR_DEST_A1 + 1 );
const u32 dest2_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_B0 + 1 ); const u32 dest2_b0 = RevbGetIndexer( RevBuffers.IIR_DEST_B0 + 1 );
const u32 dest2_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_B1 + 1 ); const u32 dest2_b1 = RevbGetIndexer( RevBuffers.IIR_DEST_B1 + 1 );
const u32 acc_src_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_A0 ); const u32 acc_src_a0 = RevbGetIndexer( RevBuffers.ACC_SRC_A0 );
const u32 acc_src_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_B0 ); const u32 acc_src_b0 = RevbGetIndexer( RevBuffers.ACC_SRC_B0 );
const u32 acc_src_c0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_C0 ); const u32 acc_src_c0 = RevbGetIndexer( RevBuffers.ACC_SRC_C0 );
const u32 acc_src_d0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_D0 ); const u32 acc_src_d0 = RevbGetIndexer( RevBuffers.ACC_SRC_D0 );
const u32 acc_src_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_A1 ); const u32 acc_src_a1 = RevbGetIndexer( RevBuffers.ACC_SRC_A1 );
const u32 acc_src_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_B1 ); const u32 acc_src_b1 = RevbGetIndexer( RevBuffers.ACC_SRC_B1 );
const u32 acc_src_c1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_C1 ); const u32 acc_src_c1 = RevbGetIndexer( RevBuffers.ACC_SRC_C1 );
const u32 acc_src_d1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_D1 ); const u32 acc_src_d1 = RevbGetIndexer( RevBuffers.ACC_SRC_D1 );
const u32 fb_src_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.FB_SRC_A0 ); const u32 fb_src_a0 = RevbGetIndexer( RevBuffers.FB_SRC_A0 );
const u32 fb_src_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.FB_SRC_A1 ); const u32 fb_src_a1 = RevbGetIndexer( RevBuffers.FB_SRC_A1 );
const u32 fb_src_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.FB_SRC_B0 ); const u32 fb_src_b0 = RevbGetIndexer( RevBuffers.FB_SRC_B0 );
const u32 fb_src_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.FB_SRC_B1 ); const u32 fb_src_b1 = RevbGetIndexer( RevBuffers.FB_SRC_B1 );
const u32 mix_dest_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.MIX_DEST_A0 ); const u32 mix_dest_a0 = RevbGetIndexer( RevBuffers.MIX_DEST_A0 );
const u32 mix_dest_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.MIX_DEST_A1 ); const u32 mix_dest_a1 = RevbGetIndexer( RevBuffers.MIX_DEST_A1 );
const u32 mix_dest_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.MIX_DEST_B0 ); const u32 mix_dest_b0 = RevbGetIndexer( RevBuffers.MIX_DEST_B0 );
const u32 mix_dest_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.MIX_DEST_B1 ); const u32 mix_dest_b1 = RevbGetIndexer( RevBuffers.MIX_DEST_B1 );
// ----------------------------------------- // -----------------------------------------
// End Buffer Pointers, Begin Reverb! // End Buffer Pointers, Begin Reverb!
// ----------------------------------------- // -----------------------------------------
//StereoOut32 INPUT_SAMPLE( thiscore.LastEffect + Input ); //StereoOut32 INPUT_SAMPLE( LastEffect + Input );
// Note: LowPass on the input! Very important. Some games like DDS get terrible feedback otherwise. // Note: LowPass on the input! Very important. Some games like DDS get terrible feedback otherwise.
// Decisions, Decisions! Should we mix in the 22khz sample skipped, or not? // Decisions, Decisions! Should we mix in the 22khz sample skipped, or not?
// First one mixes in the 22hkz sample. Second one does not. // First one mixes in the 22hkz sample. Second one does not.
/*StereoOut32 INPUT_SAMPLE( /*StereoOut32 INPUT_SAMPLE(
(s32)(lowpass_left.sample( (Input.Left+thiscore.LastEffect.Left) / 32768.0 ) * 32768.0), (s32)(lowpass_left.sample( (Input.Left+LastEffect.Left) / 32768.0 ) * 32768.0),
(s32)(lowpass_right.sample( (Input.Right+thiscore.LastEffect.Right) / 32768.0 ) * 32768.0) (s32)(lowpass_right.sample( (Input.Right+LastEffect.Right) / 32768.0 ) * 32768.0)
);*/ );*/
StereoOut32 INPUT_SAMPLE( StereoOut32 INPUT_SAMPLE(
@ -146,15 +150,15 @@ StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input )
(s32)(lowpass_right.sample( Input.Right / 32768.0 ) * 32768.0) (s32)(lowpass_right.sample( Input.Right / 32768.0 ) * 32768.0)
); );
const s32 IIR_INPUT_A0 = ((_spu2mem[src_a0] * thiscore.Revb.IIR_COEF) + (INPUT_SAMPLE.Left * thiscore.Revb.IN_COEF_L))>>16; const s32 IIR_INPUT_A0 = ((_spu2mem[src_a0] * Revb.IIR_COEF) + (INPUT_SAMPLE.Left * Revb.IN_COEF_L))>>16;
const s32 IIR_INPUT_A1 = ((_spu2mem[src_a1] * thiscore.Revb.IIR_COEF) + (INPUT_SAMPLE.Right * thiscore.Revb.IN_COEF_R))>>16; const s32 IIR_INPUT_A1 = ((_spu2mem[src_a1] * Revb.IIR_COEF) + (INPUT_SAMPLE.Right * Revb.IN_COEF_R))>>16;
const s32 IIR_INPUT_B0 = ((_spu2mem[src_b0] * thiscore.Revb.IIR_COEF) + (INPUT_SAMPLE.Left * thiscore.Revb.IN_COEF_L))>>16; const s32 IIR_INPUT_B0 = ((_spu2mem[src_b0] * Revb.IIR_COEF) + (INPUT_SAMPLE.Left * Revb.IN_COEF_L))>>16;
const s32 IIR_INPUT_B1 = ((_spu2mem[src_b1] * thiscore.Revb.IIR_COEF) + (INPUT_SAMPLE.Right * thiscore.Revb.IN_COEF_R))>>16; const s32 IIR_INPUT_B1 = ((_spu2mem[src_b1] * Revb.IIR_COEF) + (INPUT_SAMPLE.Right * Revb.IN_COEF_R))>>16;
const s32 IIR_A0 = (IIR_INPUT_A0 * thiscore.Revb.IIR_ALPHA) + (_spu2mem[dest_a0] * (0x7fff - thiscore.Revb.IIR_ALPHA)); const s32 IIR_A0 = (IIR_INPUT_A0 * Revb.IIR_ALPHA) + (_spu2mem[dest_a0] * (0x7fff - Revb.IIR_ALPHA));
const s32 IIR_A1 = (IIR_INPUT_A1 * thiscore.Revb.IIR_ALPHA) + (_spu2mem[dest_a1] * (0x7fff - thiscore.Revb.IIR_ALPHA)); const s32 IIR_A1 = (IIR_INPUT_A1 * Revb.IIR_ALPHA) + (_spu2mem[dest_a1] * (0x7fff - Revb.IIR_ALPHA));
const s32 IIR_B0 = (IIR_INPUT_B0 * thiscore.Revb.IIR_ALPHA) + (_spu2mem[dest_b0] * (0x7fff - thiscore.Revb.IIR_ALPHA)); const s32 IIR_B0 = (IIR_INPUT_B0 * Revb.IIR_ALPHA) + (_spu2mem[dest_b0] * (0x7fff - Revb.IIR_ALPHA));
const s32 IIR_B1 = (IIR_INPUT_B1 * thiscore.Revb.IIR_ALPHA) + (_spu2mem[dest_b1] * (0x7fff - thiscore.Revb.IIR_ALPHA)); const s32 IIR_B1 = (IIR_INPUT_B1 * Revb.IIR_ALPHA) + (_spu2mem[dest_b1] * (0x7fff - Revb.IIR_ALPHA));
_spu2mem[dest2_a0] = clamp_mix( IIR_A0 >> 16 ); _spu2mem[dest2_a0] = clamp_mix( IIR_A0 >> 16 );
_spu2mem[dest2_a1] = clamp_mix( IIR_A1 >> 16 ); _spu2mem[dest2_a1] = clamp_mix( IIR_A1 >> 16 );
_spu2mem[dest2_b0] = clamp_mix( IIR_B0 >> 16 ); _spu2mem[dest2_b0] = clamp_mix( IIR_B0 >> 16 );
@ -162,10 +166,10 @@ StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input )
// Faster single-mul approach to interpolation: // Faster single-mul approach to interpolation:
// (doesn't work yet -- breaks Digital Devil Saga badly) // (doesn't work yet -- breaks Digital Devil Saga badly)
/*const s32 IIR_A0 = IIR_INPUT_A0 + (((_spu2mem[dest_a0]-IIR_INPUT_A0) * thiscore.Revb.IIR_ALPHA)>>16); /*const s32 IIR_A0 = IIR_INPUT_A0 + (((_spu2mem[dest_a0]-IIR_INPUT_A0) * Revb.IIR_ALPHA)>>16);
const s32 IIR_A1 = IIR_INPUT_A1 + (((_spu2mem[dest_a1]-IIR_INPUT_A1) * thiscore.Revb.IIR_ALPHA)>>16); const s32 IIR_A1 = IIR_INPUT_A1 + (((_spu2mem[dest_a1]-IIR_INPUT_A1) * Revb.IIR_ALPHA)>>16);
const s32 IIR_B0 = IIR_INPUT_B0 + (((_spu2mem[dest_b0]-IIR_INPUT_B0) * thiscore.Revb.IIR_ALPHA)>>16); const s32 IIR_B0 = IIR_INPUT_B0 + (((_spu2mem[dest_b0]-IIR_INPUT_B0) * Revb.IIR_ALPHA)>>16);
const s32 IIR_B1 = IIR_INPUT_B1 + (((_spu2mem[dest_b1]-IIR_INPUT_B1) * thiscore.Revb.IIR_ALPHA)>>16); const s32 IIR_B1 = IIR_INPUT_B1 + (((_spu2mem[dest_b1]-IIR_INPUT_B1) * Revb.IIR_ALPHA)>>16);
_spu2mem[dest2_a0] = clamp_mix( IIR_A0 ); _spu2mem[dest2_a0] = clamp_mix( IIR_A0 );
_spu2mem[dest2_a1] = clamp_mix( IIR_A1 ); _spu2mem[dest2_a1] = clamp_mix( IIR_A1 );
@ -173,36 +177,36 @@ StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input )
_spu2mem[dest2_b1] = clamp_mix( IIR_B1 );*/ _spu2mem[dest2_b1] = clamp_mix( IIR_B1 );*/
const s32 ACC0 = const s32 ACC0 =
((_spu2mem[acc_src_a0] * thiscore.Revb.ACC_COEF_A)) + ((_spu2mem[acc_src_a0] * Revb.ACC_COEF_A)) +
((_spu2mem[acc_src_b0] * thiscore.Revb.ACC_COEF_B)) + ((_spu2mem[acc_src_b0] * Revb.ACC_COEF_B)) +
((_spu2mem[acc_src_c0] * thiscore.Revb.ACC_COEF_C)) + ((_spu2mem[acc_src_c0] * Revb.ACC_COEF_C)) +
((_spu2mem[acc_src_d0] * thiscore.Revb.ACC_COEF_D)); ((_spu2mem[acc_src_d0] * Revb.ACC_COEF_D));
const s32 ACC1 = const s32 ACC1 =
((_spu2mem[acc_src_a1] * thiscore.Revb.ACC_COEF_A)) + ((_spu2mem[acc_src_a1] * Revb.ACC_COEF_A)) +
((_spu2mem[acc_src_b1] * thiscore.Revb.ACC_COEF_B)) + ((_spu2mem[acc_src_b1] * Revb.ACC_COEF_B)) +
((_spu2mem[acc_src_c1] * thiscore.Revb.ACC_COEF_C)) + ((_spu2mem[acc_src_c1] * Revb.ACC_COEF_C)) +
((_spu2mem[acc_src_d1] * thiscore.Revb.ACC_COEF_D)); ((_spu2mem[acc_src_d1] * Revb.ACC_COEF_D));
const s32 FB_A0 = (_spu2mem[fb_src_a0] * thiscore.Revb.FB_ALPHA); const s32 FB_A0 = (_spu2mem[fb_src_a0] * Revb.FB_ALPHA);
const s32 FB_A1 = (_spu2mem[fb_src_a1] * thiscore.Revb.FB_ALPHA); const s32 FB_A1 = (_spu2mem[fb_src_a1] * Revb.FB_ALPHA);
const s32 fb_xor_a0 = _spu2mem[fb_src_a0] * ( thiscore.Revb.FB_ALPHA ^ 0x8000 ); const s32 fb_xor_a0 = _spu2mem[fb_src_a0] * ( Revb.FB_ALPHA ^ 0x8000 );
const s32 fb_xor_a1 = _spu2mem[fb_src_a1] * ( thiscore.Revb.FB_ALPHA ^ 0x8000 ); const s32 fb_xor_a1 = _spu2mem[fb_src_a1] * ( Revb.FB_ALPHA ^ 0x8000 );
_spu2mem[mix_dest_a0] = clamp_mix( (ACC0 - FB_A0) >> 16 ); _spu2mem[mix_dest_a0] = clamp_mix( (ACC0 - FB_A0) >> 16 );
_spu2mem[mix_dest_a1] = clamp_mix( (ACC1 - FB_A1) >> 16 ); _spu2mem[mix_dest_a1] = clamp_mix( (ACC1 - FB_A1) >> 16 );
_spu2mem[mix_dest_b0] = clamp_mix( (MulShr32(thiscore.Revb.FB_ALPHA<<16, ACC0) - fb_xor_a0 - (_spu2mem[fb_src_b0] * thiscore.Revb.FB_X)) >> 16 ); _spu2mem[mix_dest_b0] = clamp_mix( (MulShr32(Revb.FB_ALPHA<<16, ACC0) - fb_xor_a0 - (_spu2mem[fb_src_b0] * Revb.FB_X)) >> 16 );
_spu2mem[mix_dest_b1] = clamp_mix( (MulShr32(thiscore.Revb.FB_ALPHA<<16, ACC1) - fb_xor_a1 - (_spu2mem[fb_src_b1] * thiscore.Revb.FB_X)) >> 16 ); _spu2mem[mix_dest_b1] = clamp_mix( (MulShr32(Revb.FB_ALPHA<<16, ACC1) - fb_xor_a1 - (_spu2mem[fb_src_b1] * Revb.FB_X)) >> 16 );
thiscore.LastEffect.Left = _spu2mem[mix_dest_a0] + _spu2mem[mix_dest_b0]; LastEffect.Left = _spu2mem[mix_dest_a0] + _spu2mem[mix_dest_b0];
thiscore.LastEffect.Right = _spu2mem[mix_dest_a1] + _spu2mem[mix_dest_b1]; LastEffect.Right = _spu2mem[mix_dest_a1] + _spu2mem[mix_dest_b1];
clamp_mix( thiscore.LastEffect ); clamp_mix( LastEffect );
//thiscore.LastEffect.Left = (s32)(lowpass_left.sample( thiscore.LastEffect.Left / 32768.0 ) * 32768.0); //LastEffect.Left = (s32)(lowpass_left.sample( LastEffect.Left / 32768.0 ) * 32768.0);
//thiscore.LastEffect.Right = (s32)(lowpass_right.sample( thiscore.LastEffect.Right / 32768.0 ) * 32768.0); //LastEffect.Right = (s32)(lowpass_right.sample( LastEffect.Right / 32768.0 ) * 32768.0);
return thiscore.LastEffect; return LastEffect;
} }
} }

View File

@ -1,221 +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 "Spu2.h"
namespace Savestate {
struct SPU2freezeData
{
u32 version;
u8 unkregs[0x10000];
u8 mem[0x200000];
u32 id;
V_Core Cores[2];
V_SPDIF Spdif;
s16 OutPos;
s16 InputPos;
u32 Cycles;
u32 lClocks;
int PlayMode;
// Used as a base pointer to a series PcmCache blocks.
PcmCacheEntry cacheData;
};
// 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 = 0x0005;
static void wipe_the_cache()
{
memset( pcm_cache_data, 0, pcm_BlockCount * sizeof(PcmCacheEntry) );
}
static s16 old_state_sBuffer[pcm_DecodedSamplesPerBlock] = {0};
typedef s32 __fastcall FreezeHandlerFunction( SPU2freezeData& data );
s32 __fastcall FreezeIt( SPU2freezeData& spud )
{
spud.id = SAVE_ID;
spud.version = SAVE_VERSION;
memcpy(spud.unkregs, spu2regs, 0x010000);
memcpy(spud.mem, _spu2mem, 0x200000);
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;
// Save our cache:
// We could just force the user to rebuild the cache when loading
// from stavestates, but for most games the cache is pretty
// small and compresses well.
//
// Potential Alternative:
// If the cache is not saved then it is necessary to save the
// decoded blocks currently in use by active voices. This allows
// voices to resume seamlessly on load.
PcmCacheEntry* pcmDst = &spud.cacheData;
int blksSaved=0;
for( int bidx=0; bidx<pcm_BlockCount; bidx++ )
{
if( pcm_cache_data[bidx].Validated )
{
// save a cache block!
memcpy( pcmDst, &pcm_cache_data[bidx], sizeof(PcmCacheEntry) );
pcmDst++;
blksSaved++;
}
}
printf( " * SPU2 > FreezeSave > Saved %d cache blocks.\n", blksSaved++ );
return 0;
}
s32 __fastcall ThawIt( SPU2freezeData& spud )
{
if( spud.id != SAVE_ID || spud.version < SAVE_VERSION )
{
printf("\n*** SPU2-X Warning:\n");
if( spud.id == SAVE_ID )
printf("\tSavestate version is from an older version of this plugin.\n");
else
printf("\tThe savestate you are trying to load was not made with this plugin.\n");
printf("\tAudio may not recover correctly. Save your game to memorycard, reset,\n\n");
printf(" and 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).
//
//CoreReset( 0 );
//CoreReset( 1 );
// adpcm cache : Clear all the cache flags and buffers.
wipe_the_cache();
}
else
{
// base stuff
memcpy(spu2regs, spud.unkregs, 0x010000);
memcpy(_spu2mem, spud.mem, 0x200000);
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;
// Load the ADPCM cache:
wipe_the_cache();
const PcmCacheEntry* pcmSrc = &spud.cacheData;
int blksLoaded=0;
for( int bidx=0; bidx<pcm_BlockCount; bidx++ )
{
if( pcm_cache_data[bidx].Validated )
{
// load a cache block!
memcpy( &pcm_cache_data[bidx], pcmSrc, sizeof(PcmCacheEntry) );
pcmSrc++;
blksLoaded++;
}
}
// 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;
}
}
SndBuffer::ClearContents();
}
return 0;
}
s32 __fastcall SizeIt()
{
int size = sizeof(SPU2freezeData);
// calculate the amount of memory consumed by our cache:
for( int bidx=0; bidx<pcm_BlockCount; bidx++ )
{
if( pcm_cache_data[bidx].Validated )
size += sizeof(PcmCacheEntry);
}
return size;
}
}
using namespace Savestate;
EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data)
{
if( mode == FREEZE_SIZE )
{
data->size = SizeIt();
return 0;
}
jASSUME( mode == FREEZE_LOAD || mode == FREEZE_SAVE );
jASSUME( data != NULL );
if( data->data == NULL ) return -1;
SPU2freezeData& spud = (SPU2freezeData&)*(data->data);
switch( mode )
{
case FREEZE_LOAD: return ThawIt( spud );
case FREEZE_SAVE: return FreezeIt( spud );
jNO_DEFAULT;
}
// technically unreachable, but kills a warning:
return 0;
}

View File

@ -15,7 +15,7 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Spu2.h" #include "Global.h"
StereoOut32 StereoOut32::Empty( 0, 0 ); StereoOut32 StereoOut32::Empty( 0, 0 );
@ -56,11 +56,7 @@ public:
s32 Init() { return 0; } s32 Init() { return 0; }
void Close() { } void Close() { }
s32 Test() const { return 0; } s32 Test() const { return 0; }
#ifdef _MSC_VER
void Configure(HWND parent) { }
#else
void Configure(uptr parent) { } void Configure(uptr parent) { }
#endif
bool Is51Out() const { return false; } bool Is51Out() const { return false; }
int GetEmptySampleCount() const { return 0; } int GetEmptySampleCount() const { return 0; }
@ -290,9 +286,9 @@ void SndBuffer::Cleanup()
{ {
mods[OutputModule]->Close(); mods[OutputModule]->Close();
SAFE_DELETE_ARRAY( m_buffer ); safe_delete_array( m_buffer );
SAFE_DELETE_ARRAY( sndTempBuffer ); safe_delete_array( sndTempBuffer );
SAFE_DELETE_ARRAY( sndTempBuffer16 ); safe_delete_array( sndTempBuffer16 );
} }
int SndBuffer::m_dsp_progress = 0; int SndBuffer::m_dsp_progress = 0;
@ -375,15 +371,3 @@ s32 SndBuffer::Test()
return mods[OutputModule]->Test(); return mods[OutputModule]->Test();
} }
#ifdef _MSC_VER
void SndBuffer::Configure(HWND parent, u32 module )
#else
void SndBuffer::Configure(uptr parent, u32 module )
#endif
{
if( mods[module] == NULL )
return;
mods[module]->Configure(parent);
}

View File

@ -1,25 +1,21 @@
//GiGaHeRz's SPU2 Driver /* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com> * Developed and maintained by the Pcsx2 Development Team.
// *
//This library is free software; you can redistribute it and/or * Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
//modify it under the terms of the GNU Lesser General Public *
//License as published by the Free Software Foundation; either * SPU2-X is free software: you can redistribute it and/or modify it under the terms
//version 2.1 of the License, or (at your option) any later version. * 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.
//This library is distributed in the hope that it will be useful, *
//but WITHOUT ANY WARRANTY; without even the implied warranty of * SPU2-X is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//Lesser General Public License for more details. * PURPOSE. See the GNU Lesser General Public License for more details.
// *
//You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public License
//License along with this library; if not, write to the Free Software * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
//
#ifndef SNDOUT_H_INCLUDE
#define SNDOUT_H_INCLUDE
#include "BaseTypes.h" #pragma once
#include "Lowpass.h"
// Number of stereo samples per SndOut block. // Number of stereo samples per SndOut block.
// All drivers must work in units of this size when communicating with // All drivers must work in units of this size when communicating with
@ -35,7 +31,7 @@ static const int SndOutVolumeShift = 13;
// is too problematic. :) // is too problematic. :)
static const int SampleRate = 48000; static const int SampleRate = 48000;
int FindOutputModuleById( const wchar_t* omodid ); extern int FindOutputModuleById( const wchar_t* omodid );
struct StereoOut16 struct StereoOut16
{ {
@ -231,9 +227,9 @@ struct Stereo51Out16DplII
s32 Tfl=(RAccum)*255/(LAccum); s32 Tfl=(RAccum)*255/(LAccum);
s32 Tfr=(LAccum)*255/(RAccum); s32 Tfr=(LAccum)*255/(RAccum);
int gMax = max(Tfl,Tfr); int gMax = std::max(Tfl,Tfr);
Tfl=Tfl*255/gMax; Tfl = Tfl*255/gMax;
Tfr=Tfr*255/gMax; Tfr = Tfr*255/gMax;
if(Tfl>255) Tfl=255; if(Tfl>255) Tfl=255;
if(Tfr>255) Tfr=255; if(Tfr>255) Tfr=255;
@ -393,12 +389,6 @@ public:
static s32 Test(); static s32 Test();
static void ClearContents(); static void ClearContents();
#ifdef _MSC_VER
static void Configure(HWND parent, u32 module );
#else
static void Configure(uptr parent, u32 module );
#endif
// Note: When using with 32 bit output buffers, the user of this function is responsible // 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 // 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 // the sample output is determined by the SndOutVolumeShift, which is the number of bits
@ -474,11 +464,7 @@ public:
virtual s32 Test() const=0; virtual s32 Test() const=0;
// Gui function: Used to open the configuration box for this driver. // Gui function: Used to open the configuration box for this driver.
#ifdef _MSC_VER
virtual void Configure(HWND parent)=0;
#else
virtual void Configure(uptr parent)=0; virtual void Configure(uptr parent)=0;
#endif
// Loads settings from the INI file for this driver // Loads settings from the INI file for this driver
virtual void ReadSettings()=0; virtual void ReadSettings()=0;
@ -503,4 +489,13 @@ extern SndOutModule* XAudio2Out;
extern SndOutModule* mods[]; extern SndOutModule* mods[];
#endif // SNDOUT_H_INCLUDE // =====================================================================================================
extern void RecordStart();
extern void RecordStop();
extern void RecordWrite( const StereoOut16& sample );
extern s32 DspLoadLibrary(wchar_t *fileName, int modNum);
extern void DspCloseLibrary();
extern int DspProcess(s16 *buffer, int samples);
extern void DspUpdate(); // to let the Dsp process window messages

View File

@ -1,212 +0,0 @@
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
* Developed and maintained by the Pcsx2 Development Team.
*
* 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 "BaseTypes.h"
#include "Pcsx2Defs.h"
#include "Utilities/Exceptions.h"
#ifdef __LINUX__
#include <stdio.h>
#include <string.h>
//Until I get around to putting in Linux svn code, this is an unknown svn version.
#define SVN_REV_UNKNOWN
#endif
#include "ConvertUTF.h"
namespace VersionInfo
{
static const u8 PluginApi = PS2E_SPU2_VERSION;
static const u8 Release = 1;
static const u8 Revision = 2; // increase that with each version
}
#ifdef _MSC_VER
#define EXPORT_C_(type) extern "C" __declspec(dllexport) type CALLBACK
#else
#define EXPORT_C_(type) extern "C" type
#endif
// We have our own versions that have the DLLExport attribute configured:
EXPORT_C_(s32) SPU2init();
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);
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);
// 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_(void) SPU2setDMABaseAddr(uptr baseaddr);
EXPORT_C_(void) SPU2interruptDMA7();
EXPORT_C_(u32) SPU2ReadMemAddr(int core);
EXPORT_C_(void) SPU2WriteMemAddr(int core,u32 value);
EXPORT_C_(void) 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
EXPORT_C_(int) SPU2setupRecording(int start, void* pData);
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();
//#define EFFECTS_DUMP
//Plugin parts
#include "Config.h"
#include "defs.h"
#include "regs.h"
#include "Dma.h"
#include "SndOut.h"
#include "Spu2replay.h"
#ifdef SPU2X_DEVBUILD
#define SPU2_LOG
#endif
#include "Debug.h"
//--------------------------------------------------------------------------------------
// Helper macros
//--------------------------------------------------------------------------------------
#ifndef SAFE_FREE
# define SAFE_FREE(p) { if(p) { free(p); (p)=NULL; } }
#endif
#ifndef SAFE_DELETE_ARRAY
# define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
#endif
#ifndef SAFE_DELETE_OBJ
# define SAFE_DELETE_OBJ(p) { if(p) { delete (p); (p)=NULL; } }
#endif
#ifndef SAFE_RELEASE
# define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
#endif
// 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 void spdif_set51(u32 is_5_1_out);
extern u32 spdif_init();
extern void spdif_shutdown();
extern void spdif_get_samples(s32 *samples); // fills the buffer with [l,r,c,lfe,sl,sr] if using 5.1 output, or [l,r] if using stereo
extern short *spu2regs;
extern short *_spu2mem;
extern PcmCacheEntry* pcm_cache_data;
extern s16* __fastcall GetMemPtr(u32 addr);
extern s16 __fastcall spu2M_Read( u32 addr );
extern void __fastcall spu2M_Write( u32 addr, s16 value );
extern void __fastcall spu2M_Write( u32 addr, u16 value );
#define spu2Rs16(mmem) (*(s16 *)((s8 *)spu2regs + ((mmem) & 0x1fff)))
#define spu2Ru16(mmem) (*(u16 *)((s8 *)spu2regs + ((mmem) & 0x1fff)))
extern u8 callirq;
extern void (* _irqcallback)();
extern void (* dma4callback)();
extern void (* dma7callback)();
extern void SetIrqCall();
extern double srate_pv;
extern s16 *input_data;
extern u32 input_data_ptr;
extern int PlayMode;
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 u16 SPU_ps1_read(u32 mem);
extern void SPU_ps1_write(u32 mem, u16 value);
extern void SPU2_FastWrite( u32 rmem, u16 value );
extern void StartVoices(int core, u32 value);
extern void StopVoices(int core, u32 value);
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
extern void RecordStart();
extern void RecordStop();
extern void RecordWrite( const StereoOut16& sample );
extern void UpdateSpdifMode();
extern void LowPassFilterInit();
extern void InitADSR();
extern void CalculateADSR( V_Voice& vc );
extern void __fastcall ReadInput( uint core, StereoOut32& PData );
//////////////////////////////
// The Mixer Section //
//////////////////////////////
extern void Mix();
extern s32 clamp_mix( s32 x, u8 bitshift=0 );
extern StereoOut32 clamp_mix( const StereoOut32& sample, u8 bitshift=0 );
extern void Reverb_AdvanceBuffer( V_Core& thiscore );
extern StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input );
extern s32 MulShr32( s32 srcval, s32 mulval );
//#define PCM24_S1_INTERLEAVE

View File

@ -16,9 +16,8 @@
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
#include <stdio.h> #include "Global.h"
#include "PS2E-spu2.h"
#include "Spu2.h"
FILE* s2rfile; FILE* s2rfile;
@ -115,6 +114,7 @@ void dummy7()
#define Cread(a,b,c,d) if(fread(a,b,c,d)<b) break; #define Cread(a,b,c,d) if(fread(a,b,c,d)<b) break;
#ifdef _MSC_VER #ifdef _MSC_VER
#include "Windows/Dialogs.h"
EXPORT_C_(void) s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow) EXPORT_C_(void) s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow)
{ {
// load file // load file

View File

@ -26,11 +26,4 @@ void s2r_writedma4(u32 ticks,u16*data,u32 len);
void s2r_writedma7(u32 ticks,u16*data,u32 len); void s2r_writedma7(u32 ticks,u16*data,u32 len);
void s2r_close(); void s2r_close();
#ifdef _MSC_VER
// s2r playing
EXPORT_C_(void) s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow);
#else
#define s2r_replay 0&&
#endif
extern bool replay_mode; extern bool replay_mode;

View File

@ -15,7 +15,7 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Spu2.h" #include "Global.h"
#include "SoundTouch/SoundTouch.h" #include "SoundTouch/SoundTouch.h"
#include "SoundTouch/WavFile.h" #include "SoundTouch/WavFile.h"
@ -304,9 +304,7 @@ void SndBuffer::soundtouchInit()
pSoundTouch->setSetting( SETTING_USE_QUICKSEEK, 0 ); pSoundTouch->setSetting( SETTING_USE_QUICKSEEK, 0 );
pSoundTouch->setSetting( SETTING_USE_AA_FILTER, 0 ); pSoundTouch->setSetting( SETTING_USE_AA_FILTER, 0 );
pSoundTouch->setSetting( SETTING_SEQUENCE_MS, SoundtouchCfg::SequenceLenMS ); SoundtouchCfg::ApplySettings( *pSoundTouch );
pSoundTouch->setSetting( SETTING_SEEKWINDOW_MS, SoundtouchCfg::SeekWindowMS );
pSoundTouch->setSetting( SETTING_OVERLAP_MS, SoundtouchCfg::OverlapMS );
pSoundTouch->setTempo(1); pSoundTouch->setTempo(1);
@ -340,5 +338,5 @@ void SndBuffer::soundtouchClearContents()
void SndBuffer::soundtouchCleanup() void SndBuffer::soundtouchCleanup()
{ {
SAFE_DELETE_OBJ( pSoundTouch ); safe_delete( pSoundTouch );
} }

View File

@ -15,11 +15,7 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdexcept> #include "Global.h"
#include <new>
#include "Spu2.h"
#include "SoundTouch/WavFile.h" #include "SoundTouch/WavFile.h"
static WavOutFile* _new_WavOutFile( const char* destfile ) static WavOutFile* _new_WavOutFile( const char* destfile )
@ -52,7 +48,7 @@ namespace WaveDump
{ {
for( int srcidx=0; srcidx<CoreSrc_Count; srcidx++ ) for( int srcidx=0; srcidx<CoreSrc_Count; srcidx++ )
{ {
SAFE_DELETE_OBJ( m_CoreWav[cidx][srcidx] ); safe_delete( m_CoreWav[cidx][srcidx] );
sprintf( wavfilename, "logs\\spu2x-Core%d-%s.wav", sprintf( wavfilename, "logs\\spu2x-Core%d-%s.wav",
cidx, m_tbl_CoreOutputTypeNames[ srcidx ] ); cidx, m_tbl_CoreOutputTypeNames[ srcidx ] );
@ -77,7 +73,7 @@ namespace WaveDump
{ {
for( int srcidx=0; srcidx<CoreSrc_Count; srcidx++ ) for( int srcidx=0; srcidx<CoreSrc_Count; srcidx++ )
{ {
SAFE_DELETE_OBJ( m_CoreWav[cidx][srcidx] ); safe_delete( m_CoreWav[cidx][srcidx] );
} }
} }
} }
@ -99,7 +95,7 @@ WavOutFile* m_wavrecord = NULL;
void RecordStart() void RecordStart()
{ {
SAFE_DELETE_OBJ( m_wavrecord ); safe_delete( m_wavrecord );
try try
{ {
@ -114,7 +110,7 @@ void RecordStart()
void RecordStop() void RecordStop()
{ {
SAFE_DELETE_OBJ( m_wavrecord ); safe_delete( m_wavrecord );
} }
void RecordWrite( const StereoOut16& sample ) void RecordWrite( const StereoOut16& sample )

View File

@ -15,8 +15,8 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Global.h"
#include "Dialogs.h" #include "Dialogs.h"
#include <CommCtrl.h>
#include "svnrev.h" #include "svnrev.h"
#include "Hyperlinks.h" #include "Hyperlinks.h"

View File

@ -15,8 +15,22 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Global.h"
#include "Dialogs.h" #include "Dialogs.h"
void SysMessage(const char *fmt, ...)
{
va_list list;
char tmp[512];
wchar_t wtmp[512];
va_start(list,fmt);
sprintf_s(tmp,fmt,list);
va_end(list);
swprintf_s(wtmp, L"%S", tmp);
MessageBox(0, wtmp, L"SPU2-X System Message", 0);
}
////// //////
const TCHAR CfgFile[] = L"inis\\SPU2-X.ini"; const TCHAR CfgFile[] = L"inis\\SPU2-X.ini";

View File

@ -15,9 +15,10 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Global.h"
#include "Dialogs.h" #include "Dialogs.h"
#ifdef SPU2X_DEVBUILD #ifdef PCSX2_DEVBUILD
static const int LATENCY_MAX = 3000; static const int LATENCY_MAX = 3000;
#else #else
static const int LATENCY_MAX = 750; static const int LATENCY_MAX = 750;
@ -25,8 +26,6 @@ static const int LATENCY_MAX = 750;
static const int LATENCY_MIN = 40; static const int LATENCY_MIN = 40;
int AutoDMAPlayRate[2] = {0,0};
// MIXING // MIXING
int Interpolation = 1; int Interpolation = 1;
/* values: /* values:
@ -57,9 +56,6 @@ bool StereoExpansionEnabled = false;
void ReadSettings() void ReadSettings()
{ {
AutoDMAPlayRate[0] = CfgReadInt(L"MIXING",L"AutoDMA_Play_Rate_0",0);
AutoDMAPlayRate[1] = CfgReadInt(L"MIXING",L"AutoDMA_Play_Rate_1",0);
Interpolation = CfgReadInt( L"MIXING",L"Interpolation", 1 ); Interpolation = CfgReadInt( L"MIXING",L"Interpolation", 1 );
timeStretchDisabled = CfgReadBool( L"OUTPUT", L"Disable_Timestretch", false ); timeStretchDisabled = CfgReadBool( L"OUTPUT", L"Disable_Timestretch", false );
@ -107,9 +103,6 @@ void WriteSettings()
{ {
CfgWriteInt(L"MIXING",L"Interpolation",Interpolation); CfgWriteInt(L"MIXING",L"Interpolation",Interpolation);
CfgWriteInt(L"MIXING",L"AutoDMA_Play_Rate_0",AutoDMAPlayRate[0]);
CfgWriteInt(L"MIXING",L"AutoDMA_Play_Rate_1",AutoDMAPlayRate[1]);
CfgWriteBool(L"MIXING",L"Disable_Effects",EffectsDisabled); CfgWriteBool(L"MIXING",L"Disable_Effects",EffectsDisabled);
CfgWriteStr(L"OUTPUT",L"Output_Module", mods[OutputModule]->GetIdent() ); CfgWriteStr(L"OUTPUT",L"Output_Module", mods[OutputModule]->GetIdent() );
@ -204,9 +197,11 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
break; break;
case IDC_OUTCONF: case IDC_OUTCONF:
SndBuffer::Configure( hWnd, {
(int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0) const int module = (int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0);
); if( mods[module] == NULL ) break;
mods[module]->Configure((uptr)hWnd);
}
break; break;
case IDC_OPEN_CONFIG_DEBUG: case IDC_OPEN_CONFIG_DEBUG:

View File

@ -1,147 +0,0 @@
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
* Developed and maintained by the Pcsx2 Development Team.
*
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
*
* SPU2-X is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SPU2-X is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
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;
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 int AutoDMAPlayRate[2];
extern u32 OutputModule;
extern int SndOutLatencyMS;
extern wchar_t dspPlugin[];
extern int dspPluginModule;
extern bool dspPluginEnabled;
extern bool timeStretchDisabled;
extern bool StereoExpansionEnabled;
class SoundtouchCfg
{
// Timestretch Slider Bounds, Min/Max
static const int SequenceLen_Min = 30;
static const int SequenceLen_Max = 90;
static const int SeekWindow_Min = 10;
static const int SeekWindow_Max = 32;
static const int Overlap_Min = 3;
static const int Overlap_Max = 15;
public:
static int SequenceLenMS;
static int SeekWindowMS;
static int OverlapMS;
static void ReadSettings();
static void WriteSettings();
static void OpenDialog( HWND hWnd );
protected:
static void ClampValues();
static BOOL CALLBACK DialogProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
};
// *** BEGIN DRIVER-SPECIFIC CONFIGURATION ***
// -------------------------------------------
// DSOUND
struct CONFIG_XAUDIO2
{
std::wstring Device;
s8 NumBuffers;
CONFIG_XAUDIO2() :
Device(),
NumBuffers( 2 )
{
}
};
// WAVEOUT
struct CONFIG_WAVEOUT
{
std::wstring Device;
s8 NumBuffers;
CONFIG_WAVEOUT() :
Device(),
NumBuffers( 4 )
{
}
};
extern CONFIG_WAVEOUT Config_WaveOut;
extern CONFIG_XAUDIO2 Config_XAudio2;
//////
void ReadSettings();
void WriteSettings();
void configure();
void AboutBox();

View File

@ -15,6 +15,7 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Global.h"
#include "Dialogs.h" #include "Dialogs.h"

View File

@ -15,13 +15,33 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Global.h"
#include "Dialogs.h" #include "Dialogs.h"
int SoundtouchCfg::SequenceLenMS = 63; #include "SoundTouch/SoundTouch.h"
int SoundtouchCfg::SeekWindowMS = 16;
int SoundtouchCfg::OverlapMS = 7;
void SoundtouchCfg::ClampValues() static int SequenceLenMS = 63;
static int SeekWindowMS = 16;
static int OverlapMS = 7;
// Timestretch Slider Bounds, Min/Max
static const int SequenceLen_Min = 30;
static const int SequenceLen_Max = 90;
static const int SeekWindow_Min = 10;
static const int SeekWindow_Max = 32;
static const int Overlap_Min = 3;
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( SequenceLenMS, SequenceLen_Min, SequenceLen_Max );
Clampify( SeekWindowMS, SeekWindow_Min, SeekWindow_Max ); Clampify( SeekWindowMS, SeekWindow_Min, SeekWindow_Max );
@ -101,7 +121,7 @@ void SoundtouchCfg::OpenDialog( HWND hWnd )
ret = DialogBox( hInstance, MAKEINTRESOURCE(IDD_CONFIG_SOUNDTOUCH), hWnd, (DLGPROC)DialogProc ); ret = DialogBox( hInstance, MAKEINTRESOURCE(IDD_CONFIG_SOUNDTOUCH), hWnd, (DLGPROC)DialogProc );
if(ret==-1) if(ret==-1)
{ {
MessageBoxEx(GetActiveWindow(),L"Error Opening the Soundtouch advanced dialog.",L"OMG ERROR!",MB_OK,0); MessageBoxEx(GetActiveWindow(), L"Error Opening the Soundtouch advanced dialog.", L"OMG ERROR!", MB_OK, 0);
return; return;
} }
ReadSettings(); ReadSettings();

View File

@ -17,30 +17,11 @@
#pragma once #pragma once
#ifndef _DIALOGS_H_ #ifdef _WIN32
#define _DIALOGS_H_ # include "WinConfig.h"
#else
#include "../Spu2.h" # include "LnxConfig.h"
#endif
#include <commctrl.h>
#include <initguid.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 )
namespace DebugConfig namespace DebugConfig
{ {
@ -50,24 +31,32 @@ namespace DebugConfig
extern void EnableControls( HWND hWnd ); extern void EnableControls( HWND hWnd );
} }
extern int SendDialogMsg( HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam); namespace SoundtouchCfg
extern HRESULT GUIDFromString( const char *str, LPGUID guid ); {
extern void ReadSettings();
extern void WriteSettings();
extern void OpenDialog( HWND hWnd );
extern BOOL CALLBACK DialogProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
}
extern void AssignSliderValue( HWND idcwnd, HWND hwndDisplay, int value ); extern int SendDialogMsg( HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam);
extern void AssignSliderValue( HWND hWnd, int idc, int editbox, int value ); extern HRESULT GUIDFromString( const char *str, LPGUID guid );
extern int GetSliderValue( HWND hWnd, int idc );
extern BOOL DoHandleScrollMessage( HWND hwndDisplay, WPARAM wParam, LPARAM lParam );
bool CfgFindName( const TCHAR *Section, const TCHAR* Name); 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 );
void CfgWriteBool(const TCHAR* Section, const TCHAR* Name, bool Value); extern bool CfgFindName( const TCHAR *Section, const TCHAR* Name);
void CfgWriteInt(const TCHAR* Section, const TCHAR* Name, int Value);
void CfgWriteStr(const TCHAR* Section, const TCHAR* Name, const wstring& Data);
bool CfgReadBool(const TCHAR *Section,const TCHAR* Name, bool Default); extern void CfgWriteBool(const TCHAR* Section, const TCHAR* Name, bool Value);
void CfgReadStr(const TCHAR* Section, const TCHAR* Name, wstring& Data, int DataSize, const TCHAR* Default); extern void CfgWriteInt(const TCHAR* Section, const TCHAR* Name, int Value);
void CfgReadStr(const TCHAR* Section, const TCHAR* Name, TCHAR* Data, int DataSize, const TCHAR* Default); extern void CfgWriteStr(const TCHAR* Section, const TCHAR* Name, const wstring& Data);
int CfgReadInt(const TCHAR* Section, const TCHAR* Name,int Default);
extern bool CfgReadBool(const TCHAR *Section,const TCHAR* Name, bool Default);
extern void CfgReadStr(const TCHAR* Section, const TCHAR* Name, wstring& Data, int DataSize, 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);
// Items Specific to DirectSound // Items Specific to DirectSound
@ -83,4 +72,3 @@ struct ds_device_data
bool hasGuid; bool hasGuid;
}; };
#endif

View File

@ -16,6 +16,7 @@
*/ */
#include "Global.h"
#include "Dialogs.h" #include "Dialogs.h"
#include "../RegTable.h" #include "../RegTable.h"
@ -59,7 +60,7 @@ static BOOL CALLBACK DebugProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
return TRUE; return TRUE;
} }
#ifdef SPU2X_DEVBUILD #ifdef PCSX2_DEVBUILD
int FillRectangle(HDC dc, int left, int top, int width, int height) int FillRectangle(HDC dc, int left, int top, int width, int height)
{ {

View File

@ -15,6 +15,8 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Global.h"
#define _WIN32_DCOM #define _WIN32_DCOM
#include "Dialogs.h" #include "Dialogs.h"
@ -103,6 +105,8 @@ private:
public: public:
s32 Init() s32 Init()
{ {
CoInitializeEx( NULL, COINIT_MULTITHREADED );
// //
// Initialize DSound // Initialize DSound
// //
@ -180,7 +184,7 @@ public:
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)) ) if( FAILED(buffer_->QueryInterface(IID_IDirectSoundBuffer8,(void**)&buffer)) || buffer == NULL )
throw std::runtime_error( "DirectSound Error: Interface could not be queried." ); throw std::runtime_error( "DirectSound Error: Interface could not be queried." );
buffer_->Release(); buffer_->Release();
@ -242,11 +246,12 @@ public:
buffer_events[i] = NULL; buffer_events[i] = NULL;
} }
SAFE_RELEASE( buffer_notify ); safe_release( buffer_notify );
SAFE_RELEASE( buffer ); safe_release( buffer );
} }
SAFE_RELEASE( dsound ); safe_release( dsound );
CoUninitialize();
} }
private: private:
@ -406,13 +411,13 @@ private:
static BOOL CALLBACK DSEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext ); static BOOL CALLBACK DSEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext );
public: public:
virtual void Configure(HWND parent) virtual void Configure(uptr parent)
{ {
INT_PTR ret; INT_PTR ret;
ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DSOUND),GetActiveWindow(),(DLGPROC)ConfigProc,1); ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DSOUND),(HWND)parent,(DLGPROC)ConfigProc,1);
if(ret==-1) if(ret==-1)
{ {
MessageBoxEx(GetActiveWindow(),L"Error Opening the config dialog.",L"OMG ERROR!",MB_OK,0); MessageBoxEx((HWND)parent,L"Error Opening the config dialog.",L"OMG ERROR!",MB_OK,0);
return; return;
} }
} }

View File

@ -15,11 +15,13 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Global.h"
#define _WIN32_DCOM #define _WIN32_DCOM
#include "Dialogs.h" #include "Dialogs.h"
#include <xaudio2.h>
#include <atlbase.h>
#include <xaudio2.h>
namespace Exception namespace Exception
{ {
@ -181,7 +183,7 @@ private:
killMe->FlushSourceBuffers(); killMe->FlushSourceBuffers();
EnterCriticalSection( &cs ); EnterCriticalSection( &cs );
killMe->DestroyVoice(); killMe->DestroyVoice();
SAFE_DELETE_ARRAY( qbuffer ); safe_delete_array( qbuffer );
LeaveCriticalSection( &cs ); LeaveCriticalSection( &cs );
DeleteCriticalSection( &cs ); DeleteCriticalSection( &cs );
} }
@ -225,7 +227,7 @@ private:
}; };
IXAudio2* pXAudio2; CComPtr<IXAudio2> pXAudio2;
IXAudio2MasteringVoice* pMasteringVoice; IXAudio2MasteringVoice* pMasteringVoice;
BaseStreamingVoice* voiceContext; BaseStreamingVoice* voiceContext;
@ -314,7 +316,7 @@ public:
catch( Exception::XAudio2Error& ex ) catch( Exception::XAudio2Error& ex )
{ {
SysMessage( ex.CMessage() ); SysMessage( ex.CMessage() );
SAFE_RELEASE( pXAudio2 ); pXAudio2.Release();
CoUninitialize(); CoUninitialize();
return -1; return -1;
} }
@ -333,7 +335,7 @@ public:
// But doing no cleanup at all causes XA2 under XP to crash. So after much trial // 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: // and error we found a happy compromise as follows:
SAFE_DELETE_OBJ( voiceContext ); safe_delete( voiceContext );
voiceContext = NULL; voiceContext = NULL;
@ -342,12 +344,11 @@ public:
pMasteringVoice = NULL; pMasteringVoice = NULL;
SAFE_RELEASE( pXAudio2 ); pXAudio2.Release();
CoUninitialize(); CoUninitialize();
} }
virtual void Configure(HWND parent) virtual void Configure(uptr parent)
{ {
} }

View File

@ -15,8 +15,8 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Global.h"
#include "Dialogs.h" #include "Dialogs.h"
#include <windows.h>
class WaveOutModule: public SndOutModule class WaveOutModule: public SndOutModule
@ -197,7 +197,7 @@ public:
} }
waveOutClose(hwodevice); waveOutClose(hwodevice);
SAFE_DELETE_ARRAY( qbuffer ); safe_delete_array( qbuffer );
} }
private: private:
@ -271,13 +271,13 @@ private:
} }
public: public:
virtual void Configure(HWND parent) virtual void Configure(uptr parent)
{ {
INT_PTR ret; INT_PTR ret;
ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_WAVEOUT),GetActiveWindow(),(DLGPROC)ConfigProc,1); ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_WAVEOUT), (HWND)parent, (DLGPROC)ConfigProc,1);
if(ret==-1) if(ret==-1)
{ {
MessageBoxEx(GetActiveWindow(), L"Error Opening the config dialog.", L"OMG ERROR!", MB_OK, 0); MessageBoxEx((HWND)parent, L"Error Opening the config dialog.", L"OMG ERROR!", MB_OK, 0);
return; return;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,7 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Global.h"
#include "Dialogs.h" #include "Dialogs.h"
int SendDialogMsg( HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam) int SendDialogMsg( HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam)

View File

@ -0,0 +1,61 @@
#pragma once
# define WINVER 0x0501
# define _WIN32_WINNT 0x0501
#include <windows.h>
#include <mmsystem.h>
#include <commctrl.h>
#include <initguid.h>
#include <tchar.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
{
std::wstring Device;
s8 NumBuffers;
CONFIG_XAUDIO2() :
Device(),
NumBuffers( 2 )
{
}
};
struct CONFIG_WAVEOUT
{
std::wstring Device;
s8 NumBuffers;
CONFIG_WAVEOUT() :
Device(),
NumBuffers( 4 )
{
}
};
extern CONFIG_WAVEOUT Config_WaveOut;
extern CONFIG_XAUDIO2 Config_XAudio2;

View File

@ -15,7 +15,15 @@
//License along with this library; if not, write to the Free Software //License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
#include "../spu2.h"
#include "Global.h"
# define WINVER 0x0501
# define _WIN32_WINNT 0x0501
#include <windows.h>
#include <mmsystem.h>
extern "C" { extern "C" {
#include "dsp.h" #include "dsp.h"

View File

@ -17,12 +17,27 @@
#pragma once #pragma once
#include "Mixer.h"
// --------------------------------------------------------------------------------------
// SPU2 Memory Indexers
// --------------------------------------------------------------------------------------
#define spu2Rs16(mmem) (*(s16 *)((s8 *)spu2regs + ((mmem) & 0x1fff)))
#define spu2Ru16(mmem) (*(u16 *)((s8 *)spu2regs + ((mmem) & 0x1fff)))
extern s16* __fastcall GetMemPtr(u32 addr);
extern s16 __fastcall spu2M_Read( u32 addr );
extern void __fastcall spu2M_Write( u32 addr, s16 value );
extern void __fastcall spu2M_Write( u32 addr, u16 value );
struct V_VolumeLR struct V_VolumeLR
{ {
static V_VolumeLR Max; static V_VolumeLR Max;
s32 Left; s32 Left;
s32 Right; s32 Right;
V_VolumeLR() {} V_VolumeLR() {}
V_VolumeLR( s32 both ) : V_VolumeLR( s32 both ) :
@ -39,10 +54,10 @@ struct V_VolumeSlide
// Holds the "original" value of the volume for this voice, prior to slides. // Holds the "original" value of the volume for this voice, prior to slides.
// (ie, the volume as written to the register) // (ie, the volume as written to the register)
s16 Reg_VOL; s16 Reg_VOL;
s32 Value; s32 Value;
s8 Increment; s8 Increment;
s8 Mode; s8 Mode;
public: public:
V_VolumeSlide() {} V_VolumeSlide() {}
@ -57,7 +72,6 @@ public:
void Update(); void Update();
void RegSet( u16 src ); // used to set the volume from a register source (16 bit signed) 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 ); void DebugDump( FILE* dump, const char* title, const char* nameLR );
}; };
struct V_VolumeSlideLR struct V_VolumeSlideLR
@ -304,135 +318,235 @@ struct V_VoiceGates
s16 WetR; // 'AND Gate' for Effect Output for Right Channel s16 WetR; // 'AND Gate' for Effect Output for Right Channel
}; };
union V_CoreGates struct V_CoreGates
{ {
struct union
{ {
u64 lo; u128 v128;
u64 hi;
} v128;
struct struct
{ {
s16 InpL; // Sound Data Input to Direct Output (Left) s16 InpL; // Sound Data Input to Direct Output (Left)
s16 InpR; // Sound Data Input to Direct Output (Right) s16 InpR; // Sound Data Input to Direct Output (Right)
s16 SndL; // Voice Data to Direct Output (Left) s16 SndL; // Voice Data to Direct Output (Left)
s16 SndR; // Voice Data to Direct Output (Right) s16 SndR; // Voice Data to Direct Output (Right)
s16 ExtL; // External Input to Direct Output (Left) s16 ExtL; // External Input to Direct Output (Left)
s16 ExtR; // External Input to Direct Output (Right) 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 struct V_Core
{ {
static const uint NumVoices = 24; static const uint NumVoices = 24;
int Index; // Core index identifier.
// Voice Gates -- These are SSE-related values, and must always be // Voice Gates -- These are SSE-related values, and must always be
// first to ensure 16 byte alignment // first to ensure 16 byte alignment
V_VoiceGates VoiceGates[NumVoices]; V_VoiceGates VoiceGates[NumVoices];
V_CoreGates DryGate; V_CoreGates DryGate;
V_CoreGates WetGate; V_CoreGates WetGate;
V_VolumeSlideLR MasterVol;// Master Volume V_VolumeSlideLR MasterVol; // Master Volume
V_VolumeLR ExtVol; // Volume for External Data Input V_VolumeLR ExtVol; // Volume for External Data Input
V_VolumeLR InpVol; // Volume for Sound Data Input V_VolumeLR InpVol; // Volume for Sound Data Input
V_VolumeLR FxVol; // Volume for Output from Effects V_VolumeLR FxVol; // Volume for Output from Effects
V_Voice Voices[NumVoices]; V_Voice Voices[NumVoices];
// Interrupt Address u32 IRQA; // Interrupt Address
u32 IRQA; u32 TSA; // DMA Transfer Start Address
// DMA Transfer Start Address u32 TDA; // DMA Transfer Data Address (Internal...)
u32 TSA;
// DMA Transfer Data Address (Internal...)
u32 TDA;
// Interrupt Enable s8 IRQEnable; // Interrupt Enable
s8 IRQEnable; s8 DMABits; // DMA related?
// DMA related? s8 FxEnable; // Effect Enable
s8 DMABits; s8 NoiseClk; // Noise Clock
// Effect Enable u16 AutoDMACtrl; // AutoDMA Status
s8 FxEnable; s32 DMAICounter; // DMA Interrupt Counter
// Noise Clock s8 Mute; // Mute
s8 NoiseClk; u32 InputDataLeft; // Input Buffer
// AutoDMA Status u32 InputPos;
u16 AutoDMACtrl; u32 InputDataProgress;
// DMA Interrupt Counter u8 AdmaInProgress;
s32 DMAICounter;
// Mute
s8 Mute;
// Input Buffer
u32 InputDataLeft;
u32 InputPos;
u32 InputDataProgress;
u8 AdmaInProgress;
// Reverb V_Reverb Revb; // Reverb Registers
V_Reverb Revb; V_ReverbBuffers RevBuffers; // buffer pointers for reverb, pre-calculated and pre-clipped.
V_ReverbBuffers RevBuffers; // buffer pointers for reverb, pre-calculated and pre-clipped. u32 EffectsStartA;
u32 EffectsStartA; u32 EffectsEndA;
u32 EffectsEndA; u32 ReverbX;
u32 ReverbX;
// Current size of the effects buffer. Pre-caculated when the effects start // Current size of the effects buffer. Pre-caculated when the effects start
// or end position registers are written. CAN BE NEGATIVE OR ZERO, in which // or end position registers are written. CAN BE NEGATIVE OR ZERO, in which
// case reverb should be disabled. // case reverb should be disabled.
s32 EffectsBufferSize; s32 EffectsBufferSize;
// Registers V_CoreRegs Regs; // Registers
V_CoreRegs Regs;
// Last samples to pass through the effects processor. // Last samples to pass through the effects processor.
// Used because the effects processor works at 24khz and just pulls // Used because the effects processor works at 24khz and just pulls
// from this for the odd Ts. // from this for the odd Ts.
StereoOut32 LastEffect; StereoOut32 LastEffect;
u8 InitDelay; u8 InitDelay;
u8 CoreEnabled;
u8 CoreEnabled; u8 AttrBit0;
u8 AttrBit4;
u8 AttrBit5;
u8 AttrBit0; u16* DMAPtr;
u8 AttrBit4; u32 MADR;
u8 AttrBit5; u32 TADR;
u16*DMAPtr; // HACK -- This is a temp buffer which is (or isn't?) used to circumvent some memory
u32 MADR; // corruption that originates elsewhere in the plugin. >_< The actual ADMA buffer
u32 TADR; // is an area mapped to SPU2 main memory.
s16 ADMATempBuffer[0x1000];
s16 ADMATempBuffer[0x1000]; // ----------------------------------------------------------------------------------
// V_Core Methods
// ----------------------------------------------------------------------------------
u32 ADMAPV; V_Core() : Index( -1 ) {} // uninitialized constructor
StereoOut32 ADMAP; V_Core( int idx ); // our badass constructor
virtual ~V_Core() throw();
void Reset(); void Reset();
void UpdateEffectsBufferSize(); void UpdateEffectsBufferSize();
V_Core(); // our badass constructor s32 EffectsBufferIndexer( s32 offset ) const;
s32 EffectsBufferIndexer( s32 offset ) const; void UpdateFeedbackBuffersA();
void UpdateFeedbackBuffersA(); void UpdateFeedbackBuffersB();
void UpdateFeedbackBuffersB();
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 ReadInputPV();
StereoOut32 ReadInput_HiFi( bool isCDDA );
// --------------------------------------------------------------------------
// 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(TDA);
++TDA; TDA &= 0xfffff;
return ret;
}
__forceinline void DmaWrite(u16 value)
{
spu2M_Write( TSA, value );
++TSA; TSA &= 0xfffff;
}
void LogAutoDMA( FILE* fp );
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_Core Cores[2];
extern V_SPDIF Spdif; extern V_SPDIF Spdif;
// Output Buffer Writing Position (the same for all data); // Output Buffer Writing Position (the same for all data);
extern s16 OutPos; extern s16 OutPos;
// Input Buffer Reading Position (the same for all data); // Input Buffer Reading Position (the same for all data);
extern s16 InputPos; extern s16 InputPos;
// SPU Mixing Cycles ("Ticks mixed" counter) // SPU Mixing Cycles ("Ticks mixed" counter)
extern u32 Cycles; extern u32 Cycles;
#ifdef __LINUX__ extern short* spu2regs;
extern short* _spu2mem;
extern int PlayMode;
#include <sys/types.h> extern void SetIrqCall();
#include <sys/timeb.h> extern void StartVoices(int core, u32 value);
extern void StopVoices(int core, u32 value);
extern void InitADSR();
extern void CalculateADSR( V_Voice& vc );
static __forceinline u32 timeGetTime() extern void spdif_set51(u32 is_5_1_out);
extern u32 spdif_init();
extern void spdif_shutdown();
extern void spdif_get_samples(s32 *samples); // fills the buffer with [l,r,c,lfe,sl,sr] if using 5.1 output, or [l,r] if using stereo
extern void UpdateSpdifMode();
namespace Savestate
{ {
struct timeb t; struct DataBlock;
ftime(&t);
return (u32)(t.time*1000+t.millitm); extern s32 __fastcall FreezeIt( DataBlock& spud );
extern s32 __fastcall ThawIt( DataBlock& spud );
extern s32 __fastcall SizeIt();
} }
#endif
// --------------------------------------------------------------------------------------
// ADPCM Decoder Cache
// --------------------------------------------------------------------------------------
// The SPU2 has a dynamic memory range which is used for several internal operations, such as
// registers, CORE 1/2 mixing, AutoDMAs, and some other fancy stuff. We exclude this range
// from the cache here:
static const s32 SPU2_DYN_MEMLINE = 0x2800;
// 8 short words per encoded PCM block. (as stored in SPU2 ram)
static const int pcm_WordsPerBlock = 8;
// number of cachable ADPCM blocks (any blocks above the SPU2_DYN_MEMLINE)
static const int pcm_BlockCount = 0x100000 / pcm_WordsPerBlock;
// 28 samples per decoded PCM block (as stored in our cache)
static const int pcm_DecodedSamplesPerBlock = 28;
struct PcmCacheEntry
{
bool Validated;
s16 Sampledata[pcm_DecodedSamplesPerBlock];
};
extern PcmCacheEntry* pcm_cache_data;

View File

@ -147,21 +147,21 @@ Core attributes (SD_C)
*********************************************************************/ *********************************************************************/
#define SPDIF_OUT_OFF 0x0000 //no spdif output #define SPDIF_OUT_OFF 0x0000 // no spdif output
#define SPDIF_OUT_PCM 0x0020 //encode spdif from spu2 pcm output #define SPDIF_OUT_PCM 0x0020 // encode spdif from spu2 pcm output
#define SPDIF_OUT_BYPASS 0x0100 //bypass spu2 processing #define SPDIF_OUT_BYPASS 0x0100 // bypass spu2 processing
#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 //bypass mode for digital bitstream data #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_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_CD 0x0800 // source media is a CD
#define SPDIF_MODE_MEDIA_DVD 0x0000 //source media is a DVD #define SPDIF_MODE_MEDIA_DVD 0x0000 // source media is a DVD
#define SPDIF_MEDIA_CDVD 0x0200 #define SPDIF_MEDIA_CDVD 0x0200
#define SPDIF_MEDIA_400 0x0000 #define SPDIF_MEDIA_400 0x0000
#define SPDIF_PROTECT_NORMAL 0x0000 // spdif stream is not protected #define SPDIF_PROTECT_NORMAL 0x0000 // spdif stream is not protected
#define SPDIF_PROTECT_PROHIBIT 0x8000 // spdif stream can't be copied #define SPDIF_PROTECT_PROHIBIT 0x8000 // spdif stream can't be copied
/********************************************************************/ /********************************************************************/

View File

@ -0,0 +1,146 @@
/* 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 = 0x0005;
static void wipe_the_cache()
{
memset( pcm_cache_data, 0, pcm_BlockCount * sizeof(PcmCacheEntry) );
}
static s16 old_state_sBuffer[pcm_DecodedSamplesPerBlock] = {0};
}
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;
memcpy(spud.unkregs, spu2regs, sizeof(spud.unkregs));
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();
// base stuff
memcpy(spu2regs, spud.unkregs, sizeof(spud.unkregs));
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);
}

View File

@ -15,50 +15,31 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>. * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Spu2.h" // ======================================================================================
// spu2sys.cpp -- Emulation module for the SPU2 'virtual machine'
// ======================================================================================
// This module contains (most!) stuff which is directly related to SPU2 emulation.
// Contents should be cross-platform compatible whenever possible.
#include "Global.h"
#include "RegTable.h" #include "RegTable.h"
#include "dma.h"
#ifdef __LINUX__ #include "PS2E-spu2.h" // needed until I figure out a nice solution for irqcallback dependencies.
#include "Linux.h"
#endif
void StartVoices(int core, u32 value);
void StopVoices(int core, u32 value);
void InitADSR();
#ifdef _MSC_VER
DWORD CALLBACK TimeThread(PVOID /* unused param */);
#endif
void (* _irqcallback)();
void (* dma4callback)();
void (* dma7callback)();
short *spu2regs; short *spu2regs;
short *_spu2mem; short *_spu2mem;
u8 callirq; V_CoreDebug DebugCores[2];
V_Core Cores[2];
V_SPDIF Spdif;
V_CoreDebug DebugCores[2]; s16 OutPos;
V_Core Cores[2]; s16 InputPos;
V_SPDIF Spdif; u32 Cycles;
s16 OutPos; int PlayMode;
s16 InputPos;
u32 Cycles;
u32* cyclePtr = NULL;
u32 lClocks = 0;
int PlayMode;
#ifdef _MSC_VER
HINSTANCE hInstance;
CRITICAL_SECTION threadSync;
HANDLE hThreadFunc;
u32 ThreadFuncID;
#endif
bool has_to_call_irq=false; bool has_to_call_irq=false;
@ -67,33 +48,6 @@ void SetIrqCall()
has_to_call_irq=true; has_to_call_irq=true;
} }
#ifndef __LINUX__
void SysMessage(const char *fmt, ...)
{
va_list list;
char tmp[512];
wchar_t wtmp[512];
va_start(list,fmt);
sprintf_s(tmp,fmt,list);
va_end(list);
swprintf_s(wtmp, L"%S", tmp);
MessageBox(0, wtmp, L"SPU2-X System Message", 0);
}
#else
void SysMessage(const char *fmt, ...)
{
va_list list;
char tmp[512];
wchar_t wtmp[512];
va_start(list,fmt);
sprintf(tmp,fmt,list);
va_end(list);
printf("%s", tmp);
}
#endif
__forceinline s16 * __fastcall GetMemPtr(u32 addr) __forceinline s16 * __fastcall GetMemPtr(u32 addr)
{ {
#ifndef DEBUG_FAST #ifndef DEBUG_FAST
@ -111,9 +65,7 @@ __forceinline s16 __fastcall spu2M_Read( u32 addr )
// writes a signed value to the SPU2 ram // writes a signed value to the SPU2 ram
// Invalidates the ADPCM cache in the process. // Invalidates the ADPCM cache in the process.
// Optimization note: don't use __forceinline because the footprint of this __forceinline void __fastcall spu2M_Write( u32 addr, s16 value )
// function is a little too heavy now. Better to let the compiler decide.
__inline void __fastcall spu2M_Write( u32 addr, s16 value )
{ {
// Make sure the cache is invalidated: // Make sure the cache is invalidated:
// (note to self : addr address WORDs, not bytes) // (note to self : addr address WORDs, not bytes)
@ -135,50 +87,55 @@ __inline void __fastcall spu2M_Write( u32 addr, u16 value )
spu2M_Write( addr, (s16)value ); spu2M_Write( addr, (s16)value );
} }
V_VolumeLR V_VolumeLR::Max( 0x7FFFFFFF ); V_VolumeLR V_VolumeLR::Max( 0x7FFFFFFF );
V_VolumeSlideLR V_VolumeSlideLR::Max( 0x3FFF, 0x7FFFFFFF ); V_VolumeSlideLR V_VolumeSlideLR::Max( 0x3FFF, 0x7FFFFFFF );
V_Core::V_Core() V_Core::V_Core( int coreidx ) : Index( coreidx )
//LogFile_AutoDMA( NULL )
{ {
/*char fname[128];
sprintf( fname, "logs/adma%d.raw", GetDmaIndex() );
LogFile_AutoDMA = fopen( fname, "wb" );*/
}
V_Core::~V_Core() throw()
{
// Can't use this yet because we dumb V_Core into savestates >_<
/*if( LogFile_AutoDMA != NULL )
{
fclose( LogFile_AutoDMA );
LogFile_AutoDMA = NULL;
}*/
} }
void V_Core::Reset() void V_Core::Reset()
{ {
memset( this, 0, sizeof(V_Core) ); memset( this, 0, sizeof(V_Core) );
const int c = (this == Cores) ? 0 : 1; const int c = Index;
Regs.STATX=0; Regs.STATX = 0;
Regs.ATTR=0; Regs.ATTR = 0;
ExtVol = V_VolumeLR::Max; ExtVol = V_VolumeLR::Max;
InpVol = V_VolumeLR::Max; InpVol = V_VolumeLR::Max;
FxVol = V_VolumeLR::Max; FxVol = V_VolumeLR::Max;
MasterVol = V_VolumeSlideLR::Max; MasterVol = V_VolumeSlideLR::Max;
DryGate.ExtL = -1; memset( &DryGate, -1, sizeof(DryGate) );
DryGate.ExtR = -1; memset( &WetGate, -1, sizeof(WetGate) );
WetGate.ExtL = -1;
WetGate.ExtR = -1;
DryGate.InpL = -1;
DryGate.InpR = -1;
WetGate.InpR = -1;
WetGate.InpL = -1;
DryGate.SndL = -1;
DryGate.SndR = -1;
WetGate.SndL = -1;
WetGate.SndR = -1;
Regs.MMIX = 0xFFCF; Regs.MMIX = 0xFFCF;
Regs.VMIXL = 0xFFFFFF; Regs.VMIXL = 0xFFFFFF;
Regs.VMIXR = 0xFFFFFF; Regs.VMIXR = 0xFFFFFF;
Regs.VMIXEL = 0xFFFFFF; Regs.VMIXEL = 0xFFFFFF;
Regs.VMIXER = 0xFFFFFF; Regs.VMIXER = 0xFFFFFF;
EffectsStartA= 0xEFFF8 + 0x10000*c; EffectsStartA = 0xEFFF8 + (0x10000*c);
EffectsEndA = 0xEFFFF + 0x10000*c; EffectsEndA = 0xEFFFF + (0x10000*c);
FxEnable=0;
IRQA=0xFFFF0; FxEnable = 0;
IRQEnable=1; IRQA = 0xFFFF0;
IRQEnable = 1;
for( uint v=0; v<NumVoices; ++v ) for( uint v=0; v<NumVoices; ++v )
{ {
@ -187,19 +144,20 @@ void V_Core::Reset()
VoiceGates[v].WetL = -1; VoiceGates[v].WetL = -1;
VoiceGates[v].WetR = -1; VoiceGates[v].WetR = -1;
Voices[v].Volume = V_VolumeSlideLR::Max; Voices[v].Volume = V_VolumeSlideLR::Max;
Voices[v].ADSR.Value = 0; Voices[v].ADSR.Value = 0;
Voices[v].ADSR.Phase = 0; Voices[v].ADSR.Phase = 0;
Voices[v].Pitch = 0x3FFF; Voices[v].Pitch = 0x3FFF;
Voices[v].NextA = 2800; Voices[v].NextA = 2800;
Voices[v].StartA = 2800; Voices[v].StartA = 2800;
Voices[v].LoopStartA = 2800; Voices[v].LoopStartA = 2800;
} }
DMAICounter = 0;
AdmaInProgress = 0;
Regs.STATX = 0x80; DMAICounter = 0;
AdmaInProgress = 0;
Regs.STATX = 0x80;
} }
s32 V_Core::EffectsBufferIndexer( s32 offset ) const s32 V_Core::EffectsBufferIndexer( s32 offset ) const
@ -456,7 +414,7 @@ __forceinline void TimeUpdate(u32 cClocks)
lClocks+=TickInterval; lClocks+=TickInterval;
Cycles++; Cycles++;
// Note: IPU does not use MMX regs, so no need to save them. // Note: IOP does not use MMX regs, so no need to save them.
//SaveMMXRegs(); //SaveMMXRegs();
Mix(); Mix();
//RestoreMMXRegs(); //RestoreMMXRegs();
@ -516,11 +474,12 @@ void V_VolumeSlide::RegSet( u16 src )
Value = GetVol32( src ); Value = GetVol32( src );
} }
void SPU_ps1_write(u32 mem, u16 value) void V_Core::WriteRegPS1( u32 mem, u16 value )
{ {
bool show=true; jASSUME( Index == 0 ); // Valid on Core 0 only!
u32 reg = mem&0xffff; bool show = true;
u32 reg = mem & 0xffff;
if((reg>=0x1c00)&&(reg<0x1d80)) if((reg>=0x1c00)&&(reg<0x1d80))
{ {
@ -530,42 +489,42 @@ void SPU_ps1_write(u32 mem, u16 value)
switch(vval) switch(vval)
{ {
case 0: //VOLL (Volume L) case 0: //VOLL (Volume L)
Cores[0].Voices[voice].Volume.Left.Mode = 0; Voices[voice].Volume.Left.Mode = 0;
Cores[0].Voices[voice].Volume.Left.RegSet( value << 1 ); Voices[voice].Volume.Left.RegSet( value << 1 );
Cores[0].Voices[voice].Volume.Left.Reg_VOL = value; Voices[voice].Volume.Left.Reg_VOL = value;
break; break;
case 1: //VOLR (Volume R) case 1: //VOLR (Volume R)
Cores[0].Voices[voice].Volume.Right.Mode = 0; Voices[voice].Volume.Right.Mode = 0;
Cores[0].Voices[voice].Volume.Right.RegSet( value << 1 ); Voices[voice].Volume.Right.RegSet( value << 1 );
Cores[0].Voices[voice].Volume.Right.Reg_VOL = value; Voices[voice].Volume.Right.Reg_VOL = value;
break; break;
case 2: Cores[0].Voices[voice].Pitch = value; break; case 2: Voices[voice].Pitch = value; break;
case 3: Cores[0].Voices[voice].StartA = (u32)value<<8; break; case 3: Voices[voice].StartA = (u32)value<<8; break;
case 4: // ADSR1 (Envelope) case 4: // ADSR1 (Envelope)
Cores[0].Voices[voice].ADSR.AttackMode = (value & 0x8000)>>15; Voices[voice].ADSR.AttackMode = (value & 0x8000)>>15;
Cores[0].Voices[voice].ADSR.AttackRate = (value & 0x7F00)>>8; Voices[voice].ADSR.AttackRate = (value & 0x7F00)>>8;
Cores[0].Voices[voice].ADSR.DecayRate = (value & 0xF0)>>4; Voices[voice].ADSR.DecayRate = (value & 0xF0)>>4;
Cores[0].Voices[voice].ADSR.SustainLevel = (value & 0xF); Voices[voice].ADSR.SustainLevel = (value & 0xF);
Cores[0].Voices[voice].ADSR.Reg_ADSR1 = value; Voices[voice].ADSR.Reg_ADSR1 = value;
break; break;
case 5: // ADSR2 (Envelope) case 5: // ADSR2 (Envelope)
Cores[0].Voices[voice].ADSR.SustainMode = (value & 0xE000)>>13; Voices[voice].ADSR.SustainMode = (value & 0xE000)>>13;
Cores[0].Voices[voice].ADSR.SustainRate = (value & 0x1FC0)>>6; Voices[voice].ADSR.SustainRate = (value & 0x1FC0)>>6;
Cores[0].Voices[voice].ADSR.ReleaseMode = (value & 0x20)>>5; Voices[voice].ADSR.ReleaseMode = (value & 0x20)>>5;
Cores[0].Voices[voice].ADSR.ReleaseRate = (value & 0x1F); Voices[voice].ADSR.ReleaseRate = (value & 0x1F);
Cores[0].Voices[voice].ADSR.Reg_ADSR2 = value; Voices[voice].ADSR.Reg_ADSR2 = value;
break; break;
case 6: case 6:
Cores[0].Voices[voice].ADSR.Value = ((s32)value<<16) | value; Voices[voice].ADSR.Value = ((s32)value<<16) | value;
ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value ); ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value );
break; break;
case 7: Cores[0].Voices[voice].LoopStartA = (u32)value <<8; break; case 7: Voices[voice].LoopStartA = (u32)value <<8; break;
jNO_DEFAULT; jNO_DEFAULT;
} }
@ -574,21 +533,21 @@ void SPU_ps1_write(u32 mem, u16 value)
else switch(reg) else switch(reg)
{ {
case 0x1d80:// Mainvolume left case 0x1d80:// Mainvolume left
Cores[0].MasterVol.Left.Mode = 0; MasterVol.Left.Mode = 0;
Cores[0].MasterVol.Left.RegSet( value ); MasterVol.Left.RegSet( value );
break; break;
case 0x1d82:// Mainvolume right case 0x1d82:// Mainvolume right
Cores[0].MasterVol.Right.Mode = 0; MasterVol.Right.Mode = 0;
Cores[0].MasterVol.Right.RegSet( value ); MasterVol.Right.RegSet( value );
break; break;
case 0x1d84:// Reverberation depth left case 0x1d84:// Reverberation depth left
Cores[0].FxVol.Left = GetVol32( value ); FxVol.Left = GetVol32( value );
break; break;
case 0x1d86:// Reverberation depth right case 0x1d86:// Reverberation depth right
Cores[0].FxVol.Right = GetVol32( value ); FxVol.Right = GetVol32( value );
break; break;
case 0x1d88:// Voice ON (0-15) case 0x1d88:// Voice ON (0-15)
@ -652,11 +611,11 @@ void SPU_ps1_write(u32 mem, u16 value)
break; break;
case 0x1da4: case 0x1da4:
Cores[0].IRQA=(u32)value<<8; IRQA = (u32)value<<8;
break; break;
case 0x1da6: case 0x1da6:
Cores[0].TSA=(u32)value<<8; TSA = (u32)value<<8;
break; break;
case 0x1daa: case 0x1daa:
@ -668,7 +627,7 @@ void SPU_ps1_write(u32 mem, u16 value)
break; break;
case 0x1da8:// Spu Write to Memory case 0x1da8:// Spu Write to Memory
DmaWrite(0,value); DmaWrite(value);
show=false; show=false;
break; break;
} }
@ -678,8 +637,10 @@ void SPU_ps1_write(u32 mem, u16 value)
spu2Ru16(mem)=value; spu2Ru16(mem)=value;
} }
u16 SPU_ps1_read(u32 mem) u16 V_Core::ReadRegPS1(u32 mem)
{ {
jASSUME( Index == 0 ); // Valid on Core 0 only!
bool show=true; bool show=true;
u16 value = spu2Ru16(mem); u16 value = spu2Ru16(mem);
@ -693,60 +654,60 @@ u16 SPU_ps1_read(u32 mem)
switch(vval) switch(vval)
{ {
case 0: //VOLL (Volume L) case 0: //VOLL (Volume L)
//value=Cores[0].Voices[voice].VolumeL.Mode; //value=Voices[voice].VolumeL.Mode;
//value=Cores[0].Voices[voice].VolumeL.Value; //value=Voices[voice].VolumeL.Value;
value = Cores[0].Voices[voice].Volume.Left.Reg_VOL; value = Voices[voice].Volume.Left.Reg_VOL;
break; break;
case 1: //VOLR (Volume R) case 1: //VOLR (Volume R)
//value=Cores[0].Voices[voice].VolumeR.Mode; //value=Voices[voice].VolumeR.Mode;
//value=Cores[0].Voices[voice].VolumeR.Value; //value=Voices[voice].VolumeR.Value;
value = Cores[0].Voices[voice].Volume.Right.Reg_VOL; value = Voices[voice].Volume.Right.Reg_VOL;
break; break;
case 2: value = Cores[0].Voices[voice].Pitch; break; case 2: value = Voices[voice].Pitch; break;
case 3: value = Cores[0].Voices[voice].StartA; break; case 3: value = Voices[voice].StartA; break;
case 4: value = Cores[0].Voices[voice].ADSR.Reg_ADSR1; break; case 4: value = Voices[voice].ADSR.Reg_ADSR1; break;
case 5: value = Cores[0].Voices[voice].ADSR.Reg_ADSR2; break; case 5: value = Voices[voice].ADSR.Reg_ADSR2; break;
case 6: value = Cores[0].Voices[voice].ADSR.Value >> 16; break; case 6: value = Voices[voice].ADSR.Value >> 16; break;
case 7: value = Cores[0].Voices[voice].LoopStartA; break; case 7: value = Voices[voice].LoopStartA; break;
jNO_DEFAULT; jNO_DEFAULT;
} }
} }
else switch(reg) else switch(reg)
{ {
case 0x1d80: value = Cores[0].MasterVol.Left.Value >> 16; break; case 0x1d80: value = MasterVol.Left.Value >> 16; break;
case 0x1d82: value = Cores[0].MasterVol.Right.Value >> 16; break; case 0x1d82: value = MasterVol.Right.Value >> 16; break;
case 0x1d84: value = Cores[0].FxVol.Left >> 16; break; case 0x1d84: value = FxVol.Left >> 16; break;
case 0x1d86: value = Cores[0].FxVol.Right >> 16; break; case 0x1d86: value = FxVol.Right >> 16; break;
case 0x1d88: value = 0; break; case 0x1d88: value = 0; break;
case 0x1d8a: value = 0; break; case 0x1d8a: value = 0; break;
case 0x1d8c: value = 0; break; case 0x1d8c: value = 0; break;
case 0x1d8e: value = 0; break; case 0x1d8e: value = 0; break;
case 0x1d90: value = Cores[0].Regs.PMON&0xFFFF; break; case 0x1d90: value = Regs.PMON&0xFFFF; break;
case 0x1d92: value = Cores[0].Regs.PMON>>16; break; case 0x1d92: value = Regs.PMON>>16; break;
case 0x1d94: value = Cores[0].Regs.NON&0xFFFF; break; case 0x1d94: value = Regs.NON&0xFFFF; break;
case 0x1d96: value = Cores[0].Regs.NON>>16; break; case 0x1d96: value = Regs.NON>>16; break;
case 0x1d98: value = Cores[0].Regs.VMIXEL&0xFFFF; break; case 0x1d98: value = Regs.VMIXEL&0xFFFF; break;
case 0x1d9a: value = Cores[0].Regs.VMIXEL>>16; break; case 0x1d9a: value = Regs.VMIXEL>>16; break;
case 0x1d9c: value = Cores[0].Regs.VMIXL&0xFFFF; break; case 0x1d9c: value = Regs.VMIXL&0xFFFF; break;
case 0x1d9e: value = Cores[0].Regs.VMIXL>>16; break; case 0x1d9e: value = Regs.VMIXL>>16; break;
case 0x1da2: case 0x1da2:
if( value != Cores[0].EffectsStartA>>3 ) if( value != EffectsStartA>>3 )
{ {
value = Cores[0].EffectsStartA>>3; value = EffectsStartA>>3;
Cores[0].UpdateEffectsBufferSize(); UpdateEffectsBufferSize();
Cores[0].ReverbX = 0; ReverbX = 0;
} }
break; break;
case 0x1da4: value = Cores[0].IRQA>>3; break; case 0x1da4: value = IRQA>>3; break;
case 0x1da6: value = Cores[0].TSA>>3; break; case 0x1da6: value = TSA>>3; break;
case 0x1daa: case 0x1daa:
value = SPU2read(REG_C_ATTR); value = SPU2read(REG_C_ATTR);
@ -755,7 +716,7 @@ u16 SPU_ps1_read(u32 mem)
value = 0; //SPU2read(REG_P_STATX)<<3; value = 0; //SPU2read(REG_P_STATX)<<3;
break; break;
case 0x1da8: case 0x1da8:
value = DmaRead(0); value = DmaRead();
show=false; show=false;
break; break;
} }
@ -930,6 +891,30 @@ void SPU2_FastWrite( u32 rmem, u16 value )
V_Core& thiscore = Cores[core]; V_Core& thiscore = Cores[core];
switch(omem) switch(omem)
{ {
case 0x1ac:
// ----------------------------------------------------------------------------
// 0x1ac / 0x5ac : direct-write to DMA address : special register (undocumented)
// ----------------------------------------------------------------------------
// On the GS, DMAs are actually pushed through a hardware register. Chances are the
// SPU works the same way, and "technically" *all* DMA data actually passes through
// the HW registers at 0x1ac (core0) and 0x5ac (core1). We handle normal DMAs in
// optimized block copy fashion elsewhere, but some games will write this register
// directly, so handle those here:
// Performance Note: If a game uses this extensively, it *will* be slow. I plan to
// fix that using a proper paged LUT someday.
for( int i=0; i<2; i++ )
{
if(Cores[i].IRQEnable && (Cores[i].IRQA == Cores[i].TSA))
{
Spdif.Info = 4 << i;
SetIrqCall();
}
}
thiscore.DmaWrite( value );
break;
case REG_C_ATTR: case REG_C_ATTR:
{ {
int irqe = thiscore.IRQEnable; int irqe = thiscore.IRQEnable;