* 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/>.
*/
#include "Spu2.h"
#include "Global.h"
static const s32 ADSR_MAX_VOL = 0x7fffffff;
@ -34,7 +34,7 @@ void InitADSR() // INIT ADSR
else
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 <stdexcept>
#include <string>
#include "Global.h"
#include "ConvertUTF.h"
using std::string;
using std::wstring;

View File

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

View File

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

View File

@ -15,23 +15,20 @@
* 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;
FILE *DMA4LogFile=0;
FILE *DMA7LogFile=0;
FILE *ADMA4LogFile=0;
FILE *ADMA7LogFile=0;
FILE *ADMAOutLogFile=0;
static FILE *DMA4LogFile = NULL;
static FILE *DMA7LogFile = NULL;
static FILE *ADMA4LogFile = NULL;
static FILE *ADMA7LogFile = NULL;
static FILE *ADMAOutLogFile = NULL;
FILE *REGWRTLogFile[2]={0,0};
int packcount=0;
u16* MBASE[2] = {0,0};
u16* DMABaseAddr;
static FILE *REGWRTLogFile[2] = {0,0};
void DMALogOpen()
{
@ -56,16 +53,6 @@ void DMA7LogWrite(void *lpData, u32 ulSize) {
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) {
if(!DMALog()) return;
if (!ADMAOutLogFile) return;
@ -79,118 +66,110 @@ void RegWriteLog(u32 core,u16 value)
fwrite(&value,2,1,REGWRTLogFile[core]);
}
void DMALogClose() {
if(!DMALog()) return;
if (DMA4LogFile) fclose(DMA4LogFile);
if (DMA7LogFile) fclose(DMA7LogFile);
if (REGWRTLogFile[0]) fclose(REGWRTLogFile[0]);
if (REGWRTLogFile[1]) fclose(REGWRTLogFile[1]);
if (ADMA4LogFile) fclose(ADMA4LogFile);
if (ADMA7LogFile) fclose(ADMA7LogFile);
if (ADMAOutLogFile) fclose(ADMAOutLogFile);
void DMALogClose()
{
safe_fclose(DMA4LogFile);
safe_fclose(DMA7LogFile);
safe_fclose(REGWRTLogFile[0]);
safe_fclose(REGWRTLogFile[1]);
safe_fclose(ADMA4LogFile);
safe_fclose(ADMA7LogFile);
safe_fclose(ADMAOutLogFile);
}
__forceinline u16 DmaRead(u32 core)
void V_Core::LogAutoDMA( FILE* fp )
{
const u16 ret = (u16)spu2M_Read(Cores[core].TDA);
Cores[core].TDA++;
Cores[core].TDA&=0xfffff;
return ret;
if( !DMALog() || !fp ) return;
fwrite( DMAPtr+InputDataProgress, 0x400, 1, fp );
}
__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 );
Cores[core].TSA++;
Cores[core].TSA&=0xfffff;
}
int spos = ((InputPos+0xff)&0x100); //starting position of the free buffer
void AutoDMAReadBuffer(int core, int mode) //mode: 0= split stereo; 1 = do not split stereo
{
int spos=((Cores[core].InputPos+0xff)&0x100); //starting position of the free buffer
LogAutoDMA( Index ? ADMA7LogFile : ADMA4LogFile );
if(core==0)
ADMA4LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400);
else
ADMA7LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400);
// HACKFIX!! DMAPtr can be invalid after a savestate load, so the savestate just forces it
// to NULL and we ignore it here. (used to work in old VM editions of PCSX2 with fixed
// addressing, but new PCSX2s have dynamic memory addressing).
if(mode)
{
//hacky :p
memcpy((Cores[core].ADMATempBuffer+(spos<<1)),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400);
Cores[core].MADR+=0x400;
Cores[core].InputDataLeft-=0x200;
Cores[core].InputDataProgress+=0x200;
{
if( DMAPtr != NULL )
memcpy((ADMATempBuffer+(spos<<1)),DMAPtr+InputDataProgress,0x400);
MADR+=0x400;
InputDataLeft-=0x200;
InputDataProgress+=0x200;
}
else
{
memcpy((Cores[core].ADMATempBuffer+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200);
//memcpy((spu2mem+0x2000+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200);
Cores[core].MADR+=0x200;
Cores[core].InputDataLeft-=0x100;
Cores[core].InputDataProgress+=0x100;
if( DMAPtr != NULL )
memcpy((ADMATempBuffer+spos),DMAPtr+InputDataProgress,0x200);
//memcpy((spu2mem+0x2000+(core<<10)+spos),DMAPtr+InputDataProgress,0x200);
MADR+=0x200;
InputDataLeft-=0x100;
InputDataProgress+=0x100;
memcpy((Cores[core].ADMATempBuffer+spos+0x200),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200);
//memcpy((spu2mem+0x2200+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200);
Cores[core].MADR+=0x200;
Cores[core].InputDataLeft-=0x100;
Cores[core].InputDataProgress+=0x100;
if( DMAPtr != NULL )
memcpy((ADMATempBuffer+spos+0x200),DMAPtr+InputDataProgress,0x200);
//memcpy((spu2mem+0x2200+(core<<10)+spos),DMAPtr+InputDataProgress,0x200);
MADR+=0x200;
InputDataLeft-=0x100;
InputDataProgress+=0x100;
}
// 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",
(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;
if((Cores[core].AutoDMACtrl&(core+1))==0)
InputDataProgress=0;
if((AutoDMACtrl&(Index+1))==0)
{
Cores[core].TSA=0x2000+(core<<10);
Cores[core].DMAICounter=size;
TSA=0x2000+(Index<<10);
DMAICounter=size;
}
else if(size>=512)
{
Cores[core].InputDataLeft=size;
if(Cores[core].AdmaInProgress==0)
InputDataLeft=size;
if(AdmaInProgress==0)
{
#ifdef PCM24_S1_INTERLEAVE
if((core==1)&&((PlayMode&8)==8))
if((Index==1)&&((PlayMode&8)==8))
{
AutoDMAReadBuffer(core,1);
AutoDMAReadBuffer(Index,1);
}
else
{
AutoDMAReadBuffer(core,0);
AutoDMAReadBuffer(Index,0);
}
#else
if(((PlayMode&4)==4)&&(core==0))
if(((PlayMode&4)==4)&&(Index==0))
Cores[0].InputPos=0;
AutoDMAReadBuffer(core,0);
AutoDMAReadBuffer(0);
#endif
if(size==512)
Cores[core].DMAICounter=size;
DMAICounter=size;
}
Cores[core].AdmaInProgress=1;
AdmaInProgress=1;
}
else
{
Cores[core].InputDataLeft=0;
Cores[core].DMAICounter=1;
InputDataLeft=0;
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.
// Not really important. Everything should work regardless,
@ -198,29 +177,29 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
#if 0
uptr pa = ((uptr)pMem)&7;
uptr pm = Cores[core].TSA&0x7;
uptr pm = TSA&0x7;
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 )
{
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
if(core==0)
if(Index==0)
DMA4LogWrite(pMem,size<<1);
else
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;
if( buff1end > 0x100000 )
{
@ -228,7 +207,7 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
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;
PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart];
PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd];
@ -240,14 +219,14 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
} while ( cacheLine != &cacheEnd );
//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:
// It starts at TSA and goes to buff1end.
const u32 buff1size = (buff1end-Cores[core].TSA);
memcpy( GetMemPtr( Cores[core].TSA ), pMem, buff1size*2 );
const u32 buff1size = (buff1end-TSA);
memcpy( GetMemPtr( TSA ), pMem, buff1size*2 );
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)
memcpy( GetMemPtr( 0 ), &pMem[buff1size], buff2end*2 );
Cores[core].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();
}
}
TDA = (buff2end+1) & 0xfffff;
}
else
{
// Buffer doesn't wrap/overflow!
// 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?
// If IRQA occurs between start and dest, flag it.
// (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();
}
Spdif.Info = 4 << i;
SetIrqCall();
}
}
Cores[core].TSA=Cores[core].TDA&0xFFFF0;
Cores[core].DMAICounter=size;
Cores[core].TADR=Cores[core].MADR+(size<<1);
if(IRQEnable)
{
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 = Cores[core].TSA + size;
u32 buff1end = TSA + size;
u32 buff2end = 0;
if( buff1end > 0x100000 )
{
@ -321,8 +293,8 @@ void SPU2readDMA(int core, u16* pMem, u32 size)
buff1end = 0x100000;
}
const u32 buff1size = (buff1end-Cores[core].TSA);
memcpy( pMem, GetMemPtr( Cores[core].TSA ), buff1size*2 );
const u32 buff1size = (buff1end-TSA);
memcpy( pMem, GetMemPtr( TSA ), buff1size*2 );
// Note on TSA's position after our copy finishes:
// IRQA should be measured by the end of the writepos+0x20. But the TDA
@ -335,146 +307,65 @@ void SPU2readDMA(int core, u16* pMem, u32 size)
memcpy( &pMem[buff1size], GetMemPtr( 0 ), buff2end*2 );
Cores[core].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();
}
}
}
TDA = (buff2end+0x20) & 0xfffff;
}
else
{
// Buffer doesn't wrap/overflow!
// 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)
{
// 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();
}
}
Spdif.Info = 4 << i;
SetIrqCall();
}
}
TSA = TDA & 0xFFFFF;
Cores[core].TSA=Cores[core].TDA & 0xFFFFF;
Cores[core].DMAICounter=size;
Cores[core].Regs.STATX &= ~0x80;
//Cores[core].Regs.ATTR |= 0x30;
Cores[core].TADR=Cores[core].MADR+(size<<1);
DMAICounter = size;
Regs.STATX &= ~0x80;
//Regs.ATTR |= 0x30;
TADR = MADR + (size<<1);
}
void SPU2writeDMA(int core, u16* pMem, u32 size)
void V_Core::DoDMAwrite(u16* pMem, u32 size)
{
if(cyclePtr != NULL) TimeUpdate(*cyclePtr);
Cores[core].DMAPtr=pMem;
DMAPtr = pMem;
if(size<2) {
//if(dma7callback) dma7callback();
Cores[core].Regs.STATX &= ~0x80;
//Cores[core].Regs.ATTR |= 0x30;
Cores[core].DMAICounter=1;
Regs.STATX &= ~0x80;
//Regs.ATTR |= 0x30;
DMAICounter=1;
return;
}
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)
{
Cores[core].TSA&=0x1fff;
StartADMAWrite(core,pMem,size);
TSA&=0x1fff;
StartADMAWrite(pMem,size);
}
else
{
DoDMAWrite(core,pMem,size);
PlainDMAWrite(pMem,size);
}
Cores[core].Regs.STATX &= ~0x80;
//Cores[core].Regs.ATTR |= 0x30;
Regs.STATX &= ~0x80;
//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
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#ifndef DMA_H_INCLUDED
#define DMA_H_INCLUDED
/* 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/>.
*/
void DMALogOpen();
void DMA4LogWrite(void *lpData, u32 ulSize);
void DMA7LogWrite(void *lpData, u32 ulSize);
void DMALogClose();
#pragma once
extern void DmaWrite(u32 core, u16 data);
extern u16 DmaRead(u32 core);
extern void AutoDMAReadBuffer(int core, int mode);
#endif // DMA_H_INCLUDED //
extern void DMALogOpen();
extern void DMA4LogWrite(void *lpData, u32 ulSize);
extern void DMA7LogWrite(void *lpData, u32 ulSize);
extern void DMALogClose();

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
* Developed and maintained by the Pcsx2 Development Team.
*
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
*
/* 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.
@ -14,95 +14,95 @@
* 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"
#include "Dialogs.h"
bool DebugEnabled=false;
bool _MsgToConsole=false;
bool _MsgKeyOnOff=false;
bool _MsgVoiceOff=false;
bool _MsgDMA=false;
bool _MsgAutoDMA=false;
bool _MsgOverruns=false;
bool _MsgCache=false;
bool _AccessLog=false;
bool _DMALog=false;
bool _WaveLog=false;
bool _CoresDump=false;
bool _MemDump=false;
bool _RegDump=false;
wchar_t AccessLogFileName[255];
wchar_t WaveLogFileName[255];
wchar_t DMA4LogFileName[255];
wchar_t DMA7LogFileName[255];
wchar_t CoresDumpFileName[255];
wchar_t MemDumpFileName[255];
wchar_t RegDumpFileName[255];
#ifdef SPU2X_DEVBUILD
static const int LATENCY_MAX = 3000;
#else
static const int LATENCY_MAX = 750;
#endif
static const int LATENCY_MIN = 40;
int AutoDMAPlayRate[2] = {0,0};
// MIXING
int Interpolation = 1;
/* values:
0: no interpolation (use nearest)
1. linear interpolation
2. cubic interpolation
*/
bool EffectsDisabled = false;
// OUTPUT
int SndOutLatencyMS = 160;
bool timeStretchDisabled = false;
u32 OutputModule = 0;
CONFIG_DSOUNDOUT Config_DSoundOut;
CONFIG_WAVEOUT Config_WaveOut;
CONFIG_XAUDIO2 Config_XAudio2;
// DSP
bool dspPluginEnabled = false;
int dspPluginModule = 0;
wchar_t dspPlugin[256];
bool StereoExpansionEnabled = false;
/*****************************************************************************/
void ReadSettings()
{
}
/*****************************************************************************/
void WriteSettings()
{
}
void configure()
{
ReadSettings();
}
void MessageBox(char const*, ...)
{
}
#include "Spu2.h"
#include "Dialogs.h"
bool DebugEnabled=false;
bool _MsgToConsole=false;
bool _MsgKeyOnOff=false;
bool _MsgVoiceOff=false;
bool _MsgDMA=false;
bool _MsgAutoDMA=false;
bool _MsgOverruns=false;
bool _MsgCache=false;
bool _AccessLog=false;
bool _DMALog=false;
bool _WaveLog=false;
bool _CoresDump=false;
bool _MemDump=false;
bool _RegDump=false;
wchar_t AccessLogFileName[255];
wchar_t WaveLogFileName[255];
wchar_t DMA4LogFileName[255];
wchar_t DMA7LogFileName[255];
wchar_t CoresDumpFileName[255];
wchar_t MemDumpFileName[255];
wchar_t RegDumpFileName[255];
#ifdef PCSX2_DEVBUILD
static const int LATENCY_MAX = 3000;
#else
static const int LATENCY_MAX = 750;
#endif
static const int LATENCY_MIN = 40;
int AutoDMAPlayRate[2] = {0,0};
// MIXING
int Interpolation = 1;
/* values:
0: no interpolation (use nearest)
1. linear interpolation
2. cubic interpolation
*/
bool EffectsDisabled = false;
// OUTPUT
int SndOutLatencyMS = 160;
bool timeStretchDisabled = false;
u32 OutputModule = 0;
CONFIG_DSOUNDOUT Config_DSoundOut;
CONFIG_WAVEOUT Config_WaveOut;
CONFIG_XAUDIO2 Config_XAudio2;
// DSP
bool dspPluginEnabled = false;
int dspPluginModule = 0;
wchar_t dspPlugin[256];
bool StereoExpansionEnabled = false;
/*****************************************************************************/
void ReadSettings()
{
}
/*****************************************************************************/
void WriteSettings()
{
}
void configure()
{
ReadSettings();
}
void MessageBox(char const*, ...)
{
}

View File

@ -103,8 +103,6 @@ public:
protected:
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
* Developed and maintained by the Pcsx2 Development Team.
*
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
*
/* 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.
@ -14,46 +14,46 @@
* 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 "Linux.h"
void SysMessage(char *fmt, ...) {
GtkWidget *Ok,*Txt;
GtkWidget *Box,*Box1;
va_list list;
char msg[512];
va_start(list, fmt);
vsprintf(msg, fmt, list);
va_end(list);
if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0;
MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(MsgDlg), "SPU2null Msg");
gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5);
Box = gtk_vbox_new(5, 0);
gtk_container_add(GTK_CONTAINER(MsgDlg), Box);
gtk_widget_show(Box);
Txt = gtk_label_new(msg);
gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5);
gtk_widget_show(Txt);
Box1 = gtk_hbutton_box_new();
gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0);
gtk_widget_show(Box1);
Ok = gtk_button_new_with_label("Ok");
gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL);
gtk_container_add(GTK_CONTAINER(Box1), Ok);
GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT);
gtk_widget_show(Ok);
gtk_widget_show(MsgDlg);
gtk_main();
}
#include "Linux.h"
void SysMessage(char *fmt, ...) {
GtkWidget *Ok,*Txt;
GtkWidget *Box,*Box1;
va_list list;
char msg[512];
va_start(list, fmt);
vsprintf(msg, fmt, list);
va_end(list);
if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0;
MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(MsgDlg), "SPU2null Msg");
gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5);
Box = gtk_vbox_new(5, 0);
gtk_container_add(GTK_CONTAINER(MsgDlg), Box);
gtk_widget_show(Box);
Txt = gtk_label_new(msg);
gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5);
gtk_widget_show(Txt);
Box1 = gtk_hbutton_box_new();
gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0);
gtk_widget_show(Box1);
Ok = gtk_button_new_with_label("Ok");
gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL);
gtk_container_add(GTK_CONTAINER(Box1), Ok);
GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT);
gtk_widget_show(Ok);
gtk_widget_show(MsgDlg);
gtk_main();
}

View File

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

View File

@ -15,8 +15,8 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Spu2.h"
#include <float.h>
#include "Global.h"
//#include <float.h>
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] );
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 );
return ApplyVolume( ReadInput(), InpVol );
}
/////////////////////////////////////////////////////////////////////////////////////////
@ -547,7 +534,7 @@ static __forceinline StereoOut32 MixVoice( uint coreidx, uint voiceidx )
vc.OutX = Value;
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)
@ -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.
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] );
thiscore.MasterVol.Update();
MasterVol.Update();
// Saturate final result to standard 16 bit range.
const VoiceMixSet Voices( clamp_mix( inVoices.Dry ), clamp_mix( inVoices.Wet ) );
// Write Mixed results To Output Area
spu2M_WriteFast( 0x1000 + (coreidx<<12) + OutPos, Voices.Dry.Left );
spu2M_WriteFast( 0x1200 + (coreidx<<12) + OutPos, Voices.Dry.Right );
spu2M_WriteFast( 0x1400 + (coreidx<<12) + OutPos, Voices.Wet.Left );
spu2M_WriteFast( 0x1600 + (coreidx<<12) + OutPos, Voices.Wet.Right );
spu2M_WriteFast( 0x1000 + (Index<<12) + OutPos, Voices.Dry.Left );
spu2M_WriteFast( 0x1200 + (Index<<12) + OutPos, Voices.Dry.Right );
spu2M_WriteFast( 0x1400 + (Index<<12) + OutPos, Voices.Wet.Left );
spu2M_WriteFast( 0x1600 + (Index<<12) + OutPos, Voices.Wet.Right );
// Write mixed results to logfile (if enabled)
WaveDump::WriteCore( coreidx, CoreSrc_DryVoiceMix, Voices.Dry );
WaveDump::WriteCore( coreidx, CoreSrc_WetVoiceMix, Voices.Wet );
WaveDump::WriteCore( Index, CoreSrc_DryVoiceMix, Voices.Dry );
WaveDump::WriteCore( Index, CoreSrc_WetVoiceMix, Voices.Wet );
// Mix in the Input data
StereoOut32 TD(
Input.Left & thiscore.DryGate.InpL,
Input.Right & thiscore.DryGate.InpR
Input.Left & DryGate.InpL,
Input.Right & DryGate.InpR
);
// Mix in the Voice data
TD.Left += Voices.Dry.Left & thiscore.DryGate.SndL;
TD.Right += Voices.Dry.Right & thiscore.DryGate.SndR;
TD.Left += Voices.Dry.Left & DryGate.SndL;
TD.Right += Voices.Dry.Right & DryGate.SndR;
// Mix in the External (nothing/core0) data
TD.Left += Ext.Left & thiscore.DryGate.ExtL;
TD.Right += Ext.Right & thiscore.DryGate.ExtR;
TD.Left += Ext.Left & DryGate.ExtL;
TD.Right += Ext.Right & DryGate.ExtR;
if( !EffectsDisabled )
{
//Reverb pointer advances regardless of the FxEnable bit...
Reverb_AdvanceBuffer( thiscore );
Reverb_AdvanceBuffer();
if( thiscore.FxEnable )
if( FxEnable )
{
// Mix Input, Voice, and External data:
StereoOut32 TW(
Input.Left & thiscore.WetGate.InpL,
Input.Right & thiscore.WetGate.InpR
Input.Left & WetGate.InpL,
Input.Right & WetGate.InpR
);
TW.Left += Voices.Wet.Left & thiscore.WetGate.SndL;
TW.Right += Voices.Wet.Right & thiscore.WetGate.SndR;
TW.Left += Ext.Left & thiscore.WetGate.ExtL;
TW.Right += Ext.Right & thiscore.WetGate.ExtR;
TW.Left += Voices.Wet.Left & WetGate.SndL;
TW.Right += Voices.Wet.Right & WetGate.SndR;
TW.Left += Ext.Left & WetGate.ExtL;
TW.Right += Ext.Right & WetGate.ExtR;
WaveDump::WriteCore( 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
// 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.Right *= 2;
WaveDump::WriteCore( coreidx, CoreSrc_PostReverb, RV );
WaveDump::WriteCore( Index, CoreSrc_PostReverb, RV );
// Mix Dry+Wet
return TD + ApplyVolume( RV, thiscore.FxVol );
return TD + ApplyVolume( RV, FxVol );
}
else
{
WaveDump::WriteCore( coreidx, CoreSrc_PreReverb, 0, 0 );
WaveDump::WriteCore( coreidx, CoreSrc_PostReverb, 0, 0 );
WaveDump::WriteCore( Index, CoreSrc_PreReverb, 0, 0 );
WaveDump::WriteCore( Index, CoreSrc_PostReverb, 0, 0 );
}
}
return TD;
@ -685,8 +658,8 @@ __forceinline void Mix()
// Note: Playmode 4 is SPDIF, which overrides other inputs.
StereoOut32 InputData[2] =
{
(PlayMode&4) ? StereoOut32::Empty : ReadInputPV( 0 ),
(PlayMode&8) ? StereoOut32::Empty : ReadInputPV( 1 )
(PlayMode&4) ? StereoOut32::Empty : Cores[0].ReadInputPV(),
(PlayMode&8) ? StereoOut32::Empty : Cores[1].ReadInputPV()
};
WaveDump::WriteCore( 0, CoreSrc_Input, InputData[0] );
@ -697,7 +670,7 @@ __forceinline void Mix()
MixCoreVoices( VoiceData[0], 0 );
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) )
Ext = StereoOut32::Empty;
@ -714,14 +687,14 @@ __forceinline void Mix()
WaveDump::WriteCore( 0, CoreSrc_External, Ext );
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 )
{
// Experimental CDDA support
// 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 );
}
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/>.
*/
#include "Spu2.h"
#include "Global.h"
#include "PS2E-spu2.h"
#include "dma.h"
#include "Dialogs.h"
#include "RegTable.h"
#ifdef _MSC_VER
#include "svnrev.h"
#else
#include <stdio.h>
#include <string.h>
# include "svnrev.h"
#endif
// [Air]: Adding the spu2init boolean wasn't necessary except to help me in
// 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...
// PCSX2 expects ASNI, not unicode, so this MUST always be char...
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
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 )
hInstance = hinstDLL;
else if( dwReason == DLL_PROCESS_DETACH )
{
// TODO : perform shutdown procedure, just in case PCSX2 itself failed
// to for some reason..
}
return TRUE;
}
#endif
@ -106,7 +113,7 @@ EXPORT_C_(char*) PS2EgetLibName()
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()
@ -126,6 +133,87 @@ EXPORT_C_(s32) SPU2test()
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()
{
#define MAKESURE(a,b) \
@ -147,13 +235,13 @@ EXPORT_C_(s32) SPU2init()
#endif
srand((unsigned)time(NULL));
if (spu2init)
if (IsInitialized)
{
ConLog( " * SPU2: Already initialized - Ignoring SPU2init signal." );
return 0;
}
spu2init=true;
IsInitialized = true;
spu2regs = (short*)malloc(0x010000);
_spu2mem = (short*)malloc(0x200000);
@ -181,8 +269,8 @@ EXPORT_C_(s32) SPU2init()
}
}
memset(spu2regs,0,0x010000);
memset(_spu2mem,0,0x200000);
memset(spu2regs, 0, 0x010000);
memset(_spu2mem, 0, 0x200000);
Cores[0].Reset();
Cores[1].Reset();
@ -217,7 +305,7 @@ EXPORT_C_(s32) SPU2init()
EXPORT_C_(s32) SPU2open(void *pDsp)
{
if( spu2open ) return 0;
if( IsOpened ) return 0;
FileLog("[%10d] SPU2 Open\n",Cycles);
@ -229,7 +317,7 @@ EXPORT_C_(s32) SPU2open(void *pDsp)
debugDialogOpen=1;
}*/
spu2open = true;
IsOpened = true;
try
{
SndBuffer::Init();
@ -247,7 +335,9 @@ EXPORT_C_(s32) SPU2open(void *pDsp)
EXPORT_C_(void) SPU2close()
{
if( !spu2open ) return;
if( !IsOpened ) return;
IsOpened = false;
FileLog("[%10d] SPU2 Close\n",Cycles);
#ifndef __LINUX__
@ -255,13 +345,12 @@ EXPORT_C_(void) SPU2close()
#endif
spdif_shutdown();
SndBuffer::Cleanup();
spu2open = false;
}
EXPORT_C_(void) SPU2shutdown()
{
if(!spu2init) return;
if(!IsInitialized) return;
IsInitialized = false;
ConLog( " * SPU2: Shutting down.\n" );
@ -285,12 +374,9 @@ EXPORT_C_(void) SPU2shutdown()
DMALogClose();
spu2init = false;
SAFE_FREE(spu2regs);
SAFE_FREE(_spu2mem);
SAFE_FREE( pcm_cache_data );
safe_free(spu2regs);
safe_free(_spu2mem);
safe_free( pcm_cache_data );
spu2regs = NULL;
_spu2mem = NULL;
@ -312,32 +398,8 @@ bool numpad_plus = false, numpad_plus_old = false;
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();
if( IsDevBuild )
{
/*numpad_plus = (GetAsyncKeyState(VK_ADD)&0x8000)!=0;
if(numpad_plus && !numpad_plus_old)
{
DoFullDump();
}
numpad_plus_old = numpad_plus;*/
}
if(cyclePtr != NULL)
{
TimeUpdate( *cyclePtr );
@ -366,7 +428,7 @@ EXPORT_C_(u16) SPU2read(u32 rmem)
if(rmem==0x1f9001AC)
{
ret = DmaRead(core);
ret = Cores[core].DmaRead();
}
else
{
@ -375,7 +437,7 @@ EXPORT_C_(u16) SPU2read(u32 rmem)
if (rmem>>16 == 0x1f80)
{
ret = SPU_ps1_read(rmem);
ret = Cores[0].ReadRegPS1(rmem);
}
else if( (mem&0xFFFF) >= 0x800 )
{
@ -400,44 +462,19 @@ EXPORT_C_(void) SPU2write(u32 rmem, u16 value)
s2r_writereg(Cycles,rmem,value);
#endif
if(rmem==0x1f9001ac)
{
//RegWriteLog(0,value);
if((Cores[0].IRQEnable)&&(Cores[0].TSA==Cores[0].IRQA))
{
Spdif.Info=4;
SetIrqCall();
}
spu2M_Write( Cores[0].TSA++, 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;
}
// Note: Reverb/Effects are very sensitive to having precise update timings.
// If the SPU2 isn't in in sync with the IOP, samples can end up playing at rather
// incorrect pitches and loop lengths.
if( cyclePtr != NULL )
TimeUpdate( *cyclePtr );
if (rmem>>16 == 0x1f80)
Cores[0].WriteRegPS1(rmem,value);
else
{
// Note: Reverb/Effects are very sensitive to having precise update timings.
// If the SPU2 isn't in in sync with the IOP, samples can end up playing at rather
// incorrect pitches and loop lengths.
if( cyclePtr != NULL )
TimeUpdate( *cyclePtr );
if (rmem>>16 == 0x1f80)
SPU_ps1_write(rmem,value);
else
{
SPU2writeLog( "write", rmem, value );
SPU2_FastWrite( rmem, value );
}
SPU2writeLog( "write", rmem, value );
SPU2_FastWrite( rmem, value );
}
}
@ -453,3 +490,29 @@ EXPORT_C_(int) SPU2setupRecording(int start, void* pData)
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/>.
*/
#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;
if((core==1)&&((PlayMode&8)==8))
//give 30 bit data (SndOut downsamples the rest of the way)
retval.Left >>= 2;
retval.Right >>= 2;
}
InputPos += 2;
//if( (InputPos==0x100) || (InputPos>=0x200) ) // CDDA mode?
if( InputPos >= 0x200 )
{
AdmaInProgress = 0;
if(InputDataLeft >= 0x200)
{
thiscore.InputPos&=~1;
// 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.
u8 k = (InputDataLeft >= InputDataProgress);
#ifdef PCM24_S1_INTERLEAVE
*PData.Left=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1))));
*PData.Right=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)+2)));
AutoDMAReadBuffer(1);
#else
s32 *pl=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos]);
s32 *pr=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos+0x200]);
PData.Left = *pl;
PData.Right = *pr;
AutoDMAReadBuffer(0);
#endif
AdmaInProgress = 1;
PData.Left >>= 2; //give 30 bit data (SndOut downsamples the rest of the way)
PData.Right >>= 2;
TSA = (Index<<10) + InputPos;
thiscore.InputPos+=2;
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))
if (InputDataLeft < 0x200)
{
tl=0;
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);
FileLog("[%10d] %s AutoDMA%c block end.\n", isCDDA ? "CDDA" : "SPDIF", Cycles, GetDmaIndexChar());
tl = (s32)thiscore.ADMATempBuffer[thiscore.InputPos];
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)
if( IsDevBuild )
{
u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress;
AutoDMAReadBuffer(core,0);
thiscore.AdmaInProgress=1;
thiscore.TSA=(core<<10)+thiscore.InputPos;
if (thiscore.InputDataLeft<0x200)
if(InputDataLeft > 0)
{
thiscore.AutoDMACtrl |= ~3;
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;
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
}
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
{
PData.Left = 0;
PData.Right = 0;
StereoOut32 retval;
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/>.
*/
#include "Spu2.h"
#include "Global.h"
#include "RegTable.h"
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/>.
*/
#include "Spu2.h"
#include "Global.h"
#include "RegTable.h"
// 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.
// (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) \
U16P(Cores[c].p)

View File

@ -19,10 +19,10 @@
#ifndef _REGTABLE_H_
#define _REGTABLE_H_
#define U16P(x) ( (u16*)&(x) )
#define U16P(x) ( (u16*)&(x) )
// 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!
extern const u16 zero;

View File

@ -15,52 +15,56 @@
* 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 );
static LPF_data lowpass_right( 11000, SampleRate );
// Low pass filters: Change these to 32 for a speedup (benchmarks needed to see if
// 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
// 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 -= thiscore.EffectsEndA+1;
pos += thiscore.EffectsStartA;
//pos = EffectsStartA + ((ReverbX + offset) % (u32)EffectsBufferSize);
pos -= EffectsEndA+1;
pos += EffectsStartA;
}
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 );
thiscore.ReverbX += 1;
//ReverbX = RevbGetIndexer( thiscore, 1 );
ReverbX += 1;
if( thiscore.ReverbX >= (u32)thiscore.EffectsBufferSize ) thiscore.ReverbX = 0;
if( ReverbX >= (u32)EffectsBufferSize ) ReverbX = 0;
//thiscore.ReverbX += 1;
//if(thiscore.ReverbX >= (u32)thiscore.EffectsBufferSize )
// thiscore.ReverbX %= (u32)thiscore.EffectsBufferSize;
//ReverbX += 1;
//if(ReverbX >= (u32)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,
// and use the previous calculation for this core instead.
if( (Cycles&1)==0 )
{
StereoOut32 retval( thiscore.LastEffect );
StereoOut32 retval( LastEffect );
// 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.
@ -68,15 +72,15 @@ StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input )
lowpass_left.sample( Input.Left / 32768.0 );
lowpass_right.sample( Input.Right / 32768.0 );
//thiscore.LastEffect = Input;
//LastEffect = Input;
return retval;
}
else
{
if( thiscore.RevBuffers.NeedsUpdated )
thiscore.UpdateEffectsBufferSize();
if( RevBuffers.NeedsUpdated )
UpdateEffectsBufferSize();
if( thiscore.EffectsBufferSize <= 0 )
if( EffectsBufferSize <= 0 )
{
// StartA is past EndA, so effects are disabled.
//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
// needing for this session of reverb.
const u32 src_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_SRC_A0 );
const u32 src_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_SRC_A1 );
const u32 src_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_SRC_B0 );
const u32 src_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_SRC_B1 );
const u32 src_a0 = RevbGetIndexer( RevBuffers.IIR_SRC_A0 );
const u32 src_a1 = RevbGetIndexer( RevBuffers.IIR_SRC_A1 );
const u32 src_b0 = RevbGetIndexer( RevBuffers.IIR_SRC_B0 );
const u32 src_b1 = RevbGetIndexer( RevBuffers.IIR_SRC_B1 );
const u32 dest_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_A0 );
const u32 dest_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_A1 );
const u32 dest_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_B0 );
const u32 dest_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_B1 );
const u32 dest_a0 = RevbGetIndexer( RevBuffers.IIR_DEST_A0 );
const u32 dest_a1 = RevbGetIndexer( RevBuffers.IIR_DEST_A1 );
const u32 dest_b0 = RevbGetIndexer( RevBuffers.IIR_DEST_B0 );
const u32 dest_b1 = RevbGetIndexer( RevBuffers.IIR_DEST_B1 );
const u32 dest2_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_A0 + 1 );
const u32 dest2_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_A1 + 1 );
const u32 dest2_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_B0 + 1 );
const u32 dest2_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_B1 + 1 );
const u32 dest2_a0 = RevbGetIndexer( RevBuffers.IIR_DEST_A0 + 1 );
const u32 dest2_a1 = RevbGetIndexer( RevBuffers.IIR_DEST_A1 + 1 );
const u32 dest2_b0 = RevbGetIndexer( RevBuffers.IIR_DEST_B0 + 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_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_B0 );
const u32 acc_src_c0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_C0 );
const u32 acc_src_d0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_D0 );
const u32 acc_src_a0 = RevbGetIndexer( RevBuffers.ACC_SRC_A0 );
const u32 acc_src_b0 = RevbGetIndexer( RevBuffers.ACC_SRC_B0 );
const u32 acc_src_c0 = RevbGetIndexer( RevBuffers.ACC_SRC_C0 );
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_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_B1 );
const u32 acc_src_c1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_C1 );
const u32 acc_src_d1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_D1 );
const u32 acc_src_a1 = RevbGetIndexer( RevBuffers.ACC_SRC_A1 );
const u32 acc_src_b1 = RevbGetIndexer( RevBuffers.ACC_SRC_B1 );
const u32 acc_src_c1 = RevbGetIndexer( RevBuffers.ACC_SRC_C1 );
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_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.FB_SRC_A1 );
const u32 fb_src_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.FB_SRC_B0 );
const u32 fb_src_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.FB_SRC_B1 );
const u32 fb_src_a0 = RevbGetIndexer( RevBuffers.FB_SRC_A0 );
const u32 fb_src_a1 = RevbGetIndexer( RevBuffers.FB_SRC_A1 );
const u32 fb_src_b0 = RevbGetIndexer( RevBuffers.FB_SRC_B0 );
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_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.MIX_DEST_A1 );
const u32 mix_dest_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.MIX_DEST_B0 );
const u32 mix_dest_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.MIX_DEST_B1 );
const u32 mix_dest_a0 = RevbGetIndexer( RevBuffers.MIX_DEST_A0 );
const u32 mix_dest_a1 = RevbGetIndexer( RevBuffers.MIX_DEST_A1 );
const u32 mix_dest_b0 = RevbGetIndexer( RevBuffers.MIX_DEST_B0 );
const u32 mix_dest_b1 = RevbGetIndexer( RevBuffers.MIX_DEST_B1 );
// -----------------------------------------
// 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.
// Decisions, Decisions! Should we mix in the 22khz sample skipped, or not?
// First one mixes in the 22hkz sample. Second one does not.
/*StereoOut32 INPUT_SAMPLE(
(s32)(lowpass_left.sample( (Input.Left+thiscore.LastEffect.Left) / 32768.0 ) * 32768.0),
(s32)(lowpass_right.sample( (Input.Right+thiscore.LastEffect.Right) / 32768.0 ) * 32768.0)
(s32)(lowpass_left.sample( (Input.Left+LastEffect.Left) / 32768.0 ) * 32768.0),
(s32)(lowpass_right.sample( (Input.Right+LastEffect.Right) / 32768.0 ) * 32768.0)
);*/
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)
);
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_A1 = ((_spu2mem[src_a1] * thiscore.Revb.IIR_COEF) + (INPUT_SAMPLE.Right * thiscore.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_B1 = ((_spu2mem[src_b1] * thiscore.Revb.IIR_COEF) + (INPUT_SAMPLE.Right * thiscore.Revb.IN_COEF_R))>>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] * Revb.IIR_COEF) + (INPUT_SAMPLE.Right * Revb.IN_COEF_R))>>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] * 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_A1 = (IIR_INPUT_A1 * thiscore.Revb.IIR_ALPHA) + (_spu2mem[dest_a1] * (0x7fff - thiscore.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_B1 = (IIR_INPUT_B1 * thiscore.Revb.IIR_ALPHA) + (_spu2mem[dest_b1] * (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 * Revb.IIR_ALPHA) + (_spu2mem[dest_a1] * (0x7fff - 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 * Revb.IIR_ALPHA) + (_spu2mem[dest_b1] * (0x7fff - Revb.IIR_ALPHA));
_spu2mem[dest2_a0] = clamp_mix( IIR_A0 >> 16 );
_spu2mem[dest2_a1] = clamp_mix( IIR_A1 >> 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:
// (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_A1 = IIR_INPUT_A1 + (((_spu2mem[dest_a1]-IIR_INPUT_A1) * thiscore.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_B1 = IIR_INPUT_B1 + (((_spu2mem[dest_b1]-IIR_INPUT_B1) * 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) * 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) * Revb.IIR_ALPHA)>>16);
_spu2mem[dest2_a0] = clamp_mix( IIR_A0 );
_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 );*/
const s32 ACC0 =
((_spu2mem[acc_src_a0] * thiscore.Revb.ACC_COEF_A)) +
((_spu2mem[acc_src_b0] * thiscore.Revb.ACC_COEF_B)) +
((_spu2mem[acc_src_c0] * thiscore.Revb.ACC_COEF_C)) +
((_spu2mem[acc_src_d0] * thiscore.Revb.ACC_COEF_D));
((_spu2mem[acc_src_a0] * Revb.ACC_COEF_A)) +
((_spu2mem[acc_src_b0] * Revb.ACC_COEF_B)) +
((_spu2mem[acc_src_c0] * Revb.ACC_COEF_C)) +
((_spu2mem[acc_src_d0] * Revb.ACC_COEF_D));
const s32 ACC1 =
((_spu2mem[acc_src_a1] * thiscore.Revb.ACC_COEF_A)) +
((_spu2mem[acc_src_b1] * thiscore.Revb.ACC_COEF_B)) +
((_spu2mem[acc_src_c1] * thiscore.Revb.ACC_COEF_C)) +
((_spu2mem[acc_src_d1] * thiscore.Revb.ACC_COEF_D));
((_spu2mem[acc_src_a1] * Revb.ACC_COEF_A)) +
((_spu2mem[acc_src_b1] * Revb.ACC_COEF_B)) +
((_spu2mem[acc_src_c1] * Revb.ACC_COEF_C)) +
((_spu2mem[acc_src_d1] * Revb.ACC_COEF_D));
const s32 FB_A0 = (_spu2mem[fb_src_a0] * thiscore.Revb.FB_ALPHA);
const s32 FB_A1 = (_spu2mem[fb_src_a1] * thiscore.Revb.FB_ALPHA);
const s32 FB_A0 = (_spu2mem[fb_src_a0] * 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_a1 = _spu2mem[fb_src_a1] * ( 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] * ( Revb.FB_ALPHA ^ 0x8000 );
_spu2mem[mix_dest_a0] = clamp_mix( (ACC0 - FB_A0) >> 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_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_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(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];
thiscore.LastEffect.Right = _spu2mem[mix_dest_a1] + _spu2mem[mix_dest_b1];
LastEffect.Left = _spu2mem[mix_dest_a0] + _spu2mem[mix_dest_b0];
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);
//thiscore.LastEffect.Right = (s32)(lowpass_right.sample( thiscore.LastEffect.Right / 32768.0 ) * 32768.0);
//LastEffect.Left = (s32)(lowpass_left.sample( LastEffect.Left / 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/>.
*/
#include "Spu2.h"
#include "Global.h"
StereoOut32 StereoOut32::Empty( 0, 0 );
@ -56,11 +56,7 @@ public:
s32 Init() { return 0; }
void Close() { }
s32 Test() const { return 0; }
#ifdef _MSC_VER
void Configure(HWND parent) { }
#else
void Configure(uptr parent) { }
#endif
bool Is51Out() const { return false; }
int GetEmptySampleCount() const { return 0; }
@ -290,9 +286,9 @@ void SndBuffer::Cleanup()
{
mods[OutputModule]->Close();
SAFE_DELETE_ARRAY( m_buffer );
SAFE_DELETE_ARRAY( sndTempBuffer );
SAFE_DELETE_ARRAY( sndTempBuffer16 );
safe_delete_array( m_buffer );
safe_delete_array( sndTempBuffer );
safe_delete_array( sndTempBuffer16 );
}
int SndBuffer::m_dsp_progress = 0;
@ -375,15 +371,3 @@ s32 SndBuffer::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
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#ifndef SNDOUT_H_INCLUDE
#define SNDOUT_H_INCLUDE
/* 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 "BaseTypes.h"
#include "Lowpass.h"
#pragma once
// Number of stereo samples per SndOut block.
// All drivers must work in units of this size when communicating with
@ -35,7 +31,7 @@ static const int SndOutVolumeShift = 13;
// is too problematic. :)
static const int SampleRate = 48000;
int FindOutputModuleById( const wchar_t* omodid );
extern int FindOutputModuleById( const wchar_t* omodid );
struct StereoOut16
{
@ -231,9 +227,9 @@ struct Stereo51Out16DplII
s32 Tfl=(RAccum)*255/(LAccum);
s32 Tfr=(LAccum)*255/(RAccum);
int gMax = max(Tfl,Tfr);
Tfl=Tfl*255/gMax;
Tfr=Tfr*255/gMax;
int gMax = std::max(Tfl,Tfr);
Tfl = Tfl*255/gMax;
Tfr = Tfr*255/gMax;
if(Tfl>255) Tfl=255;
if(Tfr>255) Tfr=255;
@ -393,12 +389,6 @@ public:
static s32 Test();
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
// 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
@ -474,11 +464,7 @@ public:
virtual s32 Test() const=0;
// 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;
#endif
// Loads settings from the INI file for this driver
virtual void ReadSettings()=0;
@ -503,4 +489,13 @@ extern SndOutModule* XAudio2Out;
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
//
#include <stdio.h>
#include "Spu2.h"
#include "Global.h"
#include "PS2E-spu2.h"
FILE* s2rfile;
@ -115,6 +114,7 @@ void dummy7()
#define Cread(a,b,c,d) if(fread(a,b,c,d)<b) break;
#ifdef _MSC_VER
#include "Windows/Dialogs.h"
EXPORT_C_(void) s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow)
{
// 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_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;

View File

@ -15,7 +15,7 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Spu2.h"
#include "Global.h"
#include "SoundTouch/SoundTouch.h"
#include "SoundTouch/WavFile.h"
@ -304,9 +304,7 @@ void SndBuffer::soundtouchInit()
pSoundTouch->setSetting( SETTING_USE_QUICKSEEK, 0 );
pSoundTouch->setSetting( SETTING_USE_AA_FILTER, 0 );
pSoundTouch->setSetting( SETTING_SEQUENCE_MS, SoundtouchCfg::SequenceLenMS );
pSoundTouch->setSetting( SETTING_SEEKWINDOW_MS, SoundtouchCfg::SeekWindowMS );
pSoundTouch->setSetting( SETTING_OVERLAP_MS, SoundtouchCfg::OverlapMS );
SoundtouchCfg::ApplySettings( *pSoundTouch );
pSoundTouch->setTempo(1);
@ -340,5 +338,5 @@ void SndBuffer::soundtouchClearContents()
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/>.
*/
#include <stdexcept>
#include <new>
#include "Spu2.h"
#include "Global.h"
#include "SoundTouch/WavFile.h"
static WavOutFile* _new_WavOutFile( const char* destfile )
@ -52,7 +48,7 @@ namespace WaveDump
{
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",
cidx, m_tbl_CoreOutputTypeNames[ srcidx ] );
@ -77,7 +73,7 @@ namespace WaveDump
{
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()
{
SAFE_DELETE_OBJ( m_wavrecord );
safe_delete( m_wavrecord );
try
{
@ -114,7 +110,7 @@ void RecordStart()
void RecordStop()
{
SAFE_DELETE_OBJ( m_wavrecord );
safe_delete( m_wavrecord );
}
void RecordWrite( const StereoOut16& sample )

View File

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

View File

@ -15,8 +15,22 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Global.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";

View File

@ -15,9 +15,10 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Global.h"
#include "Dialogs.h"
#ifdef SPU2X_DEVBUILD
#ifdef PCSX2_DEVBUILD
static const int LATENCY_MAX = 3000;
#else
static const int LATENCY_MAX = 750;
@ -25,8 +26,6 @@ static const int LATENCY_MAX = 750;
static const int LATENCY_MIN = 40;
int AutoDMAPlayRate[2] = {0,0};
// MIXING
int Interpolation = 1;
/* values:
@ -57,9 +56,6 @@ bool StereoExpansionEnabled = false;
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 );
timeStretchDisabled = CfgReadBool( L"OUTPUT", L"Disable_Timestretch", false );
@ -107,9 +103,6 @@ void WriteSettings()
{
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);
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;
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;
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/>.
*/
#include "Global.h"
#include "Dialogs.h"

View File

@ -15,13 +15,33 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Global.h"
#include "Dialogs.h"
int SoundtouchCfg::SequenceLenMS = 63;
int SoundtouchCfg::SeekWindowMS = 16;
int SoundtouchCfg::OverlapMS = 7;
#include "SoundTouch/SoundTouch.h"
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( SeekWindowMS, SeekWindow_Min, SeekWindow_Max );
@ -101,7 +121,7 @@ void SoundtouchCfg::OpenDialog( HWND hWnd )
ret = DialogBox( hInstance, MAKEINTRESOURCE(IDD_CONFIG_SOUNDTOUCH), hWnd, (DLGPROC)DialogProc );
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;
}
ReadSettings();

View File

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

View File

@ -16,6 +16,7 @@
*/
#include "Global.h"
#include "Dialogs.h"
#include "../RegTable.h"
@ -59,7 +60,7 @@ static BOOL CALLBACK DebugProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
return TRUE;
}
#ifdef SPU2X_DEVBUILD
#ifdef PCSX2_DEVBUILD
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/>.
*/
#include "Global.h"
#define _WIN32_DCOM
#include "Dialogs.h"
@ -103,6 +105,8 @@ private:
public:
s32 Init()
{
CoInitializeEx( NULL, COINIT_MULTITHREADED );
//
// Initialize DSound
//
@ -180,7 +184,7 @@ public:
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." );
buffer_->Release();
@ -242,11 +246,12 @@ public:
buffer_events[i] = NULL;
}
SAFE_RELEASE( buffer_notify );
SAFE_RELEASE( buffer );
safe_release( buffer_notify );
safe_release( buffer );
}
SAFE_RELEASE( dsound );
safe_release( dsound );
CoUninitialize();
}
private:
@ -406,13 +411,13 @@ private:
static BOOL CALLBACK DSEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext );
public:
virtual void Configure(HWND parent)
virtual void Configure(uptr parent)
{
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)
{
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;
}
}

View File

@ -15,11 +15,13 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Global.h"
#define _WIN32_DCOM
#include "Dialogs.h"
#include <xaudio2.h>
#include <atlbase.h>
#include <xaudio2.h>
namespace Exception
{
@ -181,7 +183,7 @@ private:
killMe->FlushSourceBuffers();
EnterCriticalSection( &cs );
killMe->DestroyVoice();
SAFE_DELETE_ARRAY( qbuffer );
safe_delete_array( qbuffer );
LeaveCriticalSection( &cs );
DeleteCriticalSection( &cs );
}
@ -225,7 +227,7 @@ private:
};
IXAudio2* pXAudio2;
CComPtr<IXAudio2> pXAudio2;
IXAudio2MasteringVoice* pMasteringVoice;
BaseStreamingVoice* voiceContext;
@ -314,7 +316,7 @@ public:
catch( Exception::XAudio2Error& ex )
{
SysMessage( ex.CMessage() );
SAFE_RELEASE( pXAudio2 );
pXAudio2.Release();
CoUninitialize();
return -1;
}
@ -333,7 +335,7 @@ public:
// 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:
SAFE_DELETE_OBJ( voiceContext );
safe_delete( voiceContext );
voiceContext = NULL;
@ -342,12 +344,11 @@ public:
pMasteringVoice = NULL;
SAFE_RELEASE( pXAudio2 );
pXAudio2.Release();
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/>.
*/
#include "Global.h"
#include "Dialogs.h"
#include <windows.h>
class WaveOutModule: public SndOutModule
@ -197,7 +197,7 @@ public:
}
waveOutClose(hwodevice);
SAFE_DELETE_ARRAY( qbuffer );
safe_delete_array( qbuffer );
}
private:
@ -271,13 +271,13 @@ private:
}
public:
virtual void Configure(HWND parent)
virtual void Configure(uptr parent)
{
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)
{
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;
}
}

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/>.
*/
#include "Global.h"
#include "Dialogs.h"
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
//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" {
#include "dsp.h"

View File

@ -17,12 +17,27 @@
#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
{
static V_VolumeLR Max;
s32 Left;
s32 Right;
s32 Left;
s32 Right;
V_VolumeLR() {}
V_VolumeLR( s32 both ) :
@ -39,10 +54,10 @@ struct V_VolumeSlide
// Holds the "original" value of the volume for this voice, prior to slides.
// (ie, the volume as written to the register)
s16 Reg_VOL;
s32 Value;
s8 Increment;
s8 Mode;
s16 Reg_VOL;
s32 Value;
s8 Increment;
s8 Mode;
public:
V_VolumeSlide() {}
@ -57,7 +72,6 @@ public:
void Update();
void RegSet( u16 src ); // used to set the volume from a register source (16 bit signed)
void DebugDump( FILE* dump, const char* title, const char* nameLR );
};
struct V_VolumeSlideLR
@ -304,135 +318,235 @@ struct V_VoiceGates
s16 WetR; // 'AND Gate' for Effect Output for Right Channel
};
union V_CoreGates
struct V_CoreGates
{
struct
union
{
u64 lo;
u64 hi;
} v128;
u128 v128;
struct
{
s16 InpL; // Sound Data Input to Direct Output (Left)
s16 InpR; // Sound Data Input to Direct Output (Right)
s16 SndL; // Voice Data to Direct Output (Left)
s16 SndR; // Voice Data to Direct Output (Right)
s16 ExtL; // External Input to Direct Output (Left)
s16 ExtR; // External Input to Direct Output (Right)
struct
{
s16 InpL; // Sound Data Input to Direct Output (Left)
s16 InpR; // Sound Data Input to Direct Output (Right)
s16 SndL; // Voice Data to Direct Output (Left)
s16 SndR; // Voice Data to Direct Output (Right)
s16 ExtL; // External Input to Direct Output (Left)
s16 ExtR; // External Input to Direct Output (Right)
};
};
};
struct VoiceMixSet
{
static const VoiceMixSet Empty;
StereoOut32 Dry, Wet;
VoiceMixSet() {}
VoiceMixSet( const StereoOut32& dry, const StereoOut32& wet ) :
Dry( dry ),
Wet( wet )
{
}
};
struct V_Core
{
static const uint NumVoices = 24;
int Index; // Core index identifier.
// Voice Gates -- These are SSE-related values, and must always be
// first to ensure 16 byte alignment
V_VoiceGates VoiceGates[NumVoices];
V_CoreGates DryGate;
V_CoreGates WetGate;
V_VoiceGates VoiceGates[NumVoices];
V_CoreGates DryGate;
V_CoreGates WetGate;
V_VolumeSlideLR MasterVol;// Master Volume
V_VolumeLR ExtVol; // Volume for External Data Input
V_VolumeLR InpVol; // Volume for Sound Data Input
V_VolumeLR FxVol; // Volume for Output from Effects
V_VolumeSlideLR MasterVol; // Master Volume
V_VolumeLR ExtVol; // Volume for External Data Input
V_VolumeLR InpVol; // Volume for Sound Data Input
V_VolumeLR FxVol; // Volume for Output from Effects
V_Voice Voices[NumVoices];
V_Voice Voices[NumVoices];
// Interrupt Address
u32 IRQA;
// DMA Transfer Start Address
u32 TSA;
// DMA Transfer Data Address (Internal...)
u32 TDA;
u32 IRQA; // Interrupt Address
u32 TSA; // DMA Transfer Start Address
u32 TDA; // DMA Transfer Data Address (Internal...)
// Interrupt Enable
s8 IRQEnable;
// DMA related?
s8 DMABits;
// Effect Enable
s8 FxEnable;
// Noise Clock
s8 NoiseClk;
// AutoDMA Status
u16 AutoDMACtrl;
// DMA Interrupt Counter
s32 DMAICounter;
// Mute
s8 Mute;
// Input Buffer
u32 InputDataLeft;
u32 InputPos;
u32 InputDataProgress;
u8 AdmaInProgress;
s8 IRQEnable; // Interrupt Enable
s8 DMABits; // DMA related?
s8 FxEnable; // Effect Enable
s8 NoiseClk; // Noise Clock
u16 AutoDMACtrl; // AutoDMA Status
s32 DMAICounter; // DMA Interrupt Counter
s8 Mute; // Mute
u32 InputDataLeft; // Input Buffer
u32 InputPos;
u32 InputDataProgress;
u8 AdmaInProgress;
// Reverb
V_Reverb Revb;
V_ReverbBuffers RevBuffers; // buffer pointers for reverb, pre-calculated and pre-clipped.
u32 EffectsStartA;
u32 EffectsEndA;
u32 ReverbX;
V_Reverb Revb; // Reverb Registers
V_ReverbBuffers RevBuffers; // buffer pointers for reverb, pre-calculated and pre-clipped.
u32 EffectsStartA;
u32 EffectsEndA;
u32 ReverbX;
// 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
// case reverb should be disabled.
s32 EffectsBufferSize;
s32 EffectsBufferSize;
// Registers
V_CoreRegs Regs;
V_CoreRegs Regs; // Registers
// Last samples to pass through the effects processor.
// Used because the effects processor works at 24khz and just pulls
// 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;
u8 AttrBit4;
u8 AttrBit5;
u16* DMAPtr;
u32 MADR;
u32 TADR;
u16*DMAPtr;
u32 MADR;
u32 TADR;
// HACK -- This is a temp buffer which is (or isn't?) used to circumvent some memory
// corruption that originates elsewhere in the plugin. >_< The actual ADMA buffer
// is an area mapped to SPU2 main memory.
s16 ADMATempBuffer[0x1000];
s16 ADMATempBuffer[0x1000];
// ----------------------------------------------------------------------------------
// V_Core Methods
// ----------------------------------------------------------------------------------
u32 ADMAPV;
StereoOut32 ADMAP;
V_Core() : Index( -1 ) {} // uninitialized constructor
V_Core( int idx ); // our badass constructor
virtual ~V_Core() throw();
void Reset();
void UpdateEffectsBufferSize();
void Reset();
void UpdateEffectsBufferSize();
V_Core(); // our badass constructor
s32 EffectsBufferIndexer( s32 offset ) const;
void UpdateFeedbackBuffersA();
void UpdateFeedbackBuffersB();
s32 EffectsBufferIndexer( s32 offset ) const;
void UpdateFeedbackBuffersA();
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_SPDIF Spdif;
extern V_Core Cores[2];
extern V_SPDIF Spdif;
// Output Buffer Writing Position (the same for all data);
extern s16 OutPos;
extern s16 OutPos;
// Input Buffer Reading Position (the same for all data);
extern s16 InputPos;
extern s16 InputPos;
// 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>
#include <sys/timeb.h>
extern void SetIrqCall();
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;
ftime(&t);
return (u32)(t.time*1000+t.millitm);
struct DataBlock;
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_PCM 0x0020 //encode spdif from spu2 pcm output
#define SPDIF_OUT_BYPASS 0x0100 //bypass spu2 processing
#define SPDIF_OUT_OFF 0x0000 // no spdif output
#define SPDIF_OUT_PCM 0x0020 // encode spdif from spu2 pcm output
#define SPDIF_OUT_BYPASS 0x0100 // bypass spu2 processing
#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 //bypass mode for digital bitstream data
#define SPDIF_MODE_BYPASS_PCM 0x0000 //bypass mode for pcm data (using analog output)
#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 // bypass mode for digital bitstream data
#define SPDIF_MODE_BYPASS_PCM 0x0000 // bypass mode for pcm data (using analog output)
#define SPDIF_MODE_MEDIA_CD 0x0800 //source media is a CD
#define SPDIF_MODE_MEDIA_DVD 0x0000 //source media is a DVD
#define SPDIF_MODE_MEDIA_CD 0x0800 // source media is a CD
#define SPDIF_MODE_MEDIA_DVD 0x0000 // source media is a DVD
#define SPDIF_MEDIA_CDVD 0x0200
#define SPDIF_MEDIA_400 0x0000
#define SPDIF_MEDIA_CDVD 0x0200
#define SPDIF_MEDIA_400 0x0000
#define SPDIF_PROTECT_NORMAL 0x0000 // spdif stream is not protected
#define SPDIF_PROTECT_PROHIBIT 0x8000 // spdif stream can't be copied
#define SPDIF_PROTECT_NORMAL 0x0000 // spdif stream is not protected
#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/>.
*/
#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 "dma.h"
#ifdef __LINUX__
#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)();
#include "PS2E-spu2.h" // needed until I figure out a nice solution for irqcallback dependencies.
short *spu2regs;
short *_spu2mem;
u8 callirq;
V_CoreDebug DebugCores[2];
V_Core Cores[2];
V_SPDIF Spdif;
V_CoreDebug DebugCores[2];
V_Core Cores[2];
V_SPDIF Spdif;
s16 OutPos;
s16 InputPos;
u32 Cycles;
s16 OutPos;
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
int PlayMode;
bool has_to_call_irq=false;
@ -67,33 +48,6 @@ void SetIrqCall()
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)
{
#ifndef DEBUG_FAST
@ -111,9 +65,7 @@ __forceinline s16 __fastcall spu2M_Read( u32 addr )
// writes a signed value to the SPU2 ram
// Invalidates the ADPCM cache in the process.
// Optimization note: don't use __forceinline because the footprint of this
// function is a little too heavy now. Better to let the compiler decide.
__inline void __fastcall spu2M_Write( u32 addr, s16 value )
__forceinline void __fastcall spu2M_Write( u32 addr, s16 value )
{
// Make sure the cache is invalidated:
// (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 );
}
V_VolumeLR V_VolumeLR::Max( 0x7FFFFFFF );
V_VolumeSlideLR V_VolumeSlideLR::Max( 0x3FFF, 0x7FFFFFFF );
V_VolumeLR V_VolumeLR::Max( 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()
{
memset( this, 0, sizeof(V_Core) );
const int c = (this == Cores) ? 0 : 1;
const int c = Index;
Regs.STATX=0;
Regs.ATTR=0;
ExtVol = V_VolumeLR::Max;
InpVol = V_VolumeLR::Max;
FxVol = V_VolumeLR::Max;
Regs.STATX = 0;
Regs.ATTR = 0;
ExtVol = V_VolumeLR::Max;
InpVol = V_VolumeLR::Max;
FxVol = V_VolumeLR::Max;
MasterVol = V_VolumeSlideLR::Max;
MasterVol = V_VolumeSlideLR::Max;
DryGate.ExtL = -1;
DryGate.ExtR = -1;
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;
memset( &DryGate, -1, sizeof(DryGate) );
memset( &WetGate, -1, sizeof(WetGate) );
Regs.MMIX = 0xFFCF;
Regs.VMIXL = 0xFFFFFF;
Regs.VMIXR = 0xFFFFFF;
Regs.VMIXEL = 0xFFFFFF;
Regs.VMIXER = 0xFFFFFF;
EffectsStartA= 0xEFFF8 + 0x10000*c;
EffectsEndA = 0xEFFFF + 0x10000*c;
FxEnable=0;
IRQA=0xFFFF0;
IRQEnable=1;
Regs.MMIX = 0xFFCF;
Regs.VMIXL = 0xFFFFFF;
Regs.VMIXR = 0xFFFFFF;
Regs.VMIXEL = 0xFFFFFF;
Regs.VMIXER = 0xFFFFFF;
EffectsStartA = 0xEFFF8 + (0x10000*c);
EffectsEndA = 0xEFFFF + (0x10000*c);
FxEnable = 0;
IRQA = 0xFFFF0;
IRQEnable = 1;
for( uint v=0; v<NumVoices; ++v )
{
@ -187,19 +144,20 @@ void V_Core::Reset()
VoiceGates[v].WetL = -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.Phase = 0;
Voices[v].Pitch = 0x3FFF;
Voices[v].NextA = 2800;
Voices[v].StartA = 2800;
Voices[v].LoopStartA = 2800;
Voices[v].ADSR.Value = 0;
Voices[v].ADSR.Phase = 0;
Voices[v].Pitch = 0x3FFF;
Voices[v].NextA = 2800;
Voices[v].StartA = 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
@ -456,7 +414,7 @@ __forceinline void TimeUpdate(u32 cClocks)
lClocks+=TickInterval;
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();
Mix();
//RestoreMMXRegs();
@ -516,11 +474,12 @@ void V_VolumeSlide::RegSet( u16 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))
{
@ -530,42 +489,42 @@ void SPU_ps1_write(u32 mem, u16 value)
switch(vval)
{
case 0: //VOLL (Volume L)
Cores[0].Voices[voice].Volume.Left.Mode = 0;
Cores[0].Voices[voice].Volume.Left.RegSet( value << 1 );
Cores[0].Voices[voice].Volume.Left.Reg_VOL = value;
Voices[voice].Volume.Left.Mode = 0;
Voices[voice].Volume.Left.RegSet( value << 1 );
Voices[voice].Volume.Left.Reg_VOL = value;
break;
case 1: //VOLR (Volume R)
Cores[0].Voices[voice].Volume.Right.Mode = 0;
Cores[0].Voices[voice].Volume.Right.RegSet( value << 1 );
Cores[0].Voices[voice].Volume.Right.Reg_VOL = value;
Voices[voice].Volume.Right.Mode = 0;
Voices[voice].Volume.Right.RegSet( value << 1 );
Voices[voice].Volume.Right.Reg_VOL = value;
break;
case 2: Cores[0].Voices[voice].Pitch = value; break;
case 3: Cores[0].Voices[voice].StartA = (u32)value<<8; break;
case 2: Voices[voice].Pitch = value; break;
case 3: Voices[voice].StartA = (u32)value<<8; break;
case 4: // ADSR1 (Envelope)
Cores[0].Voices[voice].ADSR.AttackMode = (value & 0x8000)>>15;
Cores[0].Voices[voice].ADSR.AttackRate = (value & 0x7F00)>>8;
Cores[0].Voices[voice].ADSR.DecayRate = (value & 0xF0)>>4;
Cores[0].Voices[voice].ADSR.SustainLevel = (value & 0xF);
Cores[0].Voices[voice].ADSR.Reg_ADSR1 = value;
Voices[voice].ADSR.AttackMode = (value & 0x8000)>>15;
Voices[voice].ADSR.AttackRate = (value & 0x7F00)>>8;
Voices[voice].ADSR.DecayRate = (value & 0xF0)>>4;
Voices[voice].ADSR.SustainLevel = (value & 0xF);
Voices[voice].ADSR.Reg_ADSR1 = value;
break;
case 5: // ADSR2 (Envelope)
Cores[0].Voices[voice].ADSR.SustainMode = (value & 0xE000)>>13;
Cores[0].Voices[voice].ADSR.SustainRate = (value & 0x1FC0)>>6;
Cores[0].Voices[voice].ADSR.ReleaseMode = (value & 0x20)>>5;
Cores[0].Voices[voice].ADSR.ReleaseRate = (value & 0x1F);
Cores[0].Voices[voice].ADSR.Reg_ADSR2 = value;
Voices[voice].ADSR.SustainMode = (value & 0xE000)>>13;
Voices[voice].ADSR.SustainRate = (value & 0x1FC0)>>6;
Voices[voice].ADSR.ReleaseMode = (value & 0x20)>>5;
Voices[voice].ADSR.ReleaseRate = (value & 0x1F);
Voices[voice].ADSR.Reg_ADSR2 = value;
break;
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 );
break;
case 7: Cores[0].Voices[voice].LoopStartA = (u32)value <<8; break;
case 7: Voices[voice].LoopStartA = (u32)value <<8; break;
jNO_DEFAULT;
}
@ -574,21 +533,21 @@ void SPU_ps1_write(u32 mem, u16 value)
else switch(reg)
{
case 0x1d80:// Mainvolume left
Cores[0].MasterVol.Left.Mode = 0;
Cores[0].MasterVol.Left.RegSet( value );
MasterVol.Left.Mode = 0;
MasterVol.Left.RegSet( value );
break;
case 0x1d82:// Mainvolume right
Cores[0].MasterVol.Right.Mode = 0;
Cores[0].MasterVol.Right.RegSet( value );
MasterVol.Right.Mode = 0;
MasterVol.Right.RegSet( value );
break;
case 0x1d84:// Reverberation depth left
Cores[0].FxVol.Left = GetVol32( value );
FxVol.Left = GetVol32( value );
break;
case 0x1d86:// Reverberation depth right
Cores[0].FxVol.Right = GetVol32( value );
FxVol.Right = GetVol32( value );
break;
case 0x1d88:// Voice ON (0-15)
@ -652,11 +611,11 @@ void SPU_ps1_write(u32 mem, u16 value)
break;
case 0x1da4:
Cores[0].IRQA=(u32)value<<8;
IRQA = (u32)value<<8;
break;
case 0x1da6:
Cores[0].TSA=(u32)value<<8;
TSA = (u32)value<<8;
break;
case 0x1daa:
@ -668,7 +627,7 @@ void SPU_ps1_write(u32 mem, u16 value)
break;
case 0x1da8:// Spu Write to Memory
DmaWrite(0,value);
DmaWrite(value);
show=false;
break;
}
@ -678,8 +637,10 @@ void SPU_ps1_write(u32 mem, u16 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;
u16 value = spu2Ru16(mem);
@ -693,60 +654,60 @@ u16 SPU_ps1_read(u32 mem)
switch(vval)
{
case 0: //VOLL (Volume L)
//value=Cores[0].Voices[voice].VolumeL.Mode;
//value=Cores[0].Voices[voice].VolumeL.Value;
value = Cores[0].Voices[voice].Volume.Left.Reg_VOL;
//value=Voices[voice].VolumeL.Mode;
//value=Voices[voice].VolumeL.Value;
value = Voices[voice].Volume.Left.Reg_VOL;
break;
case 1: //VOLR (Volume R)
//value=Cores[0].Voices[voice].VolumeR.Mode;
//value=Cores[0].Voices[voice].VolumeR.Value;
value = Cores[0].Voices[voice].Volume.Right.Reg_VOL;
//value=Voices[voice].VolumeR.Mode;
//value=Voices[voice].VolumeR.Value;
value = Voices[voice].Volume.Right.Reg_VOL;
break;
case 2: value = Cores[0].Voices[voice].Pitch; break;
case 3: value = Cores[0].Voices[voice].StartA; break;
case 4: value = Cores[0].Voices[voice].ADSR.Reg_ADSR1; break;
case 5: value = Cores[0].Voices[voice].ADSR.Reg_ADSR2; break;
case 6: value = Cores[0].Voices[voice].ADSR.Value >> 16; break;
case 7: value = Cores[0].Voices[voice].LoopStartA; break;
case 2: value = Voices[voice].Pitch; break;
case 3: value = Voices[voice].StartA; break;
case 4: value = Voices[voice].ADSR.Reg_ADSR1; break;
case 5: value = Voices[voice].ADSR.Reg_ADSR2; break;
case 6: value = Voices[voice].ADSR.Value >> 16; break;
case 7: value = Voices[voice].LoopStartA; break;
jNO_DEFAULT;
}
}
else switch(reg)
{
case 0x1d80: value = Cores[0].MasterVol.Left.Value >> 16; break;
case 0x1d82: value = Cores[0].MasterVol.Right.Value >> 16; break;
case 0x1d84: value = Cores[0].FxVol.Left >> 16; break;
case 0x1d86: value = Cores[0].FxVol.Right >> 16; break;
case 0x1d80: value = MasterVol.Left.Value >> 16; break;
case 0x1d82: value = MasterVol.Right.Value >> 16; break;
case 0x1d84: value = FxVol.Left >> 16; break;
case 0x1d86: value = FxVol.Right >> 16; break;
case 0x1d88: value = 0; break;
case 0x1d8a: value = 0; break;
case 0x1d8c: value = 0; break;
case 0x1d8e: value = 0; break;
case 0x1d90: value = Cores[0].Regs.PMON&0xFFFF; break;
case 0x1d92: value = Cores[0].Regs.PMON>>16; break;
case 0x1d90: value = Regs.PMON&0xFFFF; break;
case 0x1d92: value = Regs.PMON>>16; break;
case 0x1d94: value = Cores[0].Regs.NON&0xFFFF; break;
case 0x1d96: value = Cores[0].Regs.NON>>16; break;
case 0x1d94: value = Regs.NON&0xFFFF; break;
case 0x1d96: value = Regs.NON>>16; break;
case 0x1d98: value = Cores[0].Regs.VMIXEL&0xFFFF; break;
case 0x1d9a: value = Cores[0].Regs.VMIXEL>>16; break;
case 0x1d9c: value = Cores[0].Regs.VMIXL&0xFFFF; break;
case 0x1d9e: value = Cores[0].Regs.VMIXL>>16; break;
case 0x1d98: value = Regs.VMIXEL&0xFFFF; break;
case 0x1d9a: value = Regs.VMIXEL>>16; break;
case 0x1d9c: value = Regs.VMIXL&0xFFFF; break;
case 0x1d9e: value = Regs.VMIXL>>16; break;
case 0x1da2:
if( value != Cores[0].EffectsStartA>>3 )
if( value != EffectsStartA>>3 )
{
value = Cores[0].EffectsStartA>>3;
Cores[0].UpdateEffectsBufferSize();
Cores[0].ReverbX = 0;
value = EffectsStartA>>3;
UpdateEffectsBufferSize();
ReverbX = 0;
}
break;
case 0x1da4: value = Cores[0].IRQA>>3; break;
case 0x1da6: value = Cores[0].TSA>>3; break;
case 0x1da4: value = IRQA>>3; break;
case 0x1da6: value = TSA>>3; break;
case 0x1daa:
value = SPU2read(REG_C_ATTR);
@ -755,7 +716,7 @@ u16 SPU_ps1_read(u32 mem)
value = 0; //SPU2read(REG_P_STATX)<<3;
break;
case 0x1da8:
value = DmaRead(0);
value = DmaRead();
show=false;
break;
}
@ -930,6 +891,30 @@ void SPU2_FastWrite( u32 rmem, u16 value )
V_Core& thiscore = Cores[core];
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:
{
int irqe = thiscore.IRQEnable;