mirror of https://github.com/PCSX2/pcsx2.git
SPU2-X:
* 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:
parent
15d2824d1b
commit
158b01b58d
|
@ -15,7 +15,7 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Spu2.h"
|
#include "Global.h"
|
||||||
|
|
||||||
static const s32 ADSR_MAX_VOL = 0x7fffffff;
|
static const s32 ADSR_MAX_VOL = 0x7fffffff;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ void InitADSR() // INIT ADSR
|
||||||
else
|
else
|
||||||
rate <<= shift;
|
rate <<= shift;
|
||||||
|
|
||||||
PsxRates[i] = (int)min( rate, 0x3fffffffLL );
|
PsxRates[i] = (int)std::min( rate, 0x3fffffffLL );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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();
|
|
@ -38,13 +38,9 @@
|
||||||
|
|
||||||
------------------------------------------------------------------------ */
|
------------------------------------------------------------------------ */
|
||||||
|
|
||||||
#include "PS2Etypes.h"
|
#include "Global.h"
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
#include "ConvertUTF.h"
|
#include "ConvertUTF.h"
|
||||||
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::wstring;
|
using std::wstring;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Spu2.h"
|
#include "Global.h"
|
||||||
|
|
||||||
int crazy_debug=0;
|
int crazy_debug=0;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
//License along with this library; if not, write to the Free Software
|
//License along with this library; if not, write to the Free Software
|
||||||
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
//
|
//
|
||||||
#include "Spu2.h"
|
|
||||||
|
#include "Global.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "liba52/inttypes.h"
|
#include "liba52/inttypes.h"
|
||||||
|
@ -129,12 +130,13 @@ s32 stoi(sample_t n) //input: [-1..1]
|
||||||
|
|
||||||
void spdif_update()
|
void spdif_update()
|
||||||
{
|
{
|
||||||
StereoOut32 Data;
|
|
||||||
|
|
||||||
for(int i=0;i<data_rate;i++)
|
for(int i=0;i<data_rate;i++)
|
||||||
{
|
{
|
||||||
// Right side data should be zero / ignored
|
// Source is Core 0
|
||||||
ReadInput( 0, Data ); // read from core 0
|
// .. and Right side data should be zero / ignored
|
||||||
|
StereoOut32 Data( Cores[0].ReadInput() );
|
||||||
|
|
||||||
if(fSpdifDump)
|
if(fSpdifDump)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,23 +15,20 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Spu2.h"
|
#include "Global.h"
|
||||||
|
#include "dma.h"
|
||||||
|
|
||||||
|
#include "PS2E-spu2.h" // temporary until I resolve cyclePtr/TimeUpdate dependencies.
|
||||||
|
|
||||||
extern u8 callirq;
|
extern u8 callirq;
|
||||||
|
|
||||||
FILE *DMA4LogFile=0;
|
static FILE *DMA4LogFile = NULL;
|
||||||
FILE *DMA7LogFile=0;
|
static FILE *DMA7LogFile = NULL;
|
||||||
FILE *ADMA4LogFile=0;
|
static FILE *ADMA4LogFile = NULL;
|
||||||
FILE *ADMA7LogFile=0;
|
static FILE *ADMA7LogFile = NULL;
|
||||||
FILE *ADMAOutLogFile=0;
|
static FILE *ADMAOutLogFile = NULL;
|
||||||
|
|
||||||
FILE *REGWRTLogFile[2]={0,0};
|
static FILE *REGWRTLogFile[2] = {0,0};
|
||||||
|
|
||||||
int packcount=0;
|
|
||||||
|
|
||||||
u16* MBASE[2] = {0,0};
|
|
||||||
|
|
||||||
u16* DMABaseAddr;
|
|
||||||
|
|
||||||
void DMALogOpen()
|
void DMALogOpen()
|
||||||
{
|
{
|
||||||
|
@ -56,16 +53,6 @@ void DMA7LogWrite(void *lpData, u32 ulSize) {
|
||||||
fwrite(lpData,ulSize,1,DMA7LogFile);
|
fwrite(lpData,ulSize,1,DMA7LogFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ADMA4LogWrite(void *lpData, u32 ulSize) {
|
|
||||||
if(!DMALog()) return;
|
|
||||||
if (!ADMA4LogFile) return;
|
|
||||||
fwrite(lpData,ulSize,1,ADMA4LogFile);
|
|
||||||
}
|
|
||||||
void ADMA7LogWrite(void *lpData, u32 ulSize) {
|
|
||||||
if(!DMALog()) return;
|
|
||||||
if (!ADMA7LogFile) return;
|
|
||||||
fwrite(lpData,ulSize,1,ADMA7LogFile);
|
|
||||||
}
|
|
||||||
void ADMAOutLogWrite(void *lpData, u32 ulSize) {
|
void ADMAOutLogWrite(void *lpData, u32 ulSize) {
|
||||||
if(!DMALog()) return;
|
if(!DMALog()) return;
|
||||||
if (!ADMAOutLogFile) return;
|
if (!ADMAOutLogFile) return;
|
||||||
|
@ -79,118 +66,110 @@ void RegWriteLog(u32 core,u16 value)
|
||||||
fwrite(&value,2,1,REGWRTLogFile[core]);
|
fwrite(&value,2,1,REGWRTLogFile[core]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMALogClose() {
|
void DMALogClose()
|
||||||
if(!DMALog()) return;
|
{
|
||||||
if (DMA4LogFile) fclose(DMA4LogFile);
|
safe_fclose(DMA4LogFile);
|
||||||
if (DMA7LogFile) fclose(DMA7LogFile);
|
safe_fclose(DMA7LogFile);
|
||||||
if (REGWRTLogFile[0]) fclose(REGWRTLogFile[0]);
|
safe_fclose(REGWRTLogFile[0]);
|
||||||
if (REGWRTLogFile[1]) fclose(REGWRTLogFile[1]);
|
safe_fclose(REGWRTLogFile[1]);
|
||||||
if (ADMA4LogFile) fclose(ADMA4LogFile);
|
safe_fclose(ADMA4LogFile);
|
||||||
if (ADMA7LogFile) fclose(ADMA7LogFile);
|
safe_fclose(ADMA7LogFile);
|
||||||
if (ADMAOutLogFile) fclose(ADMAOutLogFile);
|
safe_fclose(ADMAOutLogFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void V_Core::LogAutoDMA( FILE* fp )
|
||||||
__forceinline u16 DmaRead(u32 core)
|
|
||||||
{
|
{
|
||||||
const u16 ret = (u16)spu2M_Read(Cores[core].TDA);
|
if( !DMALog() || !fp ) return;
|
||||||
Cores[core].TDA++;
|
fwrite( DMAPtr+InputDataProgress, 0x400, 1, fp );
|
||||||
Cores[core].TDA&=0xfffff;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline void DmaWrite(u32 core, u16 value)
|
void V_Core::AutoDMAReadBuffer(int mode) //mode: 0= split stereo; 1 = do not split stereo
|
||||||
{
|
{
|
||||||
spu2M_Write( Cores[core].TSA, value );
|
int spos = ((InputPos+0xff)&0x100); //starting position of the free buffer
|
||||||
Cores[core].TSA++;
|
|
||||||
Cores[core].TSA&=0xfffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoDMAReadBuffer(int core, int mode) //mode: 0= split stereo; 1 = do not split stereo
|
LogAutoDMA( Index ? ADMA7LogFile : ADMA4LogFile );
|
||||||
{
|
|
||||||
int spos=((Cores[core].InputPos+0xff)&0x100); //starting position of the free buffer
|
|
||||||
|
|
||||||
if(core==0)
|
// HACKFIX!! DMAPtr can be invalid after a savestate load, so the savestate just forces it
|
||||||
ADMA4LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400);
|
// to NULL and we ignore it here. (used to work in old VM editions of PCSX2 with fixed
|
||||||
else
|
// addressing, but new PCSX2s have dynamic memory addressing).
|
||||||
ADMA7LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400);
|
|
||||||
|
|
||||||
if(mode)
|
if(mode)
|
||||||
{
|
{
|
||||||
//hacky :p
|
if( DMAPtr != NULL )
|
||||||
|
memcpy((ADMATempBuffer+(spos<<1)),DMAPtr+InputDataProgress,0x400);
|
||||||
memcpy((Cores[core].ADMATempBuffer+(spos<<1)),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400);
|
MADR+=0x400;
|
||||||
Cores[core].MADR+=0x400;
|
InputDataLeft-=0x200;
|
||||||
Cores[core].InputDataLeft-=0x200;
|
InputDataProgress+=0x200;
|
||||||
Cores[core].InputDataProgress+=0x200;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy((Cores[core].ADMATempBuffer+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200);
|
if( DMAPtr != NULL )
|
||||||
//memcpy((spu2mem+0x2000+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200);
|
memcpy((ADMATempBuffer+spos),DMAPtr+InputDataProgress,0x200);
|
||||||
Cores[core].MADR+=0x200;
|
//memcpy((spu2mem+0x2000+(core<<10)+spos),DMAPtr+InputDataProgress,0x200);
|
||||||
Cores[core].InputDataLeft-=0x100;
|
MADR+=0x200;
|
||||||
Cores[core].InputDataProgress+=0x100;
|
InputDataLeft-=0x100;
|
||||||
|
InputDataProgress+=0x100;
|
||||||
|
|
||||||
memcpy((Cores[core].ADMATempBuffer+spos+0x200),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200);
|
if( DMAPtr != NULL )
|
||||||
//memcpy((spu2mem+0x2200+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200);
|
memcpy((ADMATempBuffer+spos+0x200),DMAPtr+InputDataProgress,0x200);
|
||||||
Cores[core].MADR+=0x200;
|
//memcpy((spu2mem+0x2200+(core<<10)+spos),DMAPtr+InputDataProgress,0x200);
|
||||||
Cores[core].InputDataLeft-=0x100;
|
MADR+=0x200;
|
||||||
Cores[core].InputDataProgress+=0x100;
|
InputDataLeft-=0x100;
|
||||||
|
InputDataProgress+=0x100;
|
||||||
}
|
}
|
||||||
// See ReadInput at mixer.cpp for explanation on the commented out lines
|
// See ReadInput at mixer.cpp for explanation on the commented out lines
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartADMAWrite(int core,u16 *pMem, u32 sz)
|
void V_Core::StartADMAWrite(u16 *pMem, u32 sz)
|
||||||
{
|
{
|
||||||
int size=(sz)&(~511);
|
int size = (sz)&(~511);
|
||||||
|
|
||||||
if(MsgAutoDMA()) ConLog(" * SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n",
|
if(MsgAutoDMA()) ConLog(" * SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n",
|
||||||
(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff);
|
GetDmaIndexChar(), size<<1, TSA, DMABits, AutoDMACtrl, (~Regs.ATTR)&0x7fff);
|
||||||
|
|
||||||
Cores[core].InputDataProgress=0;
|
InputDataProgress=0;
|
||||||
if((Cores[core].AutoDMACtrl&(core+1))==0)
|
if((AutoDMACtrl&(Index+1))==0)
|
||||||
{
|
{
|
||||||
Cores[core].TSA=0x2000+(core<<10);
|
TSA=0x2000+(Index<<10);
|
||||||
Cores[core].DMAICounter=size;
|
DMAICounter=size;
|
||||||
}
|
}
|
||||||
else if(size>=512)
|
else if(size>=512)
|
||||||
{
|
{
|
||||||
Cores[core].InputDataLeft=size;
|
InputDataLeft=size;
|
||||||
if(Cores[core].AdmaInProgress==0)
|
if(AdmaInProgress==0)
|
||||||
{
|
{
|
||||||
#ifdef PCM24_S1_INTERLEAVE
|
#ifdef PCM24_S1_INTERLEAVE
|
||||||
if((core==1)&&((PlayMode&8)==8))
|
if((Index==1)&&((PlayMode&8)==8))
|
||||||
{
|
{
|
||||||
AutoDMAReadBuffer(core,1);
|
AutoDMAReadBuffer(Index,1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AutoDMAReadBuffer(core,0);
|
AutoDMAReadBuffer(Index,0);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if(((PlayMode&4)==4)&&(core==0))
|
if(((PlayMode&4)==4)&&(Index==0))
|
||||||
Cores[0].InputPos=0;
|
Cores[0].InputPos=0;
|
||||||
|
|
||||||
AutoDMAReadBuffer(core,0);
|
AutoDMAReadBuffer(0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(size==512)
|
if(size==512)
|
||||||
Cores[core].DMAICounter=size;
|
DMAICounter=size;
|
||||||
}
|
}
|
||||||
|
|
||||||
Cores[core].AdmaInProgress=1;
|
AdmaInProgress=1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Cores[core].InputDataLeft=0;
|
InputDataLeft=0;
|
||||||
Cores[core].DMAICounter=1;
|
DMAICounter=1;
|
||||||
}
|
}
|
||||||
Cores[core].TADR=Cores[core].MADR+(size<<1);
|
TADR=MADR+(size<<1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoDMAWrite(int core,u16 *pMem,u32 size)
|
void V_Core::PlainDMAWrite(u16 *pMem, u32 size)
|
||||||
{
|
{
|
||||||
// Perform an alignment check.
|
// Perform an alignment check.
|
||||||
// Not really important. Everything should work regardless,
|
// Not really important. Everything should work regardless,
|
||||||
|
@ -198,29 +177,29 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
uptr pa = ((uptr)pMem)&7;
|
uptr pa = ((uptr)pMem)&7;
|
||||||
uptr pm = Cores[core].TSA&0x7;
|
uptr pm = TSA&0x7;
|
||||||
|
|
||||||
if( pa )
|
if( pa )
|
||||||
{
|
{
|
||||||
fprintf(stderr, "* SPU2 DMA Write > Missaligned SOURCE! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size);
|
fprintf(stderr, "* SPU2 DMA Write > Missaligned SOURCE! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, TSA, TDA, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pm )
|
if( pm )
|
||||||
{
|
{
|
||||||
fprintf(stderr, "* SPU2 DMA Write > Missaligned TARGET! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size );
|
fprintf(stderr, "* SPU2 DMA Write > Missaligned TARGET! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, TSA, TDA, size );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(core==0)
|
if(Index==0)
|
||||||
DMA4LogWrite(pMem,size<<1);
|
DMA4LogWrite(pMem,size<<1);
|
||||||
else
|
else
|
||||||
DMA7LogWrite(pMem,size<<1);
|
DMA7LogWrite(pMem,size<<1);
|
||||||
|
|
||||||
if(MsgDMA()) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff);
|
if(MsgDMA()) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",GetDmaIndexChar(),size<<1,TSA,DMABits,AutoDMACtrl,(~Regs.ATTR)&0x7fff);
|
||||||
|
|
||||||
Cores[core].TSA &= 0xfffff;
|
TSA &= 0xfffff;
|
||||||
|
|
||||||
u32 buff1end = Cores[core].TSA + size;
|
u32 buff1end = TSA + size;
|
||||||
u32 buff2end=0;
|
u32 buff2end=0;
|
||||||
if( buff1end > 0x100000 )
|
if( buff1end > 0x100000 )
|
||||||
{
|
{
|
||||||
|
@ -228,7 +207,7 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
|
||||||
buff1end = 0x100000;
|
buff1end = 0x100000;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int cacheIdxStart = Cores[core].TSA / pcm_WordsPerBlock;
|
const int cacheIdxStart = TSA / pcm_WordsPerBlock;
|
||||||
const int cacheIdxEnd = (buff1end+pcm_WordsPerBlock-1) / pcm_WordsPerBlock;
|
const int cacheIdxEnd = (buff1end+pcm_WordsPerBlock-1) / pcm_WordsPerBlock;
|
||||||
PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart];
|
PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart];
|
||||||
PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd];
|
PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd];
|
||||||
|
@ -240,14 +219,14 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
|
||||||
} while ( cacheLine != &cacheEnd );
|
} while ( cacheLine != &cacheEnd );
|
||||||
|
|
||||||
//ConLog( " * SPU2 : Cache Clear Range! TSA=0x%x, TDA=0x%x (low8=0x%x, high8=0x%x, len=0x%x)\n",
|
//ConLog( " * SPU2 : Cache Clear Range! TSA=0x%x, TDA=0x%x (low8=0x%x, high8=0x%x, len=0x%x)\n",
|
||||||
// Cores[core].TSA, buff1end, flagTSA, flagTDA, clearLen );
|
// TSA, buff1end, flagTSA, flagTDA, clearLen );
|
||||||
|
|
||||||
|
|
||||||
// First Branch needs cleared:
|
// First Branch needs cleared:
|
||||||
// It starts at TSA and goes to buff1end.
|
// It starts at TSA and goes to buff1end.
|
||||||
|
|
||||||
const u32 buff1size = (buff1end-Cores[core].TSA);
|
const u32 buff1size = (buff1end-TSA);
|
||||||
memcpy( GetMemPtr( Cores[core].TSA ), pMem, buff1size*2 );
|
memcpy( GetMemPtr( TSA ), pMem, buff1size*2 );
|
||||||
|
|
||||||
if( buff2end > 0 )
|
if( buff2end > 0 )
|
||||||
{
|
{
|
||||||
|
@ -263,57 +242,50 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
|
||||||
// 0x2800? Hard to know for usre (almost no games depend on this)
|
// 0x2800? Hard to know for usre (almost no games depend on this)
|
||||||
|
|
||||||
memcpy( GetMemPtr( 0 ), &pMem[buff1size], buff2end*2 );
|
memcpy( GetMemPtr( 0 ), &pMem[buff1size], buff2end*2 );
|
||||||
Cores[core].TDA = (buff2end+1) & 0xfffff;
|
TDA = (buff2end+1) & 0xfffff;
|
||||||
|
|
||||||
if(Cores[core].IRQEnable)
|
|
||||||
{
|
|
||||||
// Flag interrupt?
|
|
||||||
// If IRQA occurs between start and dest, flag it.
|
|
||||||
// Since the buffer wraps, the conditional might seem odd, but it works.
|
|
||||||
|
|
||||||
if( ( Cores[core].IRQA >= Cores[core].TSA ) ||
|
|
||||||
( Cores[core].IRQA < Cores[core].TDA ) )
|
|
||||||
{
|
|
||||||
Spdif.Info = 4 << core;
|
|
||||||
SetIrqCall();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Buffer doesn't wrap/overflow!
|
// Buffer doesn't wrap/overflow!
|
||||||
// Just set the TDA and check for an IRQ...
|
// Just set the TDA and check for an IRQ...
|
||||||
|
|
||||||
Cores[core].TDA = buff1end;
|
TDA = buff1end;
|
||||||
|
}
|
||||||
|
|
||||||
if(Cores[core].IRQEnable)
|
// Flag interrupt? If IRQA occurs between start and dest, flag it.
|
||||||
|
// Important: Test both core IRQ settings for either DMA!
|
||||||
|
|
||||||
|
for( int i=0; i<2; i++ )
|
||||||
|
{
|
||||||
|
// Note: (start is inclusive, dest exclusive -- fixes DMC1 FMVs)
|
||||||
|
|
||||||
|
if( Cores[i].IRQEnable && (Cores[i].IRQA >= Cores[i].TSA) && (Cores[i].IRQA < Cores[i].TDA) )
|
||||||
{
|
{
|
||||||
// Flag interrupt?
|
Spdif.Info = 4 << i;
|
||||||
// If IRQA occurs between start and dest, flag it.
|
SetIrqCall();
|
||||||
// (start is inclusive, dest exclusive -- fixes DMC1 and hopefully won't break
|
|
||||||
// other games. ;)
|
|
||||||
|
|
||||||
if( ( Cores[core].IRQA >= Cores[core].TSA ) &&
|
|
||||||
( Cores[core].IRQA < Cores[core].TDA ) )
|
|
||||||
{
|
|
||||||
Spdif.Info = 4 << core;
|
|
||||||
SetIrqCall();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Cores[core].TSA=Cores[core].TDA&0xFFFF0;
|
if(IRQEnable)
|
||||||
Cores[core].DMAICounter=size;
|
{
|
||||||
Cores[core].TADR=Cores[core].MADR+(size<<1);
|
|
||||||
|
if( ( IRQA >= TSA ) && ( IRQA < TDA ) )
|
||||||
|
{
|
||||||
|
Spdif.Info = 4 << Index;
|
||||||
|
SetIrqCall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TSA = TDA & 0xFFFF0;
|
||||||
|
DMAICounter = size;
|
||||||
|
TADR = MADR + (size<<1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPU2readDMA(int core, u16* pMem, u32 size)
|
void V_Core::DoDMAread(u16* pMem, u32 size)
|
||||||
{
|
{
|
||||||
if( cyclePtr != NULL ) TimeUpdate( *cyclePtr );
|
TSA &= 0xffff8;
|
||||||
|
|
||||||
Cores[core].TSA &= 0xffff8;
|
u32 buff1end = TSA + size;
|
||||||
|
|
||||||
u32 buff1end = Cores[core].TSA + size;
|
|
||||||
u32 buff2end = 0;
|
u32 buff2end = 0;
|
||||||
if( buff1end > 0x100000 )
|
if( buff1end > 0x100000 )
|
||||||
{
|
{
|
||||||
|
@ -321,8 +293,8 @@ void SPU2readDMA(int core, u16* pMem, u32 size)
|
||||||
buff1end = 0x100000;
|
buff1end = 0x100000;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 buff1size = (buff1end-Cores[core].TSA);
|
const u32 buff1size = (buff1end-TSA);
|
||||||
memcpy( pMem, GetMemPtr( Cores[core].TSA ), buff1size*2 );
|
memcpy( pMem, GetMemPtr( TSA ), buff1size*2 );
|
||||||
|
|
||||||
// Note on TSA's position after our copy finishes:
|
// Note on TSA's position after our copy finishes:
|
||||||
// IRQA should be measured by the end of the writepos+0x20. But the TDA
|
// IRQA should be measured by the end of the writepos+0x20. But the TDA
|
||||||
|
@ -335,146 +307,65 @@ void SPU2readDMA(int core, u16* pMem, u32 size)
|
||||||
|
|
||||||
memcpy( &pMem[buff1size], GetMemPtr( 0 ), buff2end*2 );
|
memcpy( &pMem[buff1size], GetMemPtr( 0 ), buff2end*2 );
|
||||||
|
|
||||||
Cores[core].TDA = (buff2end+0x20) & 0xfffff;
|
TDA = (buff2end+0x20) & 0xfffff;
|
||||||
|
|
||||||
for( int i=0; i<2; i++ )
|
|
||||||
{
|
|
||||||
if(Cores[i].IRQEnable)
|
|
||||||
{
|
|
||||||
// Flag interrupt?
|
|
||||||
// If IRQA occurs between start and dest, flag it.
|
|
||||||
// Since the buffer wraps, the conditional might seem odd, but it works.
|
|
||||||
|
|
||||||
if( ( Cores[i].IRQA >= Cores[core].TSA ) ||
|
|
||||||
( Cores[i].IRQA <= Cores[core].TDA ) )
|
|
||||||
{
|
|
||||||
Spdif.Info=4<<i;
|
|
||||||
SetIrqCall();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Buffer doesn't wrap/overflow!
|
// Buffer doesn't wrap/overflow!
|
||||||
// Just set the TDA and check for an IRQ...
|
// Just set the TDA and check for an IRQ...
|
||||||
|
|
||||||
Cores[core].TDA = (buff1end + 0x20) & 0xfffff;
|
TDA = (buff1end + 0x20) & 0xfffff;
|
||||||
|
}
|
||||||
|
|
||||||
for( int i=0; i<2; i++ )
|
// Flag interrupt? If IRQA occurs between start and dest, flag it.
|
||||||
|
// Important: Test both core IRQ settings for either DMA!
|
||||||
|
|
||||||
|
for( int i=0; i<2; i++ )
|
||||||
|
{
|
||||||
|
if( Cores[i].IRQEnable && (Cores[i].IRQA >= Cores[i].TSA) && (Cores[i].IRQA < Cores[i].TDA) )
|
||||||
{
|
{
|
||||||
if(Cores[i].IRQEnable)
|
Spdif.Info = 4 << i;
|
||||||
{
|
SetIrqCall();
|
||||||
// Flag interrupt?
|
|
||||||
// If IRQA occurs between start and dest, flag it:
|
|
||||||
|
|
||||||
if( ( Cores[i].IRQA >= Cores[i].TSA ) &&
|
|
||||||
( Cores[i].IRQA < Cores[i].TDA ) )
|
|
||||||
{
|
|
||||||
Spdif.Info=4<<i;
|
|
||||||
SetIrqCall();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TSA = TDA & 0xFFFFF;
|
||||||
|
|
||||||
Cores[core].TSA=Cores[core].TDA & 0xFFFFF;
|
DMAICounter = size;
|
||||||
|
Regs.STATX &= ~0x80;
|
||||||
Cores[core].DMAICounter=size;
|
//Regs.ATTR |= 0x30;
|
||||||
Cores[core].Regs.STATX &= ~0x80;
|
TADR = MADR + (size<<1);
|
||||||
//Cores[core].Regs.ATTR |= 0x30;
|
|
||||||
Cores[core].TADR=Cores[core].MADR+(size<<1);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPU2writeDMA(int core, u16* pMem, u32 size)
|
void V_Core::DoDMAwrite(u16* pMem, u32 size)
|
||||||
{
|
{
|
||||||
if(cyclePtr != NULL) TimeUpdate(*cyclePtr);
|
DMAPtr = pMem;
|
||||||
|
|
||||||
Cores[core].DMAPtr=pMem;
|
|
||||||
|
|
||||||
if(size<2) {
|
if(size<2) {
|
||||||
//if(dma7callback) dma7callback();
|
//if(dma7callback) dma7callback();
|
||||||
Cores[core].Regs.STATX &= ~0x80;
|
Regs.STATX &= ~0x80;
|
||||||
//Cores[core].Regs.ATTR |= 0x30;
|
//Regs.ATTR |= 0x30;
|
||||||
Cores[core].DMAICounter=1;
|
DMAICounter=1;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( IsDevBuild )
|
if( IsDevBuild )
|
||||||
DebugCores[core].lastsize = size;
|
DebugCores[Index].lastsize = size;
|
||||||
|
|
||||||
Cores[core].TSA&=~7;
|
TSA &= ~7;
|
||||||
|
|
||||||
bool adma_enable = ((Cores[core].AutoDMACtrl&(core+1))==(core+1));
|
bool adma_enable = ((AutoDMACtrl&(Index+1))==(Index+1));
|
||||||
|
|
||||||
if(adma_enable)
|
if(adma_enable)
|
||||||
{
|
{
|
||||||
Cores[core].TSA&=0x1fff;
|
TSA&=0x1fff;
|
||||||
StartADMAWrite(core,pMem,size);
|
StartADMAWrite(pMem,size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DoDMAWrite(core,pMem,size);
|
PlainDMAWrite(pMem,size);
|
||||||
}
|
}
|
||||||
Cores[core].Regs.STATX &= ~0x80;
|
Regs.STATX &= ~0x80;
|
||||||
//Cores[core].Regs.ATTR |= 0x30;
|
//Regs.ATTR |= 0x30;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CALLBACK SPU2ReadMemAddr(int core)
|
|
||||||
{
|
|
||||||
return Cores[core].MADR;
|
|
||||||
}
|
|
||||||
void CALLBACK SPU2WriteMemAddr(int core,u32 value)
|
|
||||||
{
|
|
||||||
Cores[core].MADR=value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CALLBACK SPU2setDMABaseAddr(uptr baseaddr)
|
|
||||||
{
|
|
||||||
DMABaseAddr = (u16*)baseaddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CALLBACK SPU2readDMA4Mem(u16 *pMem, u32 size) { //size now in 16bit units
|
|
||||||
FileLog("[%10d] SPU2 readDMA4Mem size %x\n",Cycles, size<<1);
|
|
||||||
SPU2readDMA(0,pMem,size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CALLBACK SPU2writeDMA4Mem(u16* pMem, u32 size) { //size now in 16bit units
|
|
||||||
FileLog("[%10d] SPU2 writeDMA4Mem size %x at address %x\n",Cycles, size<<1, Cores[0].TSA);
|
|
||||||
#ifdef S2R_ENABLE
|
|
||||||
if(!replay_mode)
|
|
||||||
s2r_writedma4(Cycles,pMem,size);
|
|
||||||
#endif
|
|
||||||
SPU2writeDMA(0,pMem,size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CALLBACK SPU2interruptDMA4() {
|
|
||||||
FileLog("[%10d] SPU2 interruptDMA4\n",Cycles);
|
|
||||||
Cores[0].Regs.STATX |= 0x80;
|
|
||||||
//Cores[0].Regs.ATTR &= ~0x30;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CALLBACK SPU2readDMA7Mem(u16* pMem, u32 size) {
|
|
||||||
FileLog("[%10d] SPU2 readDMA7Mem size %x\n",Cycles, size<<1);
|
|
||||||
|
|
||||||
SPU2readDMA(1,pMem,size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CALLBACK SPU2writeDMA7Mem(u16* pMem, u32 size) {
|
|
||||||
FileLog("[%10d] SPU2 writeDMA7Mem size %x at address %x\n",Cycles, size<<1, Cores[1].TSA);
|
|
||||||
#ifdef S2R_ENABLE
|
|
||||||
if(!replay_mode)
|
|
||||||
s2r_writedma7(Cycles,pMem,size);
|
|
||||||
#endif
|
|
||||||
SPU2writeDMA(1,pMem,size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CALLBACK SPU2interruptDMA7() {
|
|
||||||
FileLog("[%10d] SPU2 interruptDMA7\n",Cycles);
|
|
||||||
Cores[1].Regs.STATX |= 0x80;
|
|
||||||
//Cores[1].Regs.ATTR &= ~0x30;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,23 @@
|
||||||
//GiGaHeRz's SPU2 Driver
|
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
|
||||||
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
|
* Developed and maintained by the Pcsx2 Development Team.
|
||||||
//
|
*
|
||||||
//This library is free software; you can redistribute it and/or
|
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
|
||||||
//modify it under the terms of the GNU Lesser General Public
|
*
|
||||||
//License as published by the Free Software Foundation; either
|
* SPU2-X is free software: you can redistribute it and/or modify it under the terms
|
||||||
//version 2.1 of the License, or (at your option) any later version.
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
//
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
//This library is distributed in the hope that it will be useful,
|
*
|
||||||
//but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* SPU2-X is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
//Lesser General Public License for more details.
|
* PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
//
|
*
|
||||||
//You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
//License along with this library; if not, write to the Free Software
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
*/
|
||||||
//
|
|
||||||
#ifndef DMA_H_INCLUDED
|
|
||||||
#define DMA_H_INCLUDED
|
|
||||||
|
|
||||||
void DMALogOpen();
|
#pragma once
|
||||||
void DMA4LogWrite(void *lpData, u32 ulSize);
|
|
||||||
void DMA7LogWrite(void *lpData, u32 ulSize);
|
|
||||||
void DMALogClose();
|
|
||||||
|
|
||||||
extern void DmaWrite(u32 core, u16 data);
|
extern void DMALogOpen();
|
||||||
extern u16 DmaRead(u32 core);
|
extern void DMA4LogWrite(void *lpData, u32 ulSize);
|
||||||
|
extern void DMA7LogWrite(void *lpData, u32 ulSize);
|
||||||
extern void AutoDMAReadBuffer(int core, int mode);
|
extern void DMALogClose();
|
||||||
|
|
||||||
#endif // DMA_H_INCLUDED //
|
|
||||||
|
|
|
@ -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
|
|
@ -1,8 +1,8 @@
|
||||||
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
|
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
|
||||||
* Developed and maintained by the Pcsx2 Development Team.
|
* Developed and maintained by the Pcsx2 Development Team.
|
||||||
*
|
*
|
||||||
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
|
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
|
||||||
*
|
*
|
||||||
* SPU2-X is free software: you can redistribute it and/or modify it under the terms
|
* SPU2-X is free software: you can redistribute it and/or modify it under the terms
|
||||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
@ -14,95 +14,95 @@
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Spu2.h"
|
#include "Spu2.h"
|
||||||
#include "Dialogs.h"
|
#include "Dialogs.h"
|
||||||
|
|
||||||
bool DebugEnabled=false;
|
bool DebugEnabled=false;
|
||||||
bool _MsgToConsole=false;
|
bool _MsgToConsole=false;
|
||||||
bool _MsgKeyOnOff=false;
|
bool _MsgKeyOnOff=false;
|
||||||
bool _MsgVoiceOff=false;
|
bool _MsgVoiceOff=false;
|
||||||
bool _MsgDMA=false;
|
bool _MsgDMA=false;
|
||||||
bool _MsgAutoDMA=false;
|
bool _MsgAutoDMA=false;
|
||||||
bool _MsgOverruns=false;
|
bool _MsgOverruns=false;
|
||||||
bool _MsgCache=false;
|
bool _MsgCache=false;
|
||||||
|
|
||||||
bool _AccessLog=false;
|
bool _AccessLog=false;
|
||||||
bool _DMALog=false;
|
bool _DMALog=false;
|
||||||
bool _WaveLog=false;
|
bool _WaveLog=false;
|
||||||
|
|
||||||
bool _CoresDump=false;
|
bool _CoresDump=false;
|
||||||
bool _MemDump=false;
|
bool _MemDump=false;
|
||||||
bool _RegDump=false;
|
bool _RegDump=false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
wchar_t AccessLogFileName[255];
|
wchar_t AccessLogFileName[255];
|
||||||
wchar_t WaveLogFileName[255];
|
wchar_t WaveLogFileName[255];
|
||||||
|
|
||||||
wchar_t DMA4LogFileName[255];
|
wchar_t DMA4LogFileName[255];
|
||||||
wchar_t DMA7LogFileName[255];
|
wchar_t DMA7LogFileName[255];
|
||||||
|
|
||||||
wchar_t CoresDumpFileName[255];
|
wchar_t CoresDumpFileName[255];
|
||||||
wchar_t MemDumpFileName[255];
|
wchar_t MemDumpFileName[255];
|
||||||
wchar_t RegDumpFileName[255];
|
wchar_t RegDumpFileName[255];
|
||||||
|
|
||||||
|
|
||||||
#ifdef SPU2X_DEVBUILD
|
#ifdef PCSX2_DEVBUILD
|
||||||
static const int LATENCY_MAX = 3000;
|
static const int LATENCY_MAX = 3000;
|
||||||
#else
|
#else
|
||||||
static const int LATENCY_MAX = 750;
|
static const int LATENCY_MAX = 750;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const int LATENCY_MIN = 40;
|
static const int LATENCY_MIN = 40;
|
||||||
|
|
||||||
int AutoDMAPlayRate[2] = {0,0};
|
int AutoDMAPlayRate[2] = {0,0};
|
||||||
|
|
||||||
// MIXING
|
// MIXING
|
||||||
int Interpolation = 1;
|
int Interpolation = 1;
|
||||||
/* values:
|
/* values:
|
||||||
0: no interpolation (use nearest)
|
0: no interpolation (use nearest)
|
||||||
1. linear interpolation
|
1. linear interpolation
|
||||||
2. cubic interpolation
|
2. cubic interpolation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool EffectsDisabled = false;
|
bool EffectsDisabled = false;
|
||||||
|
|
||||||
// OUTPUT
|
// OUTPUT
|
||||||
int SndOutLatencyMS = 160;
|
int SndOutLatencyMS = 160;
|
||||||
bool timeStretchDisabled = false;
|
bool timeStretchDisabled = false;
|
||||||
|
|
||||||
u32 OutputModule = 0;
|
u32 OutputModule = 0;
|
||||||
|
|
||||||
CONFIG_DSOUNDOUT Config_DSoundOut;
|
CONFIG_DSOUNDOUT Config_DSoundOut;
|
||||||
CONFIG_WAVEOUT Config_WaveOut;
|
CONFIG_WAVEOUT Config_WaveOut;
|
||||||
CONFIG_XAUDIO2 Config_XAudio2;
|
CONFIG_XAUDIO2 Config_XAudio2;
|
||||||
|
|
||||||
// DSP
|
// DSP
|
||||||
bool dspPluginEnabled = false;
|
bool dspPluginEnabled = false;
|
||||||
int dspPluginModule = 0;
|
int dspPluginModule = 0;
|
||||||
wchar_t dspPlugin[256];
|
wchar_t dspPlugin[256];
|
||||||
|
|
||||||
bool StereoExpansionEnabled = false;
|
bool StereoExpansionEnabled = false;
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
void ReadSettings()
|
void ReadSettings()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
void WriteSettings()
|
void WriteSettings()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void configure()
|
void configure()
|
||||||
{
|
{
|
||||||
ReadSettings();
|
ReadSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageBox(char const*, ...)
|
void MessageBox(char const*, ...)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,8 +103,6 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void ClampValues();
|
static void ClampValues();
|
||||||
//static bool CALLBACK DialogProc(uptr hWnd,u32 uMsg,WPARAM wParam,LPARAM lParam);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
|
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
|
||||||
* Developed and maintained by the Pcsx2 Development Team.
|
* Developed and maintained by the Pcsx2 Development Team.
|
||||||
*
|
*
|
||||||
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
|
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
|
||||||
*
|
*
|
||||||
* SPU2-X is free software: you can redistribute it and/or modify it under the terms
|
* SPU2-X is free software: you can redistribute it and/or modify it under the terms
|
||||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
@ -14,46 +14,46 @@
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Linux.h"
|
#include "Linux.h"
|
||||||
|
|
||||||
void SysMessage(char *fmt, ...) {
|
void SysMessage(char *fmt, ...) {
|
||||||
GtkWidget *Ok,*Txt;
|
GtkWidget *Ok,*Txt;
|
||||||
GtkWidget *Box,*Box1;
|
GtkWidget *Box,*Box1;
|
||||||
va_list list;
|
va_list list;
|
||||||
char msg[512];
|
char msg[512];
|
||||||
|
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
vsprintf(msg, fmt, list);
|
vsprintf(msg, fmt, list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
|
|
||||||
if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0;
|
if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0;
|
||||||
|
|
||||||
MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||||
gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER);
|
gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER);
|
||||||
gtk_window_set_title(GTK_WINDOW(MsgDlg), "SPU2null Msg");
|
gtk_window_set_title(GTK_WINDOW(MsgDlg), "SPU2null Msg");
|
||||||
gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5);
|
gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5);
|
||||||
|
|
||||||
Box = gtk_vbox_new(5, 0);
|
Box = gtk_vbox_new(5, 0);
|
||||||
gtk_container_add(GTK_CONTAINER(MsgDlg), Box);
|
gtk_container_add(GTK_CONTAINER(MsgDlg), Box);
|
||||||
gtk_widget_show(Box);
|
gtk_widget_show(Box);
|
||||||
|
|
||||||
Txt = gtk_label_new(msg);
|
Txt = gtk_label_new(msg);
|
||||||
|
|
||||||
gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5);
|
gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5);
|
||||||
gtk_widget_show(Txt);
|
gtk_widget_show(Txt);
|
||||||
|
|
||||||
Box1 = gtk_hbutton_box_new();
|
Box1 = gtk_hbutton_box_new();
|
||||||
gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0);
|
gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0);
|
||||||
gtk_widget_show(Box1);
|
gtk_widget_show(Box1);
|
||||||
|
|
||||||
Ok = gtk_button_new_with_label("Ok");
|
Ok = gtk_button_new_with_label("Ok");
|
||||||
gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL);
|
gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL);
|
||||||
gtk_container_add(GTK_CONTAINER(Box1), Ok);
|
gtk_container_add(GTK_CONTAINER(Box1), Ok);
|
||||||
GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT);
|
GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT);
|
||||||
gtk_widget_show(Ok);
|
gtk_widget_show(Ok);
|
||||||
|
|
||||||
gtk_widget_show(MsgDlg);
|
gtk_widget_show(MsgDlg);
|
||||||
|
|
||||||
gtk_main();
|
gtk_main();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,35 +19,39 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
LPF_data::LPF_data( double freq, double srate )
|
template< typename FloatType > __forceinline
|
||||||
|
LowPassFilter<FloatType>::LowPassFilter( FloatType freq, FloatType srate )
|
||||||
{
|
{
|
||||||
double omega = 2.0 * freq / srate;
|
typedef FloatType FT;
|
||||||
static const double g = 1.0;
|
|
||||||
|
FloatType omega = (FT)2.0 * freq / srate;
|
||||||
|
static const FloatType g = (FT)1.0;
|
||||||
|
|
||||||
// calculating coefficients:
|
// calculating coefficients:
|
||||||
|
|
||||||
double k,p,q,a;
|
FloatType k,p,q,a;
|
||||||
double a0,a1,a2,a3,a4;
|
FloatType a0,a1,a2,a3,a4;
|
||||||
|
|
||||||
k=(4.0*g-3.0)/(g+1.0);
|
k = ((FT)4.0*g-(FT)3.0)/(g+(FT)1.0);
|
||||||
p=1.0-0.25*k;p*=p;
|
p = (FT)1.0-(FT)0.25*k;
|
||||||
|
p *= p;
|
||||||
|
|
||||||
// LP:
|
// LP:
|
||||||
a=1.0/(tan(0.5*omega)*(1.0+p));
|
a = (FT)1.0/(tan((FT)0.5*omega)*((FT)1.0+p));
|
||||||
p=1.0+a;
|
p = (FT)1.0+a;
|
||||||
q=1.0-a;
|
q = (FT)1.0-a;
|
||||||
|
|
||||||
a0=1.0/(k+p*p*p*p);
|
|
||||||
a1=4.0*(k+p*p*p*q);
|
|
||||||
a2=6.0*(k+p*p*q*q);
|
|
||||||
a3=4.0*(k+p*q*q*q);
|
|
||||||
a4= (k+q*q*q*q);
|
|
||||||
p=a0*(k+1.0);
|
|
||||||
|
|
||||||
|
a0 = (FT)1.0/(k+p*p*p*p);
|
||||||
|
a1 = (FT)4.0*(k+p*p*p*q);
|
||||||
|
a2 = (FT)6.0*(k+p*p*q*q);
|
||||||
|
a3 = (FT)4.0*(k+p*q*q*q);
|
||||||
|
a4 = (k+q*q*q*q);
|
||||||
|
p = a0*(k+(FT)1.0);
|
||||||
|
|
||||||
coef[0] = p;
|
coef[0] = p;
|
||||||
coef[1] = 4.0*p;
|
coef[1] = (FT)4.0*p;
|
||||||
coef[2] = 6.0*p;
|
coef[2] = (FT)6.0*p;
|
||||||
coef[3] = 4.0*p;
|
coef[3] = (FT)4.0*p;
|
||||||
coef[4] = p;
|
coef[4] = p;
|
||||||
coef[5] = -a1*a0;
|
coef[5] = -a1*a0;
|
||||||
coef[6] = -a2*a0;
|
coef[6] = -a2*a0;
|
||||||
|
@ -56,9 +60,10 @@ LPF_data::LPF_data( double freq, double srate )
|
||||||
}
|
}
|
||||||
|
|
||||||
// Processes a single sample into the LPF.
|
// Processes a single sample into the LPF.
|
||||||
double LPF_data::sample( double inval )
|
template< typename FloatType > __forceinline
|
||||||
|
FloatType LowPassFilter<FloatType>::sample( FloatType inval )
|
||||||
{
|
{
|
||||||
const double out = (coef[0]*inval) + d[0];
|
const FloatType out = (coef[0]*inval) + d[0];
|
||||||
d[0] = (coef[1]*inval) + (coef[5]*out) + d[1];
|
d[0] = (coef[1]*inval) + (coef[5]*out) + d[1];
|
||||||
d[1] = (coef[2]*inval) + (coef[6]*out) + d[2];
|
d[1] = (coef[2]*inval) + (coef[6]*out) + d[2];
|
||||||
d[2] = (coef[3]*inval) + (coef[7]*out) + d[3];
|
d[2] = (coef[3]*inval) + (coef[7]*out) + d[3];
|
||||||
|
@ -66,3 +71,23 @@ double LPF_data::sample( double inval )
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LowPassFilter32::LowPassFilter32( float freq, float srate ) :
|
||||||
|
impl_lpf( freq, srate )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LowPassFilter64::LowPassFilter64( double freq, double srate ) :
|
||||||
|
impl_lpf( freq, srate )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
float LowPassFilter32::sample( float inval )
|
||||||
|
{
|
||||||
|
return impl_lpf.sample( inval );
|
||||||
|
}
|
||||||
|
|
||||||
|
double LowPassFilter64::sample( double inval )
|
||||||
|
{
|
||||||
|
return impl_lpf.sample( inval );
|
||||||
|
}
|
||||||
|
|
|
@ -1,30 +1,44 @@
|
||||||
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
|
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
|
||||||
* Developed and maintained by the Pcsx2 Development Team.
|
* Developed and maintained by the Pcsx2 Development Team.
|
||||||
*
|
*
|
||||||
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
|
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
|
||||||
*
|
*
|
||||||
* SPU2-X is free software: you can redistribute it and/or modify it under the terms
|
* SPU2-X is free software: you can redistribute it and/or modify it under the terms
|
||||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* SPU2-X is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
* SPU2-X is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
* PURPOSE. See the GNU Lesser General Public License for more details.
|
* PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "BaseTypes.h"
|
template< typename FloatType >
|
||||||
|
struct LowPassFilter
|
||||||
struct LPF_data
|
|
||||||
{
|
{
|
||||||
double coef[9];
|
FloatType coef[9];
|
||||||
double d[4];
|
FloatType d[4];
|
||||||
|
|
||||||
LPF_data( double freq, double srate );
|
LowPassFilter( FloatType freq, FloatType srate );
|
||||||
double sample( double inval );
|
FloatType sample( FloatType inval );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LowPassFilter32
|
||||||
|
{
|
||||||
|
LowPassFilter<float> impl_lpf;
|
||||||
|
|
||||||
|
LowPassFilter32( float freq, float srate );
|
||||||
|
float sample( float inval );
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LowPassFilter64
|
||||||
|
{
|
||||||
|
LowPassFilter<double> impl_lpf;
|
||||||
|
|
||||||
|
LowPassFilter64( double freq, double srate );
|
||||||
|
double sample( double inval );
|
||||||
|
};
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Spu2.h"
|
#include "Global.h"
|
||||||
#include <float.h>
|
//#include <float.h>
|
||||||
|
|
||||||
extern void spdif_update();
|
extern void spdif_update();
|
||||||
|
|
||||||
|
@ -477,22 +477,9 @@ static s32 __forceinline __fastcall GetNoiseValues( V_Core& thiscore, uint voice
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// //
|
// //
|
||||||
|
|
||||||
static __forceinline StereoOut32 ReadInputPV( uint core )
|
__forceinline StereoOut32 V_Core::ReadInputPV()
|
||||||
{
|
{
|
||||||
V_Core& thiscore( Cores[core] );
|
return ApplyVolume( ReadInput(), InpVol );
|
||||||
u32 pitch = AutoDMAPlayRate[core];
|
|
||||||
|
|
||||||
if(pitch==0) pitch=48000;
|
|
||||||
|
|
||||||
thiscore.ADMAPV += pitch;
|
|
||||||
while(thiscore.ADMAPV>=48000)
|
|
||||||
{
|
|
||||||
ReadInput( core, thiscore.ADMAP );
|
|
||||||
thiscore.ADMAPV -= 48000;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply volumes:
|
|
||||||
return ApplyVolume( thiscore.ADMAP, thiscore.InpVol );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -547,7 +534,7 @@ static __forceinline StereoOut32 MixVoice( uint coreidx, uint voiceidx )
|
||||||
vc.OutX = Value;
|
vc.OutX = Value;
|
||||||
|
|
||||||
if( IsDevBuild )
|
if( IsDevBuild )
|
||||||
DebugCores[coreidx].Voices[voiceidx].displayPeak = max(DebugCores[coreidx].Voices[voiceidx].displayPeak,abs(vc.OutX));
|
DebugCores[coreidx].Voices[voiceidx].displayPeak = std::max(DebugCores[coreidx].Voices[voiceidx].displayPeak,abs(vc.OutX));
|
||||||
|
|
||||||
// Write-back of raw voice data (post ADSR applied)
|
// Write-back of raw voice data (post ADSR applied)
|
||||||
|
|
||||||
|
@ -567,19 +554,6 @@ static __forceinline StereoOut32 MixVoice( uint coreidx, uint voiceidx )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VoiceMixSet
|
|
||||||
{
|
|
||||||
static const VoiceMixSet Empty;
|
|
||||||
StereoOut32 Dry, Wet;
|
|
||||||
|
|
||||||
VoiceMixSet() {}
|
|
||||||
VoiceMixSet( const StereoOut32& dry, const StereoOut32& wet ) :
|
|
||||||
Dry( dry ),
|
|
||||||
Wet( wet )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const VoiceMixSet VoiceMixSet::Empty( (StereoOut32()), (StereoOut32()) ); // Don't use SteroOut32::Empty because C++ doesn't make any dep/order checks on global initializers.
|
const VoiceMixSet VoiceMixSet::Empty( (StereoOut32()), (StereoOut32()) ); // Don't use SteroOut32::Empty because C++ doesn't make any dep/order checks on global initializers.
|
||||||
|
|
||||||
static __forceinline void MixCoreVoices( VoiceMixSet& dest, const uint coreidx )
|
static __forceinline void MixCoreVoices( VoiceMixSet& dest, const uint coreidx )
|
||||||
|
@ -599,61 +573,60 @@ static __forceinline void MixCoreVoices( VoiceMixSet& dest, const uint coreidx )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static StereoOut32 __fastcall MixCore( const uint coreidx, const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext )
|
StereoOut32 V_Core::Mix( const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext )
|
||||||
{
|
{
|
||||||
V_Core& thiscore( Cores[coreidx] );
|
MasterVol.Update();
|
||||||
thiscore.MasterVol.Update();
|
|
||||||
|
|
||||||
// Saturate final result to standard 16 bit range.
|
// Saturate final result to standard 16 bit range.
|
||||||
const VoiceMixSet Voices( clamp_mix( inVoices.Dry ), clamp_mix( inVoices.Wet ) );
|
const VoiceMixSet Voices( clamp_mix( inVoices.Dry ), clamp_mix( inVoices.Wet ) );
|
||||||
|
|
||||||
// Write Mixed results To Output Area
|
// Write Mixed results To Output Area
|
||||||
spu2M_WriteFast( 0x1000 + (coreidx<<12) + OutPos, Voices.Dry.Left );
|
spu2M_WriteFast( 0x1000 + (Index<<12) + OutPos, Voices.Dry.Left );
|
||||||
spu2M_WriteFast( 0x1200 + (coreidx<<12) + OutPos, Voices.Dry.Right );
|
spu2M_WriteFast( 0x1200 + (Index<<12) + OutPos, Voices.Dry.Right );
|
||||||
spu2M_WriteFast( 0x1400 + (coreidx<<12) + OutPos, Voices.Wet.Left );
|
spu2M_WriteFast( 0x1400 + (Index<<12) + OutPos, Voices.Wet.Left );
|
||||||
spu2M_WriteFast( 0x1600 + (coreidx<<12) + OutPos, Voices.Wet.Right );
|
spu2M_WriteFast( 0x1600 + (Index<<12) + OutPos, Voices.Wet.Right );
|
||||||
|
|
||||||
// Write mixed results to logfile (if enabled)
|
// Write mixed results to logfile (if enabled)
|
||||||
|
|
||||||
WaveDump::WriteCore( coreidx, CoreSrc_DryVoiceMix, Voices.Dry );
|
WaveDump::WriteCore( Index, CoreSrc_DryVoiceMix, Voices.Dry );
|
||||||
WaveDump::WriteCore( coreidx, CoreSrc_WetVoiceMix, Voices.Wet );
|
WaveDump::WriteCore( Index, CoreSrc_WetVoiceMix, Voices.Wet );
|
||||||
|
|
||||||
// Mix in the Input data
|
// Mix in the Input data
|
||||||
|
|
||||||
StereoOut32 TD(
|
StereoOut32 TD(
|
||||||
Input.Left & thiscore.DryGate.InpL,
|
Input.Left & DryGate.InpL,
|
||||||
Input.Right & thiscore.DryGate.InpR
|
Input.Right & DryGate.InpR
|
||||||
);
|
);
|
||||||
|
|
||||||
// Mix in the Voice data
|
// Mix in the Voice data
|
||||||
TD.Left += Voices.Dry.Left & thiscore.DryGate.SndL;
|
TD.Left += Voices.Dry.Left & DryGate.SndL;
|
||||||
TD.Right += Voices.Dry.Right & thiscore.DryGate.SndR;
|
TD.Right += Voices.Dry.Right & DryGate.SndR;
|
||||||
|
|
||||||
// Mix in the External (nothing/core0) data
|
// Mix in the External (nothing/core0) data
|
||||||
TD.Left += Ext.Left & thiscore.DryGate.ExtL;
|
TD.Left += Ext.Left & DryGate.ExtL;
|
||||||
TD.Right += Ext.Right & thiscore.DryGate.ExtR;
|
TD.Right += Ext.Right & DryGate.ExtR;
|
||||||
|
|
||||||
if( !EffectsDisabled )
|
if( !EffectsDisabled )
|
||||||
{
|
{
|
||||||
//Reverb pointer advances regardless of the FxEnable bit...
|
//Reverb pointer advances regardless of the FxEnable bit...
|
||||||
Reverb_AdvanceBuffer( thiscore );
|
Reverb_AdvanceBuffer();
|
||||||
|
|
||||||
if( thiscore.FxEnable )
|
if( FxEnable )
|
||||||
{
|
{
|
||||||
// Mix Input, Voice, and External data:
|
// Mix Input, Voice, and External data:
|
||||||
StereoOut32 TW(
|
StereoOut32 TW(
|
||||||
Input.Left & thiscore.WetGate.InpL,
|
Input.Left & WetGate.InpL,
|
||||||
Input.Right & thiscore.WetGate.InpR
|
Input.Right & WetGate.InpR
|
||||||
);
|
);
|
||||||
|
|
||||||
TW.Left += Voices.Wet.Left & thiscore.WetGate.SndL;
|
TW.Left += Voices.Wet.Left & WetGate.SndL;
|
||||||
TW.Right += Voices.Wet.Right & thiscore.WetGate.SndR;
|
TW.Right += Voices.Wet.Right & WetGate.SndR;
|
||||||
TW.Left += Ext.Left & thiscore.WetGate.ExtL;
|
TW.Left += Ext.Left & WetGate.ExtL;
|
||||||
TW.Right += Ext.Right & thiscore.WetGate.ExtR;
|
TW.Right += Ext.Right & WetGate.ExtR;
|
||||||
|
|
||||||
WaveDump::WriteCore( coreidx, CoreSrc_PreReverb, TW );
|
WaveDump::WriteCore( Index, CoreSrc_PreReverb, TW );
|
||||||
|
|
||||||
StereoOut32 RV( DoReverb( thiscore, TW ) );
|
StereoOut32 RV( DoReverb( TW ) );
|
||||||
|
|
||||||
// Volume boost after effects application. Boosting volume prior to effects
|
// Volume boost after effects application. Boosting volume prior to effects
|
||||||
// causes slight overflows in some games, and the volume boost is required.
|
// causes slight overflows in some games, and the volume boost is required.
|
||||||
|
@ -663,15 +636,15 @@ static StereoOut32 __fastcall MixCore( const uint coreidx, const VoiceMixSet& in
|
||||||
RV.Left *= 2;
|
RV.Left *= 2;
|
||||||
RV.Right *= 2;
|
RV.Right *= 2;
|
||||||
|
|
||||||
WaveDump::WriteCore( coreidx, CoreSrc_PostReverb, RV );
|
WaveDump::WriteCore( Index, CoreSrc_PostReverb, RV );
|
||||||
|
|
||||||
// Mix Dry+Wet
|
// Mix Dry+Wet
|
||||||
return TD + ApplyVolume( RV, thiscore.FxVol );
|
return TD + ApplyVolume( RV, FxVol );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WaveDump::WriteCore( coreidx, CoreSrc_PreReverb, 0, 0 );
|
WaveDump::WriteCore( Index, CoreSrc_PreReverb, 0, 0 );
|
||||||
WaveDump::WriteCore( coreidx, CoreSrc_PostReverb, 0, 0 );
|
WaveDump::WriteCore( Index, CoreSrc_PostReverb, 0, 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TD;
|
return TD;
|
||||||
|
@ -685,8 +658,8 @@ __forceinline void Mix()
|
||||||
// Note: Playmode 4 is SPDIF, which overrides other inputs.
|
// Note: Playmode 4 is SPDIF, which overrides other inputs.
|
||||||
StereoOut32 InputData[2] =
|
StereoOut32 InputData[2] =
|
||||||
{
|
{
|
||||||
(PlayMode&4) ? StereoOut32::Empty : ReadInputPV( 0 ),
|
(PlayMode&4) ? StereoOut32::Empty : Cores[0].ReadInputPV(),
|
||||||
(PlayMode&8) ? StereoOut32::Empty : ReadInputPV( 1 )
|
(PlayMode&8) ? StereoOut32::Empty : Cores[1].ReadInputPV()
|
||||||
};
|
};
|
||||||
|
|
||||||
WaveDump::WriteCore( 0, CoreSrc_Input, InputData[0] );
|
WaveDump::WriteCore( 0, CoreSrc_Input, InputData[0] );
|
||||||
|
@ -697,7 +670,7 @@ __forceinline void Mix()
|
||||||
MixCoreVoices( VoiceData[0], 0 );
|
MixCoreVoices( VoiceData[0], 0 );
|
||||||
MixCoreVoices( VoiceData[1], 1 );
|
MixCoreVoices( VoiceData[1], 1 );
|
||||||
|
|
||||||
StereoOut32 Ext( MixCore( 0, VoiceData[0], InputData[0], StereoOut32::Empty ) );
|
StereoOut32 Ext( Cores[0].Mix( VoiceData[0], InputData[0], StereoOut32::Empty ) );
|
||||||
|
|
||||||
if( (PlayMode & 4) || (Cores[0].Mute!=0) )
|
if( (PlayMode & 4) || (Cores[0].Mute!=0) )
|
||||||
Ext = StereoOut32::Empty;
|
Ext = StereoOut32::Empty;
|
||||||
|
@ -714,14 +687,14 @@ __forceinline void Mix()
|
||||||
WaveDump::WriteCore( 0, CoreSrc_External, Ext );
|
WaveDump::WriteCore( 0, CoreSrc_External, Ext );
|
||||||
|
|
||||||
ApplyVolume( Ext, Cores[1].ExtVol );
|
ApplyVolume( Ext, Cores[1].ExtVol );
|
||||||
StereoOut32 Out( MixCore( 1, VoiceData[1], InputData[1], Ext ) );
|
StereoOut32 Out( Cores[1].Mix( VoiceData[1], InputData[1], Ext ) );
|
||||||
|
|
||||||
if( PlayMode & 8 )
|
if( PlayMode & 8 )
|
||||||
{
|
{
|
||||||
// Experimental CDDA support
|
// Experimental CDDA support
|
||||||
// The CDDA overrides all other mixer output. It's a direct feed!
|
// The CDDA overrides all other mixer output. It's a direct feed!
|
||||||
|
|
||||||
ReadInput( 1, Out );
|
Out = Cores[1].ReadInput();
|
||||||
//WaveLog::WriteCore( 1, "CDDA-32", OutL, OutR );
|
//WaveLog::WriteCore( 1, "CDDA-32", OutL, OutR );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -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 );
|
|
@ -15,33 +15,40 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Spu2.h"
|
#include "Global.h"
|
||||||
|
#include "PS2E-spu2.h"
|
||||||
|
#include "dma.h"
|
||||||
#include "Dialogs.h"
|
#include "Dialogs.h"
|
||||||
#include "RegTable.h"
|
#include "RegTable.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#include "svnrev.h"
|
# include "svnrev.h"
|
||||||
#else
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// [Air]: Adding the spu2init boolean wasn't necessary except to help me in
|
// PCSX2 expects ASNI, not unicode, so this MUST always be char...
|
||||||
// debugging the spu2 suspend/resume behavior (when user hits escape).
|
|
||||||
static bool spu2open=false; // has spu2open plugin interface been called?
|
|
||||||
static bool spu2init=false; // has spu2init plugin interface been called?
|
|
||||||
|
|
||||||
//static s32 logvolume[16384];
|
|
||||||
static u32 pClocks=0;
|
|
||||||
|
|
||||||
// Pcsx2 expects ASNI, not unicode, so this MUST always be char...
|
|
||||||
static char libraryName[256];
|
static char libraryName[256];
|
||||||
|
|
||||||
|
|
||||||
|
static bool IsOpened = false;
|
||||||
|
static bool IsInitialized = false;
|
||||||
|
|
||||||
|
static u32 pClocks = 0;
|
||||||
|
|
||||||
|
u32* cyclePtr = NULL;
|
||||||
|
u32 lClocks = 0;
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD dwReason,LPVOID lpvReserved)
|
HINSTANCE hInstance;
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
|
||||||
{
|
{
|
||||||
if( dwReason == DLL_PROCESS_ATTACH )
|
if( dwReason == DLL_PROCESS_ATTACH )
|
||||||
hInstance = hinstDLL;
|
hInstance = hinstDLL;
|
||||||
|
|
||||||
|
else if( dwReason == DLL_PROCESS_DETACH )
|
||||||
|
{
|
||||||
|
// TODO : perform shutdown procedure, just in case PCSX2 itself failed
|
||||||
|
// to for some reason..
|
||||||
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -106,7 +113,7 @@ EXPORT_C_(char*) PS2EgetLibName()
|
||||||
|
|
||||||
EXPORT_C_(u32) PS2EgetLibVersion2(u32 type)
|
EXPORT_C_(u32) PS2EgetLibVersion2(u32 type)
|
||||||
{
|
{
|
||||||
return (VersionInfo::PluginApi<<16) | (VersionInfo::Release<<8) | VersionInfo::Revision;
|
return (PS2E_SPU2_VERSION<<16) | (VersionInfo::Release<<8) | VersionInfo::Revision;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_C_(void) SPU2configure()
|
EXPORT_C_(void) SPU2configure()
|
||||||
|
@ -126,6 +133,87 @@ EXPORT_C_(s32) SPU2test()
|
||||||
return SndBuffer::Test();
|
return SndBuffer::Test();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// DMA 4/7 Callbacks from Core Emulator
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
u16* DMABaseAddr;
|
||||||
|
void (* _irqcallback)();
|
||||||
|
void (* dma4callback)();
|
||||||
|
void (* dma7callback)();
|
||||||
|
|
||||||
|
EXPORT_C_(u32) CALLBACK SPU2ReadMemAddr(int core)
|
||||||
|
{
|
||||||
|
return Cores[core].MADR;
|
||||||
|
}
|
||||||
|
EXPORT_C_(void) CALLBACK SPU2WriteMemAddr(int core,u32 value)
|
||||||
|
{
|
||||||
|
Cores[core].MADR = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_C_(void) CALLBACK SPU2setDMABaseAddr(uptr baseaddr)
|
||||||
|
{
|
||||||
|
DMABaseAddr = (u16*)baseaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_C_(void) CALLBACK SPU2readDMA4Mem(u16 *pMem, u32 size) // size now in 16bit units
|
||||||
|
{
|
||||||
|
if( cyclePtr != NULL ) TimeUpdate( *cyclePtr );
|
||||||
|
|
||||||
|
FileLog("[%10d] SPU2 readDMA4Mem size %x\n",Cycles, size<<1);
|
||||||
|
Cores[0].DoDMAread(pMem, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_C_(void) CALLBACK SPU2writeDMA4Mem(u16* pMem, u32 size) // size now in 16bit units
|
||||||
|
{
|
||||||
|
if( cyclePtr != NULL ) TimeUpdate( *cyclePtr );
|
||||||
|
|
||||||
|
FileLog("[%10d] SPU2 writeDMA4Mem size %x at address %x\n",Cycles, size<<1, Cores[0].TSA);
|
||||||
|
#ifdef S2R_ENABLE
|
||||||
|
if(!replay_mode)
|
||||||
|
s2r_writedma4(Cycles,pMem,size);
|
||||||
|
#endif
|
||||||
|
Cores[0].DoDMAwrite(pMem,size);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_C_(void) CALLBACK SPU2interruptDMA4()
|
||||||
|
{
|
||||||
|
if( cyclePtr != NULL ) TimeUpdate( *cyclePtr );
|
||||||
|
|
||||||
|
FileLog("[%10d] SPU2 interruptDMA4\n",Cycles);
|
||||||
|
Cores[0].Regs.STATX |= 0x80;
|
||||||
|
//Cores[0].Regs.ATTR &= ~0x30;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_C_(void) CALLBACK SPU2readDMA7Mem(u16* pMem, u32 size)
|
||||||
|
{
|
||||||
|
if( cyclePtr != NULL ) TimeUpdate( *cyclePtr );
|
||||||
|
|
||||||
|
FileLog("[%10d] SPU2 readDMA7Mem size %x\n",Cycles, size<<1);
|
||||||
|
Cores[1].DoDMAread(pMem,size);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_C_(void) CALLBACK SPU2writeDMA7Mem(u16* pMem, u32 size)
|
||||||
|
{
|
||||||
|
if( cyclePtr != NULL ) TimeUpdate( *cyclePtr );
|
||||||
|
|
||||||
|
FileLog("[%10d] SPU2 writeDMA7Mem size %x at address %x\n",Cycles, size<<1, Cores[1].TSA);
|
||||||
|
#ifdef S2R_ENABLE
|
||||||
|
if(!replay_mode)
|
||||||
|
s2r_writedma7(Cycles,pMem,size);
|
||||||
|
#endif
|
||||||
|
Cores[1].DoDMAwrite(pMem,size);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_C_(void) CALLBACK SPU2interruptDMA7()
|
||||||
|
{
|
||||||
|
if( cyclePtr != NULL ) TimeUpdate( *cyclePtr );
|
||||||
|
|
||||||
|
FileLog("[%10d] SPU2 interruptDMA7\n",Cycles);
|
||||||
|
Cores[1].Regs.STATX |= 0x80;
|
||||||
|
//Cores[1].Regs.ATTR &= ~0x30;
|
||||||
|
}
|
||||||
|
|
||||||
EXPORT_C_(s32) SPU2init()
|
EXPORT_C_(s32) SPU2init()
|
||||||
{
|
{
|
||||||
#define MAKESURE(a,b) \
|
#define MAKESURE(a,b) \
|
||||||
|
@ -147,13 +235,13 @@ EXPORT_C_(s32) SPU2init()
|
||||||
#endif
|
#endif
|
||||||
srand((unsigned)time(NULL));
|
srand((unsigned)time(NULL));
|
||||||
|
|
||||||
if (spu2init)
|
if (IsInitialized)
|
||||||
{
|
{
|
||||||
ConLog( " * SPU2: Already initialized - Ignoring SPU2init signal." );
|
ConLog( " * SPU2: Already initialized - Ignoring SPU2init signal." );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
spu2init=true;
|
IsInitialized = true;
|
||||||
|
|
||||||
spu2regs = (short*)malloc(0x010000);
|
spu2regs = (short*)malloc(0x010000);
|
||||||
_spu2mem = (short*)malloc(0x200000);
|
_spu2mem = (short*)malloc(0x200000);
|
||||||
|
@ -181,8 +269,8 @@ EXPORT_C_(s32) SPU2init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(spu2regs,0,0x010000);
|
memset(spu2regs, 0, 0x010000);
|
||||||
memset(_spu2mem,0,0x200000);
|
memset(_spu2mem, 0, 0x200000);
|
||||||
Cores[0].Reset();
|
Cores[0].Reset();
|
||||||
Cores[1].Reset();
|
Cores[1].Reset();
|
||||||
|
|
||||||
|
@ -217,7 +305,7 @@ EXPORT_C_(s32) SPU2init()
|
||||||
|
|
||||||
EXPORT_C_(s32) SPU2open(void *pDsp)
|
EXPORT_C_(s32) SPU2open(void *pDsp)
|
||||||
{
|
{
|
||||||
if( spu2open ) return 0;
|
if( IsOpened ) return 0;
|
||||||
|
|
||||||
FileLog("[%10d] SPU2 Open\n",Cycles);
|
FileLog("[%10d] SPU2 Open\n",Cycles);
|
||||||
|
|
||||||
|
@ -229,7 +317,7 @@ EXPORT_C_(s32) SPU2open(void *pDsp)
|
||||||
debugDialogOpen=1;
|
debugDialogOpen=1;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
spu2open = true;
|
IsOpened = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SndBuffer::Init();
|
SndBuffer::Init();
|
||||||
|
@ -247,7 +335,9 @@ EXPORT_C_(s32) SPU2open(void *pDsp)
|
||||||
|
|
||||||
EXPORT_C_(void) SPU2close()
|
EXPORT_C_(void) SPU2close()
|
||||||
{
|
{
|
||||||
if( !spu2open ) return;
|
if( !IsOpened ) return;
|
||||||
|
IsOpened = false;
|
||||||
|
|
||||||
FileLog("[%10d] SPU2 Close\n",Cycles);
|
FileLog("[%10d] SPU2 Close\n",Cycles);
|
||||||
|
|
||||||
#ifndef __LINUX__
|
#ifndef __LINUX__
|
||||||
|
@ -255,13 +345,12 @@ EXPORT_C_(void) SPU2close()
|
||||||
#endif
|
#endif
|
||||||
spdif_shutdown();
|
spdif_shutdown();
|
||||||
SndBuffer::Cleanup();
|
SndBuffer::Cleanup();
|
||||||
|
|
||||||
spu2open = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_C_(void) SPU2shutdown()
|
EXPORT_C_(void) SPU2shutdown()
|
||||||
{
|
{
|
||||||
if(!spu2init) return;
|
if(!IsInitialized) return;
|
||||||
|
IsInitialized = false;
|
||||||
|
|
||||||
ConLog( " * SPU2: Shutting down.\n" );
|
ConLog( " * SPU2: Shutting down.\n" );
|
||||||
|
|
||||||
|
@ -285,12 +374,9 @@ EXPORT_C_(void) SPU2shutdown()
|
||||||
|
|
||||||
DMALogClose();
|
DMALogClose();
|
||||||
|
|
||||||
spu2init = false;
|
safe_free(spu2regs);
|
||||||
|
safe_free(_spu2mem);
|
||||||
SAFE_FREE(spu2regs);
|
safe_free( pcm_cache_data );
|
||||||
SAFE_FREE(_spu2mem);
|
|
||||||
|
|
||||||
SAFE_FREE( pcm_cache_data );
|
|
||||||
|
|
||||||
spu2regs = NULL;
|
spu2regs = NULL;
|
||||||
_spu2mem = NULL;
|
_spu2mem = NULL;
|
||||||
|
@ -312,32 +398,8 @@ bool numpad_plus = false, numpad_plus_old = false;
|
||||||
|
|
||||||
EXPORT_C_(void) SPU2async(u32 cycles)
|
EXPORT_C_(void) SPU2async(u32 cycles)
|
||||||
{
|
{
|
||||||
if( IsDevBuild )
|
|
||||||
{
|
|
||||||
u32 oldClocks = lClocks;
|
|
||||||
static u32 timer=0,time1=0,time2=0;
|
|
||||||
timer++;
|
|
||||||
if (timer == 1){
|
|
||||||
time1=timeGetTime();
|
|
||||||
}
|
|
||||||
if (timer == 3000){
|
|
||||||
time2 = timeGetTime()-time1 ;
|
|
||||||
timer=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DspUpdate();
|
DspUpdate();
|
||||||
|
|
||||||
if( IsDevBuild )
|
|
||||||
{
|
|
||||||
/*numpad_plus = (GetAsyncKeyState(VK_ADD)&0x8000)!=0;
|
|
||||||
if(numpad_plus && !numpad_plus_old)
|
|
||||||
{
|
|
||||||
DoFullDump();
|
|
||||||
}
|
|
||||||
numpad_plus_old = numpad_plus;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cyclePtr != NULL)
|
if(cyclePtr != NULL)
|
||||||
{
|
{
|
||||||
TimeUpdate( *cyclePtr );
|
TimeUpdate( *cyclePtr );
|
||||||
|
@ -366,7 +428,7 @@ EXPORT_C_(u16) SPU2read(u32 rmem)
|
||||||
|
|
||||||
if(rmem==0x1f9001AC)
|
if(rmem==0x1f9001AC)
|
||||||
{
|
{
|
||||||
ret = DmaRead(core);
|
ret = Cores[core].DmaRead();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -375,7 +437,7 @@ EXPORT_C_(u16) SPU2read(u32 rmem)
|
||||||
|
|
||||||
if (rmem>>16 == 0x1f80)
|
if (rmem>>16 == 0x1f80)
|
||||||
{
|
{
|
||||||
ret = SPU_ps1_read(rmem);
|
ret = Cores[0].ReadRegPS1(rmem);
|
||||||
}
|
}
|
||||||
else if( (mem&0xFFFF) >= 0x800 )
|
else if( (mem&0xFFFF) >= 0x800 )
|
||||||
{
|
{
|
||||||
|
@ -400,44 +462,19 @@ EXPORT_C_(void) SPU2write(u32 rmem, u16 value)
|
||||||
s2r_writereg(Cycles,rmem,value);
|
s2r_writereg(Cycles,rmem,value);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(rmem==0x1f9001ac)
|
// Note: Reverb/Effects are very sensitive to having precise update timings.
|
||||||
{
|
// If the SPU2 isn't in in sync with the IOP, samples can end up playing at rather
|
||||||
//RegWriteLog(0,value);
|
// incorrect pitches and loop lengths.
|
||||||
if((Cores[0].IRQEnable)&&(Cores[0].TSA==Cores[0].IRQA))
|
|
||||||
{
|
if( cyclePtr != NULL )
|
||||||
Spdif.Info=4;
|
TimeUpdate( *cyclePtr );
|
||||||
SetIrqCall();
|
|
||||||
}
|
if (rmem>>16 == 0x1f80)
|
||||||
spu2M_Write( Cores[0].TSA++, value );
|
Cores[0].WriteRegPS1(rmem,value);
|
||||||
Cores[0].TSA&=0xfffff;
|
|
||||||
}
|
|
||||||
else if(rmem==0x1f9005ac)
|
|
||||||
{
|
|
||||||
//RegWriteLog(1,value);
|
|
||||||
if((Cores[0].IRQEnable)&&(Cores[0].TSA==Cores[0].IRQA))
|
|
||||||
{
|
|
||||||
Spdif.Info=4;
|
|
||||||
SetIrqCall();
|
|
||||||
}
|
|
||||||
spu2M_Write( Cores[1].TSA++, value );
|
|
||||||
Cores[1].TSA&=0xfffff;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Note: Reverb/Effects are very sensitive to having precise update timings.
|
SPU2writeLog( "write", rmem, value );
|
||||||
// If the SPU2 isn't in in sync with the IOP, samples can end up playing at rather
|
SPU2_FastWrite( rmem, value );
|
||||||
// incorrect pitches and loop lengths.
|
|
||||||
|
|
||||||
if( cyclePtr != NULL )
|
|
||||||
TimeUpdate( *cyclePtr );
|
|
||||||
|
|
||||||
if (rmem>>16 == 0x1f80)
|
|
||||||
SPU_ps1_write(rmem,value);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SPU2writeLog( "write", rmem, value );
|
|
||||||
SPU2_FastWrite( rmem, value );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,3 +490,29 @@ EXPORT_C_(int) SPU2setupRecording(int start, void* pData)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data)
|
||||||
|
{
|
||||||
|
if( mode == FREEZE_SIZE )
|
||||||
|
{
|
||||||
|
data->size = Savestate::SizeIt();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
jASSUME( mode == FREEZE_LOAD || mode == FREEZE_SAVE );
|
||||||
|
jASSUME( data != NULL );
|
||||||
|
|
||||||
|
if( data->data == NULL ) return -1;
|
||||||
|
Savestate::DataBlock& spud = (Savestate::DataBlock&)*(data->data);
|
||||||
|
|
||||||
|
switch( mode )
|
||||||
|
{
|
||||||
|
case FREEZE_LOAD: return Savestate::ThawIt( spud );
|
||||||
|
case FREEZE_SAVE: return Savestate::FreezeIt( spud );
|
||||||
|
|
||||||
|
jNO_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// technically unreachable, but kills a warning:
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
#include "Global.h"
|
|
@ -15,172 +15,138 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Spu2.h"
|
#include "Global.h"
|
||||||
|
#include "dma.h"
|
||||||
|
|
||||||
void __fastcall ReadInput( uint core, StereoOut32& PData )
|
// CDDA mode - Source audio data is 32 bits.
|
||||||
|
// PS2 note: Very! few PS2 games use this mode. Some PSX games used it, however no
|
||||||
|
// *known* PS2 game does since it was likely only available if the game was recorded to CD
|
||||||
|
// media (ie, not available in DVD mode, which almost all PS2 games use). Plus PS2 games
|
||||||
|
// generally prefer to use ADPCM streaming audio since they need as much storage space as
|
||||||
|
// possible for FMVs and high-def textures.
|
||||||
|
//
|
||||||
|
__forceinline StereoOut32 V_Core::ReadInput_HiFi( bool isCDDA )
|
||||||
{
|
{
|
||||||
V_Core& thiscore( Cores[core] );
|
InputPos &= ~1;
|
||||||
|
|
||||||
if((thiscore.AutoDMACtrl&(core+1))==(core+1))
|
#ifdef PCM24_S1_INTERLEAVE
|
||||||
|
StereoOut32 retval(
|
||||||
|
*((s32*)(ADMATempBuffer+(InputPos<<1))),
|
||||||
|
*((s32*)(ADMATempBuffer+(InputPos<<1)+2))
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
StereoOut32 retval(
|
||||||
|
(s32&)(ADMATempBuffer[InputPos]),
|
||||||
|
(s32&)(ADMATempBuffer[InputPos+0x200])
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( isCDDA )
|
||||||
{
|
{
|
||||||
s32 tl,tr;
|
//give 30 bit data (SndOut downsamples the rest of the way)
|
||||||
|
retval.Left >>= 2;
|
||||||
if((core==1)&&((PlayMode&8)==8))
|
retval.Right >>= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputPos += 2;
|
||||||
|
//if( (InputPos==0x100) || (InputPos>=0x200) ) // CDDA mode?
|
||||||
|
if( InputPos >= 0x200 )
|
||||||
|
{
|
||||||
|
AdmaInProgress = 0;
|
||||||
|
if(InputDataLeft >= 0x200)
|
||||||
{
|
{
|
||||||
thiscore.InputPos&=~1;
|
u8 k = (InputDataLeft >= InputDataProgress);
|
||||||
|
|
||||||
// CDDA mode
|
|
||||||
// Source audio data is 32 bits.
|
|
||||||
// We don't yet have the capability to handle this high res input data
|
|
||||||
// so we just downgrade it to 16 bits for now.
|
|
||||||
|
|
||||||
#ifdef PCM24_S1_INTERLEAVE
|
#ifdef PCM24_S1_INTERLEAVE
|
||||||
*PData.Left=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1))));
|
AutoDMAReadBuffer(1);
|
||||||
*PData.Right=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)+2)));
|
|
||||||
#else
|
#else
|
||||||
s32 *pl=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos]);
|
AutoDMAReadBuffer(0);
|
||||||
s32 *pr=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos+0x200]);
|
|
||||||
PData.Left = *pl;
|
|
||||||
PData.Right = *pr;
|
|
||||||
#endif
|
#endif
|
||||||
|
AdmaInProgress = 1;
|
||||||
|
|
||||||
PData.Left >>= 2; //give 30 bit data (SndOut downsamples the rest of the way)
|
TSA = (Index<<10) + InputPos;
|
||||||
PData.Right >>= 2;
|
|
||||||
|
|
||||||
thiscore.InputPos+=2;
|
if (InputDataLeft < 0x200)
|
||||||
if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) {
|
|
||||||
thiscore.AdmaInProgress=0;
|
|
||||||
if(thiscore.InputDataLeft>=0x200)
|
|
||||||
{
|
|
||||||
u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress;
|
|
||||||
|
|
||||||
#ifdef PCM24_S1_INTERLEAVE
|
|
||||||
AutoDMAReadBuffer(core,1);
|
|
||||||
#else
|
|
||||||
AutoDMAReadBuffer(core,0);
|
|
||||||
#endif
|
|
||||||
thiscore.AdmaInProgress=1;
|
|
||||||
|
|
||||||
thiscore.TSA=(core<<10)+thiscore.InputPos;
|
|
||||||
|
|
||||||
if (thiscore.InputDataLeft<0x200)
|
|
||||||
{
|
|
||||||
FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7');
|
|
||||||
|
|
||||||
if( IsDevBuild )
|
|
||||||
{
|
|
||||||
if(thiscore.InputDataLeft>0)
|
|
||||||
{
|
|
||||||
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thiscore.InputDataLeft=0;
|
|
||||||
thiscore.DMAICounter=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thiscore.InputPos&=0x1ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else if((core==0)&&((PlayMode&4)==4))
|
|
||||||
{
|
|
||||||
thiscore.InputPos&=~1;
|
|
||||||
|
|
||||||
s32 *pl=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos]);
|
|
||||||
s32 *pr=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos+0x200]);
|
|
||||||
PData.Left = *pl;
|
|
||||||
PData.Right = *pr;
|
|
||||||
|
|
||||||
thiscore.InputPos+=2;
|
|
||||||
if(thiscore.InputPos>=0x200) {
|
|
||||||
thiscore.AdmaInProgress=0;
|
|
||||||
if(thiscore.InputDataLeft>=0x200)
|
|
||||||
{
|
|
||||||
u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress;
|
|
||||||
|
|
||||||
AutoDMAReadBuffer(core,0);
|
|
||||||
|
|
||||||
thiscore.AdmaInProgress=1;
|
|
||||||
|
|
||||||
thiscore.TSA=(core<<10)+thiscore.InputPos;
|
|
||||||
|
|
||||||
if (thiscore.InputDataLeft<0x200)
|
|
||||||
{
|
|
||||||
FileLog("[%10d] Spdif AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7');
|
|
||||||
|
|
||||||
if( IsDevBuild )
|
|
||||||
{
|
|
||||||
if(thiscore.InputDataLeft>0)
|
|
||||||
{
|
|
||||||
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thiscore.InputDataLeft=0;
|
|
||||||
thiscore.DMAICounter=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thiscore.InputPos&=0x1ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if((core==1)&&((PlayMode&2)!=0))
|
|
||||||
{
|
{
|
||||||
tl=0;
|
FileLog("[%10d] %s AutoDMA%c block end.\n", isCDDA ? "CDDA" : "SPDIF", Cycles, GetDmaIndexChar());
|
||||||
tr=0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Using the temporary buffer because this area gets overwritten by some other code.
|
|
||||||
//*PData.Left = (s32)*(s16*)(spu2mem+0x2000+(core<<10)+thiscore.InputPos);
|
|
||||||
//*PData.Right = (s32)*(s16*)(spu2mem+0x2200+(core<<10)+thiscore.InputPos);
|
|
||||||
|
|
||||||
tl = (s32)thiscore.ADMATempBuffer[thiscore.InputPos];
|
if( IsDevBuild )
|
||||||
tr = (s32)thiscore.ADMATempBuffer[thiscore.InputPos+0x200];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
PData.Left = tl;
|
|
||||||
PData.Right = tr;
|
|
||||||
|
|
||||||
thiscore.InputPos++;
|
|
||||||
if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) {
|
|
||||||
thiscore.AdmaInProgress=0;
|
|
||||||
if(thiscore.InputDataLeft>=0x200)
|
|
||||||
{
|
{
|
||||||
u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress;
|
if(InputDataLeft > 0)
|
||||||
|
|
||||||
AutoDMAReadBuffer(core,0);
|
|
||||||
|
|
||||||
thiscore.AdmaInProgress=1;
|
|
||||||
|
|
||||||
thiscore.TSA=(core<<10)+thiscore.InputPos;
|
|
||||||
|
|
||||||
if (thiscore.InputDataLeft<0x200)
|
|
||||||
{
|
{
|
||||||
thiscore.AutoDMACtrl |= ~3;
|
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
|
||||||
|
|
||||||
if( IsDevBuild )
|
|
||||||
{
|
|
||||||
FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7');
|
|
||||||
if(thiscore.InputDataLeft>0)
|
|
||||||
{
|
|
||||||
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thiscore.InputDataLeft = 0;
|
|
||||||
thiscore.DMAICounter = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thiscore.InputPos&=0x1ff;
|
InputDataLeft = 0;
|
||||||
|
DMAICounter = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InputPos &= 0x1ff;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
StereoOut32 V_Core::ReadInput()
|
||||||
|
{
|
||||||
|
if((AutoDMACtrl&(Index+1)) != (Index+1))
|
||||||
|
return StereoOut32();
|
||||||
|
|
||||||
|
if( (Index==1) && ((PlayMode&8)==8) )
|
||||||
|
{
|
||||||
|
return ReadInput_HiFi( false );
|
||||||
|
}
|
||||||
|
else if( (Index==0) && ((PlayMode&4)==4) )
|
||||||
|
{
|
||||||
|
return ReadInput_HiFi( true );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PData.Left = 0;
|
StereoOut32 retval;
|
||||||
PData.Right = 0;
|
|
||||||
|
if( (Index!=1) || ((PlayMode&2)==0) )
|
||||||
|
{
|
||||||
|
// Using the temporary buffer because this area gets overwritten by some other code.
|
||||||
|
//*PData.Left = (s32)*(s16*)(spu2mem+0x2000+(core<<10)+InputPos);
|
||||||
|
//*PData.Right = (s32)*(s16*)(spu2mem+0x2200+(core<<10)+InputPos);
|
||||||
|
|
||||||
|
retval = StereoOut32(
|
||||||
|
(s32)ADMATempBuffer[InputPos],
|
||||||
|
(s32)ADMATempBuffer[InputPos+0x200]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputPos++;
|
||||||
|
if( (InputPos==0x100) || (InputPos>=0x200) )
|
||||||
|
{
|
||||||
|
AdmaInProgress = 0;
|
||||||
|
if(InputDataLeft >= 0x200)
|
||||||
|
{
|
||||||
|
u8 k=InputDataLeft>=InputDataProgress;
|
||||||
|
|
||||||
|
AutoDMAReadBuffer(0);
|
||||||
|
|
||||||
|
AdmaInProgress = 1;
|
||||||
|
TSA = (Index<<10) + InputPos;
|
||||||
|
|
||||||
|
if (InputDataLeft < 0x200)
|
||||||
|
{
|
||||||
|
AutoDMACtrl |= ~3;
|
||||||
|
|
||||||
|
if( IsDevBuild )
|
||||||
|
{
|
||||||
|
FileLog("[%10d] AutoDMA%c block end.\n",Cycles, GetDmaIndexChar());
|
||||||
|
if(InputDataLeft>0)
|
||||||
|
{
|
||||||
|
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDataLeft = 0;
|
||||||
|
DMAICounter = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InputPos&=0x1ff;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Spu2.h"
|
#include "Global.h"
|
||||||
#include "RegTable.h"
|
#include "RegTable.h"
|
||||||
|
|
||||||
const char *ParamNames[8]={"VOLL","VOLR","PITCH","ADSR1","ADSR2","ENVX","VOLXL","VOLXR"};
|
const char *ParamNames[8]={"VOLL","VOLR","PITCH","ADSR1","ADSR2","ENVX","VOLXL","VOLXR"};
|
||||||
|
|
|
@ -15,14 +15,13 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
#include "Spu2.h"
|
|
||||||
#include "RegTable.h"
|
#include "RegTable.h"
|
||||||
|
|
||||||
// This var is used to confirm that our lookup table is "correct"
|
// This var is used to confirm that our lookup table is "correct"
|
||||||
// If the assertion in DllMain fails, it means the table has too too few entries.
|
// If the assertion in DllMain fails, it means the table has too too few entries.
|
||||||
// (it can't have too many because that would generate a compiler error).
|
// (it can't have too many because that would generate a compiler error).
|
||||||
const u16 zero=0;
|
const u16 zero = 0;
|
||||||
|
|
||||||
#define PCORE(c,p) \
|
#define PCORE(c,p) \
|
||||||
U16P(Cores[c].p)
|
U16P(Cores[c].p)
|
||||||
|
|
|
@ -19,10 +19,10 @@
|
||||||
#ifndef _REGTABLE_H_
|
#ifndef _REGTABLE_H_
|
||||||
#define _REGTABLE_H_
|
#define _REGTABLE_H_
|
||||||
|
|
||||||
#define U16P(x) ( (u16*)&(x) )
|
#define U16P(x) ( (u16*)&(x) )
|
||||||
|
|
||||||
// Returns the hiword of a 32 bit integer.
|
// Returns the hiword of a 32 bit integer.
|
||||||
#define U16P_HI(x) ( ((u16*)&(x))+1 )
|
#define U16P_HI(x) ( ((u16*)&(x))+1 )
|
||||||
|
|
||||||
// Yay! Global namespace pollution 101!
|
// Yay! Global namespace pollution 101!
|
||||||
extern const u16 zero;
|
extern const u16 zero;
|
||||||
|
|
|
@ -15,52 +15,56 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Spu2.h"
|
#include "Global.h"
|
||||||
|
#include "Lowpass.h"
|
||||||
|
|
||||||
static LPF_data lowpass_left( 11000, SampleRate );
|
// Low pass filters: Change these to 32 for a speedup (benchmarks needed to see if
|
||||||
static LPF_data lowpass_right( 11000, SampleRate );
|
// the speed gain is worth the quality drop)
|
||||||
|
|
||||||
static __forceinline s32 RevbGetIndexer( V_Core& thiscore, s32 offset )
|
static LowPassFilter64 lowpass_left( 11000, SampleRate );
|
||||||
|
static LowPassFilter64 lowpass_right( 11000, SampleRate );
|
||||||
|
|
||||||
|
__forceinline s32 V_Core::RevbGetIndexer( s32 offset )
|
||||||
{
|
{
|
||||||
u32 pos = thiscore.ReverbX + offset;
|
u32 pos = ReverbX + offset;
|
||||||
|
|
||||||
// Need to use modulus here, because games can and will drop the buffer size
|
// Need to use modulus here, because games can and will drop the buffer size
|
||||||
// without notice, and it leads to offsets several times past the end of the buffer.
|
// without notice, and it leads to offsets several times past the end of the buffer.
|
||||||
|
|
||||||
if( pos > thiscore.EffectsEndA )
|
if( pos > EffectsEndA )
|
||||||
{
|
{
|
||||||
//pos = thiscore.EffectsStartA + ((thiscore.ReverbX + offset) % (u32)thiscore.EffectsBufferSize);
|
//pos = EffectsStartA + ((ReverbX + offset) % (u32)EffectsBufferSize);
|
||||||
pos -= thiscore.EffectsEndA+1;
|
pos -= EffectsEndA+1;
|
||||||
pos += thiscore.EffectsStartA;
|
pos += EffectsStartA;
|
||||||
}
|
}
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reverb_AdvanceBuffer( V_Core& thiscore )
|
void V_Core::Reverb_AdvanceBuffer()
|
||||||
{
|
{
|
||||||
if( (Cycles & 1) && (thiscore.EffectsBufferSize > 0) )
|
if( (Cycles & 1) && (EffectsBufferSize > 0) )
|
||||||
{
|
{
|
||||||
//thiscore.ReverbX = RevbGetIndexer( thiscore, 1 );
|
//ReverbX = RevbGetIndexer( thiscore, 1 );
|
||||||
thiscore.ReverbX += 1;
|
ReverbX += 1;
|
||||||
|
|
||||||
if( thiscore.ReverbX >= (u32)thiscore.EffectsBufferSize ) thiscore.ReverbX = 0;
|
if( ReverbX >= (u32)EffectsBufferSize ) ReverbX = 0;
|
||||||
|
|
||||||
//thiscore.ReverbX += 1;
|
//ReverbX += 1;
|
||||||
//if(thiscore.ReverbX >= (u32)thiscore.EffectsBufferSize )
|
//if(ReverbX >= (u32)EffectsBufferSize )
|
||||||
// thiscore.ReverbX %= (u32)thiscore.EffectsBufferSize;
|
// ReverbX %= (u32)EffectsBufferSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input )
|
StereoOut32 V_Core::DoReverb( const StereoOut32& Input )
|
||||||
{
|
{
|
||||||
// Reverb processing occurs at 24khz, so we skip processing every other sample,
|
// Reverb processing occurs at 24khz, so we skip processing every other sample,
|
||||||
// and use the previous calculation for this core instead.
|
// and use the previous calculation for this core instead.
|
||||||
|
|
||||||
if( (Cycles&1)==0 )
|
if( (Cycles&1)==0 )
|
||||||
{
|
{
|
||||||
StereoOut32 retval( thiscore.LastEffect );
|
StereoOut32 retval( LastEffect );
|
||||||
|
|
||||||
// Make sure and pass input through the LPF. The result can be discarded.
|
// Make sure and pass input through the LPF. The result can be discarded.
|
||||||
// This gives the LPF a better sampling from which to kill offending frequencies.
|
// This gives the LPF a better sampling from which to kill offending frequencies.
|
||||||
|
@ -68,15 +72,15 @@ StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input )
|
||||||
lowpass_left.sample( Input.Left / 32768.0 );
|
lowpass_left.sample( Input.Left / 32768.0 );
|
||||||
lowpass_right.sample( Input.Right / 32768.0 );
|
lowpass_right.sample( Input.Right / 32768.0 );
|
||||||
|
|
||||||
//thiscore.LastEffect = Input;
|
//LastEffect = Input;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( thiscore.RevBuffers.NeedsUpdated )
|
if( RevBuffers.NeedsUpdated )
|
||||||
thiscore.UpdateEffectsBufferSize();
|
UpdateEffectsBufferSize();
|
||||||
|
|
||||||
if( thiscore.EffectsBufferSize <= 0 )
|
if( EffectsBufferSize <= 0 )
|
||||||
{
|
{
|
||||||
// StartA is past EndA, so effects are disabled.
|
// StartA is past EndA, so effects are disabled.
|
||||||
//ConLog( " * SPU2: Effects disabled due to leapfrogged EffectsStart." );
|
//ConLog( " * SPU2: Effects disabled due to leapfrogged EffectsStart." );
|
||||||
|
@ -91,54 +95,54 @@ StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input )
|
||||||
// Advance the current reverb buffer pointer, and cache the read/write addresses we'll be
|
// Advance the current reverb buffer pointer, and cache the read/write addresses we'll be
|
||||||
// needing for this session of reverb.
|
// needing for this session of reverb.
|
||||||
|
|
||||||
const u32 src_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_SRC_A0 );
|
const u32 src_a0 = RevbGetIndexer( RevBuffers.IIR_SRC_A0 );
|
||||||
const u32 src_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_SRC_A1 );
|
const u32 src_a1 = RevbGetIndexer( RevBuffers.IIR_SRC_A1 );
|
||||||
const u32 src_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_SRC_B0 );
|
const u32 src_b0 = RevbGetIndexer( RevBuffers.IIR_SRC_B0 );
|
||||||
const u32 src_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_SRC_B1 );
|
const u32 src_b1 = RevbGetIndexer( RevBuffers.IIR_SRC_B1 );
|
||||||
|
|
||||||
const u32 dest_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_A0 );
|
const u32 dest_a0 = RevbGetIndexer( RevBuffers.IIR_DEST_A0 );
|
||||||
const u32 dest_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_A1 );
|
const u32 dest_a1 = RevbGetIndexer( RevBuffers.IIR_DEST_A1 );
|
||||||
const u32 dest_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_B0 );
|
const u32 dest_b0 = RevbGetIndexer( RevBuffers.IIR_DEST_B0 );
|
||||||
const u32 dest_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_B1 );
|
const u32 dest_b1 = RevbGetIndexer( RevBuffers.IIR_DEST_B1 );
|
||||||
|
|
||||||
const u32 dest2_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_A0 + 1 );
|
const u32 dest2_a0 = RevbGetIndexer( RevBuffers.IIR_DEST_A0 + 1 );
|
||||||
const u32 dest2_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_A1 + 1 );
|
const u32 dest2_a1 = RevbGetIndexer( RevBuffers.IIR_DEST_A1 + 1 );
|
||||||
const u32 dest2_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_B0 + 1 );
|
const u32 dest2_b0 = RevbGetIndexer( RevBuffers.IIR_DEST_B0 + 1 );
|
||||||
const u32 dest2_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.IIR_DEST_B1 + 1 );
|
const u32 dest2_b1 = RevbGetIndexer( RevBuffers.IIR_DEST_B1 + 1 );
|
||||||
|
|
||||||
const u32 acc_src_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_A0 );
|
const u32 acc_src_a0 = RevbGetIndexer( RevBuffers.ACC_SRC_A0 );
|
||||||
const u32 acc_src_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_B0 );
|
const u32 acc_src_b0 = RevbGetIndexer( RevBuffers.ACC_SRC_B0 );
|
||||||
const u32 acc_src_c0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_C0 );
|
const u32 acc_src_c0 = RevbGetIndexer( RevBuffers.ACC_SRC_C0 );
|
||||||
const u32 acc_src_d0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_D0 );
|
const u32 acc_src_d0 = RevbGetIndexer( RevBuffers.ACC_SRC_D0 );
|
||||||
|
|
||||||
const u32 acc_src_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_A1 );
|
const u32 acc_src_a1 = RevbGetIndexer( RevBuffers.ACC_SRC_A1 );
|
||||||
const u32 acc_src_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_B1 );
|
const u32 acc_src_b1 = RevbGetIndexer( RevBuffers.ACC_SRC_B1 );
|
||||||
const u32 acc_src_c1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_C1 );
|
const u32 acc_src_c1 = RevbGetIndexer( RevBuffers.ACC_SRC_C1 );
|
||||||
const u32 acc_src_d1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.ACC_SRC_D1 );
|
const u32 acc_src_d1 = RevbGetIndexer( RevBuffers.ACC_SRC_D1 );
|
||||||
|
|
||||||
const u32 fb_src_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.FB_SRC_A0 );
|
const u32 fb_src_a0 = RevbGetIndexer( RevBuffers.FB_SRC_A0 );
|
||||||
const u32 fb_src_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.FB_SRC_A1 );
|
const u32 fb_src_a1 = RevbGetIndexer( RevBuffers.FB_SRC_A1 );
|
||||||
const u32 fb_src_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.FB_SRC_B0 );
|
const u32 fb_src_b0 = RevbGetIndexer( RevBuffers.FB_SRC_B0 );
|
||||||
const u32 fb_src_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.FB_SRC_B1 );
|
const u32 fb_src_b1 = RevbGetIndexer( RevBuffers.FB_SRC_B1 );
|
||||||
|
|
||||||
const u32 mix_dest_a0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.MIX_DEST_A0 );
|
const u32 mix_dest_a0 = RevbGetIndexer( RevBuffers.MIX_DEST_A0 );
|
||||||
const u32 mix_dest_a1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.MIX_DEST_A1 );
|
const u32 mix_dest_a1 = RevbGetIndexer( RevBuffers.MIX_DEST_A1 );
|
||||||
const u32 mix_dest_b0 = RevbGetIndexer( thiscore, thiscore.RevBuffers.MIX_DEST_B0 );
|
const u32 mix_dest_b0 = RevbGetIndexer( RevBuffers.MIX_DEST_B0 );
|
||||||
const u32 mix_dest_b1 = RevbGetIndexer( thiscore, thiscore.RevBuffers.MIX_DEST_B1 );
|
const u32 mix_dest_b1 = RevbGetIndexer( RevBuffers.MIX_DEST_B1 );
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
// End Buffer Pointers, Begin Reverb!
|
// End Buffer Pointers, Begin Reverb!
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
//StereoOut32 INPUT_SAMPLE( thiscore.LastEffect + Input );
|
//StereoOut32 INPUT_SAMPLE( LastEffect + Input );
|
||||||
|
|
||||||
// Note: LowPass on the input! Very important. Some games like DDS get terrible feedback otherwise.
|
// Note: LowPass on the input! Very important. Some games like DDS get terrible feedback otherwise.
|
||||||
// Decisions, Decisions! Should we mix in the 22khz sample skipped, or not?
|
// Decisions, Decisions! Should we mix in the 22khz sample skipped, or not?
|
||||||
// First one mixes in the 22hkz sample. Second one does not.
|
// First one mixes in the 22hkz sample. Second one does not.
|
||||||
|
|
||||||
/*StereoOut32 INPUT_SAMPLE(
|
/*StereoOut32 INPUT_SAMPLE(
|
||||||
(s32)(lowpass_left.sample( (Input.Left+thiscore.LastEffect.Left) / 32768.0 ) * 32768.0),
|
(s32)(lowpass_left.sample( (Input.Left+LastEffect.Left) / 32768.0 ) * 32768.0),
|
||||||
(s32)(lowpass_right.sample( (Input.Right+thiscore.LastEffect.Right) / 32768.0 ) * 32768.0)
|
(s32)(lowpass_right.sample( (Input.Right+LastEffect.Right) / 32768.0 ) * 32768.0)
|
||||||
);*/
|
);*/
|
||||||
|
|
||||||
StereoOut32 INPUT_SAMPLE(
|
StereoOut32 INPUT_SAMPLE(
|
||||||
|
@ -146,15 +150,15 @@ StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input )
|
||||||
(s32)(lowpass_right.sample( Input.Right / 32768.0 ) * 32768.0)
|
(s32)(lowpass_right.sample( Input.Right / 32768.0 ) * 32768.0)
|
||||||
);
|
);
|
||||||
|
|
||||||
const s32 IIR_INPUT_A0 = ((_spu2mem[src_a0] * thiscore.Revb.IIR_COEF) + (INPUT_SAMPLE.Left * thiscore.Revb.IN_COEF_L))>>16;
|
const s32 IIR_INPUT_A0 = ((_spu2mem[src_a0] * Revb.IIR_COEF) + (INPUT_SAMPLE.Left * Revb.IN_COEF_L))>>16;
|
||||||
const s32 IIR_INPUT_A1 = ((_spu2mem[src_a1] * thiscore.Revb.IIR_COEF) + (INPUT_SAMPLE.Right * thiscore.Revb.IN_COEF_R))>>16;
|
const s32 IIR_INPUT_A1 = ((_spu2mem[src_a1] * Revb.IIR_COEF) + (INPUT_SAMPLE.Right * Revb.IN_COEF_R))>>16;
|
||||||
const s32 IIR_INPUT_B0 = ((_spu2mem[src_b0] * thiscore.Revb.IIR_COEF) + (INPUT_SAMPLE.Left * thiscore.Revb.IN_COEF_L))>>16;
|
const s32 IIR_INPUT_B0 = ((_spu2mem[src_b0] * Revb.IIR_COEF) + (INPUT_SAMPLE.Left * Revb.IN_COEF_L))>>16;
|
||||||
const s32 IIR_INPUT_B1 = ((_spu2mem[src_b1] * thiscore.Revb.IIR_COEF) + (INPUT_SAMPLE.Right * thiscore.Revb.IN_COEF_R))>>16;
|
const s32 IIR_INPUT_B1 = ((_spu2mem[src_b1] * Revb.IIR_COEF) + (INPUT_SAMPLE.Right * Revb.IN_COEF_R))>>16;
|
||||||
|
|
||||||
const s32 IIR_A0 = (IIR_INPUT_A0 * thiscore.Revb.IIR_ALPHA) + (_spu2mem[dest_a0] * (0x7fff - thiscore.Revb.IIR_ALPHA));
|
const s32 IIR_A0 = (IIR_INPUT_A0 * Revb.IIR_ALPHA) + (_spu2mem[dest_a0] * (0x7fff - Revb.IIR_ALPHA));
|
||||||
const s32 IIR_A1 = (IIR_INPUT_A1 * thiscore.Revb.IIR_ALPHA) + (_spu2mem[dest_a1] * (0x7fff - thiscore.Revb.IIR_ALPHA));
|
const s32 IIR_A1 = (IIR_INPUT_A1 * Revb.IIR_ALPHA) + (_spu2mem[dest_a1] * (0x7fff - Revb.IIR_ALPHA));
|
||||||
const s32 IIR_B0 = (IIR_INPUT_B0 * thiscore.Revb.IIR_ALPHA) + (_spu2mem[dest_b0] * (0x7fff - thiscore.Revb.IIR_ALPHA));
|
const s32 IIR_B0 = (IIR_INPUT_B0 * Revb.IIR_ALPHA) + (_spu2mem[dest_b0] * (0x7fff - Revb.IIR_ALPHA));
|
||||||
const s32 IIR_B1 = (IIR_INPUT_B1 * thiscore.Revb.IIR_ALPHA) + (_spu2mem[dest_b1] * (0x7fff - thiscore.Revb.IIR_ALPHA));
|
const s32 IIR_B1 = (IIR_INPUT_B1 * Revb.IIR_ALPHA) + (_spu2mem[dest_b1] * (0x7fff - Revb.IIR_ALPHA));
|
||||||
_spu2mem[dest2_a0] = clamp_mix( IIR_A0 >> 16 );
|
_spu2mem[dest2_a0] = clamp_mix( IIR_A0 >> 16 );
|
||||||
_spu2mem[dest2_a1] = clamp_mix( IIR_A1 >> 16 );
|
_spu2mem[dest2_a1] = clamp_mix( IIR_A1 >> 16 );
|
||||||
_spu2mem[dest2_b0] = clamp_mix( IIR_B0 >> 16 );
|
_spu2mem[dest2_b0] = clamp_mix( IIR_B0 >> 16 );
|
||||||
|
@ -162,10 +166,10 @@ StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input )
|
||||||
|
|
||||||
// Faster single-mul approach to interpolation:
|
// Faster single-mul approach to interpolation:
|
||||||
// (doesn't work yet -- breaks Digital Devil Saga badly)
|
// (doesn't work yet -- breaks Digital Devil Saga badly)
|
||||||
/*const s32 IIR_A0 = IIR_INPUT_A0 + (((_spu2mem[dest_a0]-IIR_INPUT_A0) * thiscore.Revb.IIR_ALPHA)>>16);
|
/*const s32 IIR_A0 = IIR_INPUT_A0 + (((_spu2mem[dest_a0]-IIR_INPUT_A0) * Revb.IIR_ALPHA)>>16);
|
||||||
const s32 IIR_A1 = IIR_INPUT_A1 + (((_spu2mem[dest_a1]-IIR_INPUT_A1) * thiscore.Revb.IIR_ALPHA)>>16);
|
const s32 IIR_A1 = IIR_INPUT_A1 + (((_spu2mem[dest_a1]-IIR_INPUT_A1) * Revb.IIR_ALPHA)>>16);
|
||||||
const s32 IIR_B0 = IIR_INPUT_B0 + (((_spu2mem[dest_b0]-IIR_INPUT_B0) * thiscore.Revb.IIR_ALPHA)>>16);
|
const s32 IIR_B0 = IIR_INPUT_B0 + (((_spu2mem[dest_b0]-IIR_INPUT_B0) * Revb.IIR_ALPHA)>>16);
|
||||||
const s32 IIR_B1 = IIR_INPUT_B1 + (((_spu2mem[dest_b1]-IIR_INPUT_B1) * thiscore.Revb.IIR_ALPHA)>>16);
|
const s32 IIR_B1 = IIR_INPUT_B1 + (((_spu2mem[dest_b1]-IIR_INPUT_B1) * Revb.IIR_ALPHA)>>16);
|
||||||
|
|
||||||
_spu2mem[dest2_a0] = clamp_mix( IIR_A0 );
|
_spu2mem[dest2_a0] = clamp_mix( IIR_A0 );
|
||||||
_spu2mem[dest2_a1] = clamp_mix( IIR_A1 );
|
_spu2mem[dest2_a1] = clamp_mix( IIR_A1 );
|
||||||
|
@ -173,36 +177,36 @@ StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input )
|
||||||
_spu2mem[dest2_b1] = clamp_mix( IIR_B1 );*/
|
_spu2mem[dest2_b1] = clamp_mix( IIR_B1 );*/
|
||||||
|
|
||||||
const s32 ACC0 =
|
const s32 ACC0 =
|
||||||
((_spu2mem[acc_src_a0] * thiscore.Revb.ACC_COEF_A)) +
|
((_spu2mem[acc_src_a0] * Revb.ACC_COEF_A)) +
|
||||||
((_spu2mem[acc_src_b0] * thiscore.Revb.ACC_COEF_B)) +
|
((_spu2mem[acc_src_b0] * Revb.ACC_COEF_B)) +
|
||||||
((_spu2mem[acc_src_c0] * thiscore.Revb.ACC_COEF_C)) +
|
((_spu2mem[acc_src_c0] * Revb.ACC_COEF_C)) +
|
||||||
((_spu2mem[acc_src_d0] * thiscore.Revb.ACC_COEF_D));
|
((_spu2mem[acc_src_d0] * Revb.ACC_COEF_D));
|
||||||
|
|
||||||
const s32 ACC1 =
|
const s32 ACC1 =
|
||||||
((_spu2mem[acc_src_a1] * thiscore.Revb.ACC_COEF_A)) +
|
((_spu2mem[acc_src_a1] * Revb.ACC_COEF_A)) +
|
||||||
((_spu2mem[acc_src_b1] * thiscore.Revb.ACC_COEF_B)) +
|
((_spu2mem[acc_src_b1] * Revb.ACC_COEF_B)) +
|
||||||
((_spu2mem[acc_src_c1] * thiscore.Revb.ACC_COEF_C)) +
|
((_spu2mem[acc_src_c1] * Revb.ACC_COEF_C)) +
|
||||||
((_spu2mem[acc_src_d1] * thiscore.Revb.ACC_COEF_D));
|
((_spu2mem[acc_src_d1] * Revb.ACC_COEF_D));
|
||||||
|
|
||||||
const s32 FB_A0 = (_spu2mem[fb_src_a0] * thiscore.Revb.FB_ALPHA);
|
const s32 FB_A0 = (_spu2mem[fb_src_a0] * Revb.FB_ALPHA);
|
||||||
const s32 FB_A1 = (_spu2mem[fb_src_a1] * thiscore.Revb.FB_ALPHA);
|
const s32 FB_A1 = (_spu2mem[fb_src_a1] * Revb.FB_ALPHA);
|
||||||
|
|
||||||
const s32 fb_xor_a0 = _spu2mem[fb_src_a0] * ( thiscore.Revb.FB_ALPHA ^ 0x8000 );
|
const s32 fb_xor_a0 = _spu2mem[fb_src_a0] * ( Revb.FB_ALPHA ^ 0x8000 );
|
||||||
const s32 fb_xor_a1 = _spu2mem[fb_src_a1] * ( thiscore.Revb.FB_ALPHA ^ 0x8000 );
|
const s32 fb_xor_a1 = _spu2mem[fb_src_a1] * ( Revb.FB_ALPHA ^ 0x8000 );
|
||||||
|
|
||||||
_spu2mem[mix_dest_a0] = clamp_mix( (ACC0 - FB_A0) >> 16 );
|
_spu2mem[mix_dest_a0] = clamp_mix( (ACC0 - FB_A0) >> 16 );
|
||||||
_spu2mem[mix_dest_a1] = clamp_mix( (ACC1 - FB_A1) >> 16 );
|
_spu2mem[mix_dest_a1] = clamp_mix( (ACC1 - FB_A1) >> 16 );
|
||||||
_spu2mem[mix_dest_b0] = clamp_mix( (MulShr32(thiscore.Revb.FB_ALPHA<<16, ACC0) - fb_xor_a0 - (_spu2mem[fb_src_b0] * thiscore.Revb.FB_X)) >> 16 );
|
_spu2mem[mix_dest_b0] = clamp_mix( (MulShr32(Revb.FB_ALPHA<<16, ACC0) - fb_xor_a0 - (_spu2mem[fb_src_b0] * Revb.FB_X)) >> 16 );
|
||||||
_spu2mem[mix_dest_b1] = clamp_mix( (MulShr32(thiscore.Revb.FB_ALPHA<<16, ACC1) - fb_xor_a1 - (_spu2mem[fb_src_b1] * thiscore.Revb.FB_X)) >> 16 );
|
_spu2mem[mix_dest_b1] = clamp_mix( (MulShr32(Revb.FB_ALPHA<<16, ACC1) - fb_xor_a1 - (_spu2mem[fb_src_b1] * Revb.FB_X)) >> 16 );
|
||||||
|
|
||||||
thiscore.LastEffect.Left = _spu2mem[mix_dest_a0] + _spu2mem[mix_dest_b0];
|
LastEffect.Left = _spu2mem[mix_dest_a0] + _spu2mem[mix_dest_b0];
|
||||||
thiscore.LastEffect.Right = _spu2mem[mix_dest_a1] + _spu2mem[mix_dest_b1];
|
LastEffect.Right = _spu2mem[mix_dest_a1] + _spu2mem[mix_dest_b1];
|
||||||
|
|
||||||
clamp_mix( thiscore.LastEffect );
|
clamp_mix( LastEffect );
|
||||||
|
|
||||||
//thiscore.LastEffect.Left = (s32)(lowpass_left.sample( thiscore.LastEffect.Left / 32768.0 ) * 32768.0);
|
//LastEffect.Left = (s32)(lowpass_left.sample( LastEffect.Left / 32768.0 ) * 32768.0);
|
||||||
//thiscore.LastEffect.Right = (s32)(lowpass_right.sample( thiscore.LastEffect.Right / 32768.0 ) * 32768.0);
|
//LastEffect.Right = (s32)(lowpass_right.sample( LastEffect.Right / 32768.0 ) * 32768.0);
|
||||||
|
|
||||||
return thiscore.LastEffect;
|
return LastEffect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -15,7 +15,7 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Spu2.h"
|
#include "Global.h"
|
||||||
|
|
||||||
|
|
||||||
StereoOut32 StereoOut32::Empty( 0, 0 );
|
StereoOut32 StereoOut32::Empty( 0, 0 );
|
||||||
|
@ -56,11 +56,7 @@ public:
|
||||||
s32 Init() { return 0; }
|
s32 Init() { return 0; }
|
||||||
void Close() { }
|
void Close() { }
|
||||||
s32 Test() const { return 0; }
|
s32 Test() const { return 0; }
|
||||||
#ifdef _MSC_VER
|
|
||||||
void Configure(HWND parent) { }
|
|
||||||
#else
|
|
||||||
void Configure(uptr parent) { }
|
void Configure(uptr parent) { }
|
||||||
#endif
|
|
||||||
bool Is51Out() const { return false; }
|
bool Is51Out() const { return false; }
|
||||||
int GetEmptySampleCount() const { return 0; }
|
int GetEmptySampleCount() const { return 0; }
|
||||||
|
|
||||||
|
@ -290,9 +286,9 @@ void SndBuffer::Cleanup()
|
||||||
{
|
{
|
||||||
mods[OutputModule]->Close();
|
mods[OutputModule]->Close();
|
||||||
|
|
||||||
SAFE_DELETE_ARRAY( m_buffer );
|
safe_delete_array( m_buffer );
|
||||||
SAFE_DELETE_ARRAY( sndTempBuffer );
|
safe_delete_array( sndTempBuffer );
|
||||||
SAFE_DELETE_ARRAY( sndTempBuffer16 );
|
safe_delete_array( sndTempBuffer16 );
|
||||||
}
|
}
|
||||||
|
|
||||||
int SndBuffer::m_dsp_progress = 0;
|
int SndBuffer::m_dsp_progress = 0;
|
||||||
|
@ -375,15 +371,3 @@ s32 SndBuffer::Test()
|
||||||
|
|
||||||
return mods[OutputModule]->Test();
|
return mods[OutputModule]->Test();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
void SndBuffer::Configure(HWND parent, u32 module )
|
|
||||||
#else
|
|
||||||
void SndBuffer::Configure(uptr parent, u32 module )
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if( mods[module] == NULL )
|
|
||||||
return;
|
|
||||||
|
|
||||||
mods[module]->Configure(parent);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,25 +1,21 @@
|
||||||
//GiGaHeRz's SPU2 Driver
|
/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
|
||||||
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
|
* Developed and maintained by the Pcsx2 Development Team.
|
||||||
//
|
*
|
||||||
//This library is free software; you can redistribute it and/or
|
* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
|
||||||
//modify it under the terms of the GNU Lesser General Public
|
*
|
||||||
//License as published by the Free Software Foundation; either
|
* SPU2-X is free software: you can redistribute it and/or modify it under the terms
|
||||||
//version 2.1 of the License, or (at your option) any later version.
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
//
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
//This library is distributed in the hope that it will be useful,
|
*
|
||||||
//but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* SPU2-X is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
//Lesser General Public License for more details.
|
* PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
//
|
*
|
||||||
//You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
//License along with this library; if not, write to the Free Software
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
*/
|
||||||
//
|
|
||||||
#ifndef SNDOUT_H_INCLUDE
|
|
||||||
#define SNDOUT_H_INCLUDE
|
|
||||||
|
|
||||||
#include "BaseTypes.h"
|
#pragma once
|
||||||
#include "Lowpass.h"
|
|
||||||
|
|
||||||
// Number of stereo samples per SndOut block.
|
// Number of stereo samples per SndOut block.
|
||||||
// All drivers must work in units of this size when communicating with
|
// All drivers must work in units of this size when communicating with
|
||||||
|
@ -35,7 +31,7 @@ static const int SndOutVolumeShift = 13;
|
||||||
// is too problematic. :)
|
// is too problematic. :)
|
||||||
static const int SampleRate = 48000;
|
static const int SampleRate = 48000;
|
||||||
|
|
||||||
int FindOutputModuleById( const wchar_t* omodid );
|
extern int FindOutputModuleById( const wchar_t* omodid );
|
||||||
|
|
||||||
struct StereoOut16
|
struct StereoOut16
|
||||||
{
|
{
|
||||||
|
@ -231,9 +227,9 @@ struct Stereo51Out16DplII
|
||||||
s32 Tfl=(RAccum)*255/(LAccum);
|
s32 Tfl=(RAccum)*255/(LAccum);
|
||||||
s32 Tfr=(LAccum)*255/(RAccum);
|
s32 Tfr=(LAccum)*255/(RAccum);
|
||||||
|
|
||||||
int gMax = max(Tfl,Tfr);
|
int gMax = std::max(Tfl,Tfr);
|
||||||
Tfl=Tfl*255/gMax;
|
Tfl = Tfl*255/gMax;
|
||||||
Tfr=Tfr*255/gMax;
|
Tfr = Tfr*255/gMax;
|
||||||
|
|
||||||
if(Tfl>255) Tfl=255;
|
if(Tfl>255) Tfl=255;
|
||||||
if(Tfr>255) Tfr=255;
|
if(Tfr>255) Tfr=255;
|
||||||
|
@ -393,12 +389,6 @@ public:
|
||||||
static s32 Test();
|
static s32 Test();
|
||||||
static void ClearContents();
|
static void ClearContents();
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
static void Configure(HWND parent, u32 module );
|
|
||||||
#else
|
|
||||||
static void Configure(uptr parent, u32 module );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Note: When using with 32 bit output buffers, the user of this function is responsible
|
// Note: When using with 32 bit output buffers, the user of this function is responsible
|
||||||
// for shifting the values to where they need to be manually. The fixed point depth of
|
// for shifting the values to where they need to be manually. The fixed point depth of
|
||||||
// the sample output is determined by the SndOutVolumeShift, which is the number of bits
|
// the sample output is determined by the SndOutVolumeShift, which is the number of bits
|
||||||
|
@ -474,11 +464,7 @@ public:
|
||||||
virtual s32 Test() const=0;
|
virtual s32 Test() const=0;
|
||||||
|
|
||||||
// Gui function: Used to open the configuration box for this driver.
|
// Gui function: Used to open the configuration box for this driver.
|
||||||
#ifdef _MSC_VER
|
|
||||||
virtual void Configure(HWND parent)=0;
|
|
||||||
#else
|
|
||||||
virtual void Configure(uptr parent)=0;
|
virtual void Configure(uptr parent)=0;
|
||||||
#endif
|
|
||||||
|
|
||||||
// Loads settings from the INI file for this driver
|
// Loads settings from the INI file for this driver
|
||||||
virtual void ReadSettings()=0;
|
virtual void ReadSettings()=0;
|
||||||
|
@ -503,4 +489,13 @@ extern SndOutModule* XAudio2Out;
|
||||||
|
|
||||||
extern SndOutModule* mods[];
|
extern SndOutModule* mods[];
|
||||||
|
|
||||||
#endif // SNDOUT_H_INCLUDE
|
// =====================================================================================================
|
||||||
|
|
||||||
|
extern void RecordStart();
|
||||||
|
extern void RecordStop();
|
||||||
|
extern void RecordWrite( const StereoOut16& sample );
|
||||||
|
|
||||||
|
extern s32 DspLoadLibrary(wchar_t *fileName, int modNum);
|
||||||
|
extern void DspCloseLibrary();
|
||||||
|
extern int DspProcess(s16 *buffer, int samples);
|
||||||
|
extern void DspUpdate(); // to let the Dsp process window messages
|
||||||
|
|
|
@ -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
|
|
|
@ -16,9 +16,8 @@
|
||||||
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "Global.h"
|
||||||
|
#include "PS2E-spu2.h"
|
||||||
#include "Spu2.h"
|
|
||||||
|
|
||||||
FILE* s2rfile;
|
FILE* s2rfile;
|
||||||
|
|
||||||
|
@ -115,6 +114,7 @@ void dummy7()
|
||||||
#define Cread(a,b,c,d) if(fread(a,b,c,d)<b) break;
|
#define Cread(a,b,c,d) if(fread(a,b,c,d)<b) break;
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
#include "Windows/Dialogs.h"
|
||||||
EXPORT_C_(void) s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow)
|
EXPORT_C_(void) s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow)
|
||||||
{
|
{
|
||||||
// load file
|
// load file
|
||||||
|
|
|
@ -26,11 +26,4 @@ void s2r_writedma4(u32 ticks,u16*data,u32 len);
|
||||||
void s2r_writedma7(u32 ticks,u16*data,u32 len);
|
void s2r_writedma7(u32 ticks,u16*data,u32 len);
|
||||||
void s2r_close();
|
void s2r_close();
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
// s2r playing
|
|
||||||
EXPORT_C_(void) s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow);
|
|
||||||
#else
|
|
||||||
#define s2r_replay 0&&
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern bool replay_mode;
|
extern bool replay_mode;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Spu2.h"
|
#include "Global.h"
|
||||||
#include "SoundTouch/SoundTouch.h"
|
#include "SoundTouch/SoundTouch.h"
|
||||||
#include "SoundTouch/WavFile.h"
|
#include "SoundTouch/WavFile.h"
|
||||||
|
|
||||||
|
@ -304,9 +304,7 @@ void SndBuffer::soundtouchInit()
|
||||||
pSoundTouch->setSetting( SETTING_USE_QUICKSEEK, 0 );
|
pSoundTouch->setSetting( SETTING_USE_QUICKSEEK, 0 );
|
||||||
pSoundTouch->setSetting( SETTING_USE_AA_FILTER, 0 );
|
pSoundTouch->setSetting( SETTING_USE_AA_FILTER, 0 );
|
||||||
|
|
||||||
pSoundTouch->setSetting( SETTING_SEQUENCE_MS, SoundtouchCfg::SequenceLenMS );
|
SoundtouchCfg::ApplySettings( *pSoundTouch );
|
||||||
pSoundTouch->setSetting( SETTING_SEEKWINDOW_MS, SoundtouchCfg::SeekWindowMS );
|
|
||||||
pSoundTouch->setSetting( SETTING_OVERLAP_MS, SoundtouchCfg::OverlapMS );
|
|
||||||
|
|
||||||
pSoundTouch->setTempo(1);
|
pSoundTouch->setTempo(1);
|
||||||
|
|
||||||
|
@ -340,5 +338,5 @@ void SndBuffer::soundtouchClearContents()
|
||||||
|
|
||||||
void SndBuffer::soundtouchCleanup()
|
void SndBuffer::soundtouchCleanup()
|
||||||
{
|
{
|
||||||
SAFE_DELETE_OBJ( pSoundTouch );
|
safe_delete( pSoundTouch );
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,7 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdexcept>
|
#include "Global.h"
|
||||||
#include <new>
|
|
||||||
|
|
||||||
#include "Spu2.h"
|
|
||||||
|
|
||||||
#include "SoundTouch/WavFile.h"
|
#include "SoundTouch/WavFile.h"
|
||||||
|
|
||||||
static WavOutFile* _new_WavOutFile( const char* destfile )
|
static WavOutFile* _new_WavOutFile( const char* destfile )
|
||||||
|
@ -52,7 +48,7 @@ namespace WaveDump
|
||||||
{
|
{
|
||||||
for( int srcidx=0; srcidx<CoreSrc_Count; srcidx++ )
|
for( int srcidx=0; srcidx<CoreSrc_Count; srcidx++ )
|
||||||
{
|
{
|
||||||
SAFE_DELETE_OBJ( m_CoreWav[cidx][srcidx] );
|
safe_delete( m_CoreWav[cidx][srcidx] );
|
||||||
|
|
||||||
sprintf( wavfilename, "logs\\spu2x-Core%d-%s.wav",
|
sprintf( wavfilename, "logs\\spu2x-Core%d-%s.wav",
|
||||||
cidx, m_tbl_CoreOutputTypeNames[ srcidx ] );
|
cidx, m_tbl_CoreOutputTypeNames[ srcidx ] );
|
||||||
|
@ -77,7 +73,7 @@ namespace WaveDump
|
||||||
{
|
{
|
||||||
for( int srcidx=0; srcidx<CoreSrc_Count; srcidx++ )
|
for( int srcidx=0; srcidx<CoreSrc_Count; srcidx++ )
|
||||||
{
|
{
|
||||||
SAFE_DELETE_OBJ( m_CoreWav[cidx][srcidx] );
|
safe_delete( m_CoreWav[cidx][srcidx] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +95,7 @@ WavOutFile* m_wavrecord = NULL;
|
||||||
|
|
||||||
void RecordStart()
|
void RecordStart()
|
||||||
{
|
{
|
||||||
SAFE_DELETE_OBJ( m_wavrecord );
|
safe_delete( m_wavrecord );
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -114,7 +110,7 @@ void RecordStart()
|
||||||
|
|
||||||
void RecordStop()
|
void RecordStop()
|
||||||
{
|
{
|
||||||
SAFE_DELETE_OBJ( m_wavrecord );
|
safe_delete( m_wavrecord );
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecordWrite( const StereoOut16& sample )
|
void RecordWrite( const StereoOut16& sample )
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
#include "Dialogs.h"
|
#include "Dialogs.h"
|
||||||
#include <CommCtrl.h>
|
|
||||||
|
|
||||||
#include "svnrev.h"
|
#include "svnrev.h"
|
||||||
#include "Hyperlinks.h"
|
#include "Hyperlinks.h"
|
||||||
|
|
|
@ -15,8 +15,22 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
#include "Dialogs.h"
|
#include "Dialogs.h"
|
||||||
|
|
||||||
|
void SysMessage(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list list;
|
||||||
|
char tmp[512];
|
||||||
|
wchar_t wtmp[512];
|
||||||
|
|
||||||
|
va_start(list,fmt);
|
||||||
|
sprintf_s(tmp,fmt,list);
|
||||||
|
va_end(list);
|
||||||
|
swprintf_s(wtmp, L"%S", tmp);
|
||||||
|
MessageBox(0, wtmp, L"SPU2-X System Message", 0);
|
||||||
|
}
|
||||||
|
|
||||||
//////
|
//////
|
||||||
|
|
||||||
const TCHAR CfgFile[] = L"inis\\SPU2-X.ini";
|
const TCHAR CfgFile[] = L"inis\\SPU2-X.ini";
|
||||||
|
|
|
@ -15,9 +15,10 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
#include "Dialogs.h"
|
#include "Dialogs.h"
|
||||||
|
|
||||||
#ifdef SPU2X_DEVBUILD
|
#ifdef PCSX2_DEVBUILD
|
||||||
static const int LATENCY_MAX = 3000;
|
static const int LATENCY_MAX = 3000;
|
||||||
#else
|
#else
|
||||||
static const int LATENCY_MAX = 750;
|
static const int LATENCY_MAX = 750;
|
||||||
|
@ -25,8 +26,6 @@ static const int LATENCY_MAX = 750;
|
||||||
|
|
||||||
static const int LATENCY_MIN = 40;
|
static const int LATENCY_MIN = 40;
|
||||||
|
|
||||||
int AutoDMAPlayRate[2] = {0,0};
|
|
||||||
|
|
||||||
// MIXING
|
// MIXING
|
||||||
int Interpolation = 1;
|
int Interpolation = 1;
|
||||||
/* values:
|
/* values:
|
||||||
|
@ -57,9 +56,6 @@ bool StereoExpansionEnabled = false;
|
||||||
|
|
||||||
void ReadSettings()
|
void ReadSettings()
|
||||||
{
|
{
|
||||||
AutoDMAPlayRate[0] = CfgReadInt(L"MIXING",L"AutoDMA_Play_Rate_0",0);
|
|
||||||
AutoDMAPlayRate[1] = CfgReadInt(L"MIXING",L"AutoDMA_Play_Rate_1",0);
|
|
||||||
|
|
||||||
Interpolation = CfgReadInt( L"MIXING",L"Interpolation", 1 );
|
Interpolation = CfgReadInt( L"MIXING",L"Interpolation", 1 );
|
||||||
|
|
||||||
timeStretchDisabled = CfgReadBool( L"OUTPUT", L"Disable_Timestretch", false );
|
timeStretchDisabled = CfgReadBool( L"OUTPUT", L"Disable_Timestretch", false );
|
||||||
|
@ -107,9 +103,6 @@ void WriteSettings()
|
||||||
{
|
{
|
||||||
CfgWriteInt(L"MIXING",L"Interpolation",Interpolation);
|
CfgWriteInt(L"MIXING",L"Interpolation",Interpolation);
|
||||||
|
|
||||||
CfgWriteInt(L"MIXING",L"AutoDMA_Play_Rate_0",AutoDMAPlayRate[0]);
|
|
||||||
CfgWriteInt(L"MIXING",L"AutoDMA_Play_Rate_1",AutoDMAPlayRate[1]);
|
|
||||||
|
|
||||||
CfgWriteBool(L"MIXING",L"Disable_Effects",EffectsDisabled);
|
CfgWriteBool(L"MIXING",L"Disable_Effects",EffectsDisabled);
|
||||||
|
|
||||||
CfgWriteStr(L"OUTPUT",L"Output_Module", mods[OutputModule]->GetIdent() );
|
CfgWriteStr(L"OUTPUT",L"Output_Module", mods[OutputModule]->GetIdent() );
|
||||||
|
@ -204,9 +197,11 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IDC_OUTCONF:
|
case IDC_OUTCONF:
|
||||||
SndBuffer::Configure( hWnd,
|
{
|
||||||
(int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0)
|
const int module = (int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0);
|
||||||
);
|
if( mods[module] == NULL ) break;
|
||||||
|
mods[module]->Configure((uptr)hWnd);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IDC_OPEN_CONFIG_DEBUG:
|
case IDC_OPEN_CONFIG_DEBUG:
|
||||||
|
|
|
@ -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();
|
|
|
@ -15,6 +15,7 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
#include "Dialogs.h"
|
#include "Dialogs.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,33 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
#include "Dialogs.h"
|
#include "Dialogs.h"
|
||||||
|
|
||||||
int SoundtouchCfg::SequenceLenMS = 63;
|
#include "SoundTouch/SoundTouch.h"
|
||||||
int SoundtouchCfg::SeekWindowMS = 16;
|
|
||||||
int SoundtouchCfg::OverlapMS = 7;
|
|
||||||
|
|
||||||
void SoundtouchCfg::ClampValues()
|
static int SequenceLenMS = 63;
|
||||||
|
static int SeekWindowMS = 16;
|
||||||
|
static int OverlapMS = 7;
|
||||||
|
|
||||||
|
// Timestretch Slider Bounds, Min/Max
|
||||||
|
static const int SequenceLen_Min = 30;
|
||||||
|
static const int SequenceLen_Max = 90;
|
||||||
|
|
||||||
|
static const int SeekWindow_Min = 10;
|
||||||
|
static const int SeekWindow_Max = 32;
|
||||||
|
|
||||||
|
static const int Overlap_Min = 3;
|
||||||
|
static const int Overlap_Max = 15;
|
||||||
|
|
||||||
|
void SoundtouchCfg::ApplySettings( soundtouch::SoundTouch& sndtouch )
|
||||||
|
{
|
||||||
|
sndtouch.setSetting( SETTING_SEQUENCE_MS, SequenceLenMS );
|
||||||
|
sndtouch.setSetting( SETTING_SEEKWINDOW_MS, SeekWindowMS );
|
||||||
|
sndtouch.setSetting( SETTING_OVERLAP_MS, OverlapMS );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ClampValues()
|
||||||
{
|
{
|
||||||
Clampify( SequenceLenMS, SequenceLen_Min, SequenceLen_Max );
|
Clampify( SequenceLenMS, SequenceLen_Min, SequenceLen_Max );
|
||||||
Clampify( SeekWindowMS, SeekWindow_Min, SeekWindow_Max );
|
Clampify( SeekWindowMS, SeekWindow_Min, SeekWindow_Max );
|
||||||
|
@ -101,7 +121,7 @@ void SoundtouchCfg::OpenDialog( HWND hWnd )
|
||||||
ret = DialogBox( hInstance, MAKEINTRESOURCE(IDD_CONFIG_SOUNDTOUCH), hWnd, (DLGPROC)DialogProc );
|
ret = DialogBox( hInstance, MAKEINTRESOURCE(IDD_CONFIG_SOUNDTOUCH), hWnd, (DLGPROC)DialogProc );
|
||||||
if(ret==-1)
|
if(ret==-1)
|
||||||
{
|
{
|
||||||
MessageBoxEx(GetActiveWindow(),L"Error Opening the Soundtouch advanced dialog.",L"OMG ERROR!",MB_OK,0);
|
MessageBoxEx(GetActiveWindow(), L"Error Opening the Soundtouch advanced dialog.", L"OMG ERROR!", MB_OK, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ReadSettings();
|
ReadSettings();
|
||||||
|
|
|
@ -17,30 +17,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef _DIALOGS_H_
|
#ifdef _WIN32
|
||||||
#define _DIALOGS_H_
|
# include "WinConfig.h"
|
||||||
|
#else
|
||||||
#include "../Spu2.h"
|
# include "LnxConfig.h"
|
||||||
|
#endif
|
||||||
#include <commctrl.h>
|
|
||||||
#include <initguid.h>
|
|
||||||
|
|
||||||
extern HINSTANCE hInstance;
|
|
||||||
|
|
||||||
#define SET_CHECK(idc,value) SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,((value)==0)?BST_UNCHECKED:BST_CHECKED,0)
|
|
||||||
#define HANDLE_CHECK(idc,hvar) case idc: (hvar) = !(hvar); SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,(hvar)?BST_CHECKED:BST_UNCHECKED,0); break
|
|
||||||
#define HANDLE_CHECKNB(idc,hvar)case idc: (hvar) = !(hvar); SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,(hvar)?BST_CHECKED:BST_UNCHECKED,0)
|
|
||||||
#define ENABLE_CONTROL(idc,value) EnableWindow(GetDlgItem(hWnd,idc),value)
|
|
||||||
|
|
||||||
#define INIT_SLIDER(idc,minrange,maxrange,tickfreq,pagesize,linesize) \
|
|
||||||
SendMessage(GetDlgItem(hWnd,idc),TBM_SETRANGEMIN,FALSE,minrange); \
|
|
||||||
SendMessage(GetDlgItem(hWnd,idc),TBM_SETRANGEMAX,FALSE,maxrange); \
|
|
||||||
SendMessage(GetDlgItem(hWnd,idc),TBM_SETTICFREQ,tickfreq,0); \
|
|
||||||
SendMessage(GetDlgItem(hWnd,idc),TBM_SETPAGESIZE,0,pagesize); \
|
|
||||||
SendMessage(GetDlgItem(hWnd,idc),TBM_SETLINESIZE,0,linesize)
|
|
||||||
|
|
||||||
#define HANDLE_SCROLL_MESSAGE(idc,idcDisplay) \
|
|
||||||
if((HWND)lParam == GetDlgItem(hWnd,idc)) return DoHandleScrollMessage( GetDlgItem(hWnd,idcDisplay), wParam, lParam )
|
|
||||||
|
|
||||||
namespace DebugConfig
|
namespace DebugConfig
|
||||||
{
|
{
|
||||||
|
@ -50,24 +31,32 @@ namespace DebugConfig
|
||||||
extern void EnableControls( HWND hWnd );
|
extern void EnableControls( HWND hWnd );
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int SendDialogMsg( HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam);
|
namespace SoundtouchCfg
|
||||||
extern HRESULT GUIDFromString( const char *str, LPGUID guid );
|
{
|
||||||
|
extern void ReadSettings();
|
||||||
|
extern void WriteSettings();
|
||||||
|
extern void OpenDialog( HWND hWnd );
|
||||||
|
extern BOOL CALLBACK DialogProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
|
||||||
|
}
|
||||||
|
|
||||||
extern void AssignSliderValue( HWND idcwnd, HWND hwndDisplay, int value );
|
extern int SendDialogMsg( HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam);
|
||||||
extern void AssignSliderValue( HWND hWnd, int idc, int editbox, int value );
|
extern HRESULT GUIDFromString( const char *str, LPGUID guid );
|
||||||
extern int GetSliderValue( HWND hWnd, int idc );
|
|
||||||
extern BOOL DoHandleScrollMessage( HWND hwndDisplay, WPARAM wParam, LPARAM lParam );
|
|
||||||
|
|
||||||
bool CfgFindName( const TCHAR *Section, const TCHAR* Name);
|
extern void AssignSliderValue( HWND idcwnd, HWND hwndDisplay, int value );
|
||||||
|
extern void AssignSliderValue( HWND hWnd, int idc, int editbox, int value );
|
||||||
|
extern int GetSliderValue( HWND hWnd, int idc );
|
||||||
|
extern BOOL DoHandleScrollMessage( HWND hwndDisplay, WPARAM wParam, LPARAM lParam );
|
||||||
|
|
||||||
void CfgWriteBool(const TCHAR* Section, const TCHAR* Name, bool Value);
|
extern bool CfgFindName( const TCHAR *Section, const TCHAR* Name);
|
||||||
void CfgWriteInt(const TCHAR* Section, const TCHAR* Name, int Value);
|
|
||||||
void CfgWriteStr(const TCHAR* Section, const TCHAR* Name, const wstring& Data);
|
|
||||||
|
|
||||||
bool CfgReadBool(const TCHAR *Section,const TCHAR* Name, bool Default);
|
extern void CfgWriteBool(const TCHAR* Section, const TCHAR* Name, bool Value);
|
||||||
void CfgReadStr(const TCHAR* Section, const TCHAR* Name, wstring& Data, int DataSize, const TCHAR* Default);
|
extern void CfgWriteInt(const TCHAR* Section, const TCHAR* Name, int Value);
|
||||||
void CfgReadStr(const TCHAR* Section, const TCHAR* Name, TCHAR* Data, int DataSize, const TCHAR* Default);
|
extern void CfgWriteStr(const TCHAR* Section, const TCHAR* Name, const wstring& Data);
|
||||||
int CfgReadInt(const TCHAR* Section, const TCHAR* Name,int Default);
|
|
||||||
|
extern bool CfgReadBool(const TCHAR *Section,const TCHAR* Name, bool Default);
|
||||||
|
extern void CfgReadStr(const TCHAR* Section, const TCHAR* Name, wstring& Data, int DataSize, const TCHAR* Default);
|
||||||
|
extern void CfgReadStr(const TCHAR* Section, const TCHAR* Name, TCHAR* Data, int DataSize, const TCHAR* Default);
|
||||||
|
extern int CfgReadInt(const TCHAR* Section, const TCHAR* Name,int Default);
|
||||||
|
|
||||||
|
|
||||||
// Items Specific to DirectSound
|
// Items Specific to DirectSound
|
||||||
|
@ -83,4 +72,3 @@ struct ds_device_data
|
||||||
bool hasGuid;
|
bool hasGuid;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
#include "Dialogs.h"
|
#include "Dialogs.h"
|
||||||
#include "../RegTable.h"
|
#include "../RegTable.h"
|
||||||
|
|
||||||
|
@ -59,7 +60,7 @@ static BOOL CALLBACK DebugProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SPU2X_DEVBUILD
|
#ifdef PCSX2_DEVBUILD
|
||||||
|
|
||||||
int FillRectangle(HDC dc, int left, int top, int width, int height)
|
int FillRectangle(HDC dc, int left, int top, int width, int height)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
|
|
||||||
#define _WIN32_DCOM
|
#define _WIN32_DCOM
|
||||||
#include "Dialogs.h"
|
#include "Dialogs.h"
|
||||||
|
|
||||||
|
@ -103,6 +105,8 @@ private:
|
||||||
public:
|
public:
|
||||||
s32 Init()
|
s32 Init()
|
||||||
{
|
{
|
||||||
|
CoInitializeEx( NULL, COINIT_MULTITHREADED );
|
||||||
|
|
||||||
//
|
//
|
||||||
// Initialize DSound
|
// Initialize DSound
|
||||||
//
|
//
|
||||||
|
@ -180,7 +184,7 @@ public:
|
||||||
|
|
||||||
throw std::runtime_error( "DirectSound Error: Buffer could not be created." );
|
throw std::runtime_error( "DirectSound Error: Buffer could not be created." );
|
||||||
}
|
}
|
||||||
if( FAILED(buffer_->QueryInterface(IID_IDirectSoundBuffer8,(void**)&buffer)) )
|
if( FAILED(buffer_->QueryInterface(IID_IDirectSoundBuffer8,(void**)&buffer)) || buffer == NULL )
|
||||||
throw std::runtime_error( "DirectSound Error: Interface could not be queried." );
|
throw std::runtime_error( "DirectSound Error: Interface could not be queried." );
|
||||||
|
|
||||||
buffer_->Release();
|
buffer_->Release();
|
||||||
|
@ -242,11 +246,12 @@ public:
|
||||||
buffer_events[i] = NULL;
|
buffer_events[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SAFE_RELEASE( buffer_notify );
|
safe_release( buffer_notify );
|
||||||
SAFE_RELEASE( buffer );
|
safe_release( buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
SAFE_RELEASE( dsound );
|
safe_release( dsound );
|
||||||
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -406,13 +411,13 @@ private:
|
||||||
static BOOL CALLBACK DSEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext );
|
static BOOL CALLBACK DSEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void Configure(HWND parent)
|
virtual void Configure(uptr parent)
|
||||||
{
|
{
|
||||||
INT_PTR ret;
|
INT_PTR ret;
|
||||||
ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DSOUND),GetActiveWindow(),(DLGPROC)ConfigProc,1);
|
ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DSOUND),(HWND)parent,(DLGPROC)ConfigProc,1);
|
||||||
if(ret==-1)
|
if(ret==-1)
|
||||||
{
|
{
|
||||||
MessageBoxEx(GetActiveWindow(),L"Error Opening the config dialog.",L"OMG ERROR!",MB_OK,0);
|
MessageBoxEx((HWND)parent,L"Error Opening the config dialog.",L"OMG ERROR!",MB_OK,0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,13 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
|
|
||||||
#define _WIN32_DCOM
|
#define _WIN32_DCOM
|
||||||
|
|
||||||
#include "Dialogs.h"
|
#include "Dialogs.h"
|
||||||
#include <xaudio2.h>
|
|
||||||
|
|
||||||
|
#include <atlbase.h>
|
||||||
|
#include <xaudio2.h>
|
||||||
|
|
||||||
namespace Exception
|
namespace Exception
|
||||||
{
|
{
|
||||||
|
@ -181,7 +183,7 @@ private:
|
||||||
killMe->FlushSourceBuffers();
|
killMe->FlushSourceBuffers();
|
||||||
EnterCriticalSection( &cs );
|
EnterCriticalSection( &cs );
|
||||||
killMe->DestroyVoice();
|
killMe->DestroyVoice();
|
||||||
SAFE_DELETE_ARRAY( qbuffer );
|
safe_delete_array( qbuffer );
|
||||||
LeaveCriticalSection( &cs );
|
LeaveCriticalSection( &cs );
|
||||||
DeleteCriticalSection( &cs );
|
DeleteCriticalSection( &cs );
|
||||||
}
|
}
|
||||||
|
@ -225,7 +227,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
IXAudio2* pXAudio2;
|
CComPtr<IXAudio2> pXAudio2;
|
||||||
IXAudio2MasteringVoice* pMasteringVoice;
|
IXAudio2MasteringVoice* pMasteringVoice;
|
||||||
BaseStreamingVoice* voiceContext;
|
BaseStreamingVoice* voiceContext;
|
||||||
|
|
||||||
|
@ -314,7 +316,7 @@ public:
|
||||||
catch( Exception::XAudio2Error& ex )
|
catch( Exception::XAudio2Error& ex )
|
||||||
{
|
{
|
||||||
SysMessage( ex.CMessage() );
|
SysMessage( ex.CMessage() );
|
||||||
SAFE_RELEASE( pXAudio2 );
|
pXAudio2.Release();
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -333,7 +335,7 @@ public:
|
||||||
// But doing no cleanup at all causes XA2 under XP to crash. So after much trial
|
// But doing no cleanup at all causes XA2 under XP to crash. So after much trial
|
||||||
// and error we found a happy compromise as follows:
|
// and error we found a happy compromise as follows:
|
||||||
|
|
||||||
SAFE_DELETE_OBJ( voiceContext );
|
safe_delete( voiceContext );
|
||||||
|
|
||||||
voiceContext = NULL;
|
voiceContext = NULL;
|
||||||
|
|
||||||
|
@ -342,12 +344,11 @@ public:
|
||||||
|
|
||||||
pMasteringVoice = NULL;
|
pMasteringVoice = NULL;
|
||||||
|
|
||||||
SAFE_RELEASE( pXAudio2 );
|
pXAudio2.Release();
|
||||||
|
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Configure(HWND parent)
|
virtual void Configure(uptr parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
#include "Dialogs.h"
|
#include "Dialogs.h"
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
|
|
||||||
class WaveOutModule: public SndOutModule
|
class WaveOutModule: public SndOutModule
|
||||||
|
@ -197,7 +197,7 @@ public:
|
||||||
}
|
}
|
||||||
waveOutClose(hwodevice);
|
waveOutClose(hwodevice);
|
||||||
|
|
||||||
SAFE_DELETE_ARRAY( qbuffer );
|
safe_delete_array( qbuffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -271,13 +271,13 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void Configure(HWND parent)
|
virtual void Configure(uptr parent)
|
||||||
{
|
{
|
||||||
INT_PTR ret;
|
INT_PTR ret;
|
||||||
ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_WAVEOUT),GetActiveWindow(),(DLGPROC)ConfigProc,1);
|
ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_WAVEOUT), (HWND)parent, (DLGPROC)ConfigProc,1);
|
||||||
if(ret==-1)
|
if(ret==-1)
|
||||||
{
|
{
|
||||||
MessageBoxEx(GetActiveWindow(), L"Error Opening the config dialog.", L"OMG ERROR!", MB_OK, 0);
|
MessageBoxEx((HWND)parent, L"Error Opening the config dialog.", L"OMG ERROR!", MB_OK, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,6 +15,7 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
#include "Dialogs.h"
|
#include "Dialogs.h"
|
||||||
|
|
||||||
int SendDialogMsg( HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam)
|
int SendDialogMsg( HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam)
|
||||||
|
|
|
@ -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;
|
|
@ -15,7 +15,15 @@
|
||||||
//License along with this library; if not, write to the Free Software
|
//License along with this library; if not, write to the Free Software
|
||||||
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
//
|
//
|
||||||
#include "../spu2.h"
|
|
||||||
|
#include "Global.h"
|
||||||
|
|
||||||
|
# define WINVER 0x0501
|
||||||
|
# define _WIN32_WINNT 0x0501
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <mmsystem.h>
|
||||||
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "dsp.h"
|
#include "dsp.h"
|
||||||
|
|
|
@ -17,12 +17,27 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Mixer.h"
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// SPU2 Memory Indexers
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define spu2Rs16(mmem) (*(s16 *)((s8 *)spu2regs + ((mmem) & 0x1fff)))
|
||||||
|
#define spu2Ru16(mmem) (*(u16 *)((s8 *)spu2regs + ((mmem) & 0x1fff)))
|
||||||
|
|
||||||
|
extern s16* __fastcall GetMemPtr(u32 addr);
|
||||||
|
extern s16 __fastcall spu2M_Read( u32 addr );
|
||||||
|
extern void __fastcall spu2M_Write( u32 addr, s16 value );
|
||||||
|
extern void __fastcall spu2M_Write( u32 addr, u16 value );
|
||||||
|
|
||||||
|
|
||||||
struct V_VolumeLR
|
struct V_VolumeLR
|
||||||
{
|
{
|
||||||
static V_VolumeLR Max;
|
static V_VolumeLR Max;
|
||||||
|
|
||||||
s32 Left;
|
s32 Left;
|
||||||
s32 Right;
|
s32 Right;
|
||||||
|
|
||||||
V_VolumeLR() {}
|
V_VolumeLR() {}
|
||||||
V_VolumeLR( s32 both ) :
|
V_VolumeLR( s32 both ) :
|
||||||
|
@ -39,10 +54,10 @@ struct V_VolumeSlide
|
||||||
// Holds the "original" value of the volume for this voice, prior to slides.
|
// Holds the "original" value of the volume for this voice, prior to slides.
|
||||||
// (ie, the volume as written to the register)
|
// (ie, the volume as written to the register)
|
||||||
|
|
||||||
s16 Reg_VOL;
|
s16 Reg_VOL;
|
||||||
s32 Value;
|
s32 Value;
|
||||||
s8 Increment;
|
s8 Increment;
|
||||||
s8 Mode;
|
s8 Mode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
V_VolumeSlide() {}
|
V_VolumeSlide() {}
|
||||||
|
@ -57,7 +72,6 @@ public:
|
||||||
void Update();
|
void Update();
|
||||||
void RegSet( u16 src ); // used to set the volume from a register source (16 bit signed)
|
void RegSet( u16 src ); // used to set the volume from a register source (16 bit signed)
|
||||||
void DebugDump( FILE* dump, const char* title, const char* nameLR );
|
void DebugDump( FILE* dump, const char* title, const char* nameLR );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct V_VolumeSlideLR
|
struct V_VolumeSlideLR
|
||||||
|
@ -304,135 +318,235 @@ struct V_VoiceGates
|
||||||
s16 WetR; // 'AND Gate' for Effect Output for Right Channel
|
s16 WetR; // 'AND Gate' for Effect Output for Right Channel
|
||||||
};
|
};
|
||||||
|
|
||||||
union V_CoreGates
|
struct V_CoreGates
|
||||||
{
|
{
|
||||||
struct
|
union
|
||||||
{
|
{
|
||||||
u64 lo;
|
u128 v128;
|
||||||
u64 hi;
|
|
||||||
} v128;
|
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
s16 InpL; // Sound Data Input to Direct Output (Left)
|
s16 InpL; // Sound Data Input to Direct Output (Left)
|
||||||
s16 InpR; // Sound Data Input to Direct Output (Right)
|
s16 InpR; // Sound Data Input to Direct Output (Right)
|
||||||
s16 SndL; // Voice Data to Direct Output (Left)
|
s16 SndL; // Voice Data to Direct Output (Left)
|
||||||
s16 SndR; // Voice Data to Direct Output (Right)
|
s16 SndR; // Voice Data to Direct Output (Right)
|
||||||
s16 ExtL; // External Input to Direct Output (Left)
|
s16 ExtL; // External Input to Direct Output (Left)
|
||||||
s16 ExtR; // External Input to Direct Output (Right)
|
s16 ExtR; // External Input to Direct Output (Right)
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VoiceMixSet
|
||||||
|
{
|
||||||
|
static const VoiceMixSet Empty;
|
||||||
|
StereoOut32 Dry, Wet;
|
||||||
|
|
||||||
|
VoiceMixSet() {}
|
||||||
|
VoiceMixSet( const StereoOut32& dry, const StereoOut32& wet ) :
|
||||||
|
Dry( dry ),
|
||||||
|
Wet( wet )
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct V_Core
|
struct V_Core
|
||||||
{
|
{
|
||||||
static const uint NumVoices = 24;
|
static const uint NumVoices = 24;
|
||||||
|
|
||||||
|
int Index; // Core index identifier.
|
||||||
|
|
||||||
// Voice Gates -- These are SSE-related values, and must always be
|
// Voice Gates -- These are SSE-related values, and must always be
|
||||||
// first to ensure 16 byte alignment
|
// first to ensure 16 byte alignment
|
||||||
|
|
||||||
V_VoiceGates VoiceGates[NumVoices];
|
V_VoiceGates VoiceGates[NumVoices];
|
||||||
V_CoreGates DryGate;
|
V_CoreGates DryGate;
|
||||||
V_CoreGates WetGate;
|
V_CoreGates WetGate;
|
||||||
|
|
||||||
V_VolumeSlideLR MasterVol;// Master Volume
|
V_VolumeSlideLR MasterVol; // Master Volume
|
||||||
V_VolumeLR ExtVol; // Volume for External Data Input
|
V_VolumeLR ExtVol; // Volume for External Data Input
|
||||||
V_VolumeLR InpVol; // Volume for Sound Data Input
|
V_VolumeLR InpVol; // Volume for Sound Data Input
|
||||||
V_VolumeLR FxVol; // Volume for Output from Effects
|
V_VolumeLR FxVol; // Volume for Output from Effects
|
||||||
|
|
||||||
V_Voice Voices[NumVoices];
|
V_Voice Voices[NumVoices];
|
||||||
|
|
||||||
// Interrupt Address
|
u32 IRQA; // Interrupt Address
|
||||||
u32 IRQA;
|
u32 TSA; // DMA Transfer Start Address
|
||||||
// DMA Transfer Start Address
|
u32 TDA; // DMA Transfer Data Address (Internal...)
|
||||||
u32 TSA;
|
|
||||||
// DMA Transfer Data Address (Internal...)
|
|
||||||
u32 TDA;
|
|
||||||
|
|
||||||
// Interrupt Enable
|
s8 IRQEnable; // Interrupt Enable
|
||||||
s8 IRQEnable;
|
s8 DMABits; // DMA related?
|
||||||
// DMA related?
|
s8 FxEnable; // Effect Enable
|
||||||
s8 DMABits;
|
s8 NoiseClk; // Noise Clock
|
||||||
// Effect Enable
|
u16 AutoDMACtrl; // AutoDMA Status
|
||||||
s8 FxEnable;
|
s32 DMAICounter; // DMA Interrupt Counter
|
||||||
// Noise Clock
|
s8 Mute; // Mute
|
||||||
s8 NoiseClk;
|
u32 InputDataLeft; // Input Buffer
|
||||||
// AutoDMA Status
|
u32 InputPos;
|
||||||
u16 AutoDMACtrl;
|
u32 InputDataProgress;
|
||||||
// DMA Interrupt Counter
|
u8 AdmaInProgress;
|
||||||
s32 DMAICounter;
|
|
||||||
// Mute
|
|
||||||
s8 Mute;
|
|
||||||
// Input Buffer
|
|
||||||
u32 InputDataLeft;
|
|
||||||
u32 InputPos;
|
|
||||||
u32 InputDataProgress;
|
|
||||||
u8 AdmaInProgress;
|
|
||||||
|
|
||||||
// Reverb
|
V_Reverb Revb; // Reverb Registers
|
||||||
V_Reverb Revb;
|
V_ReverbBuffers RevBuffers; // buffer pointers for reverb, pre-calculated and pre-clipped.
|
||||||
V_ReverbBuffers RevBuffers; // buffer pointers for reverb, pre-calculated and pre-clipped.
|
u32 EffectsStartA;
|
||||||
u32 EffectsStartA;
|
u32 EffectsEndA;
|
||||||
u32 EffectsEndA;
|
u32 ReverbX;
|
||||||
u32 ReverbX;
|
|
||||||
|
|
||||||
// Current size of the effects buffer. Pre-caculated when the effects start
|
// Current size of the effects buffer. Pre-caculated when the effects start
|
||||||
// or end position registers are written. CAN BE NEGATIVE OR ZERO, in which
|
// or end position registers are written. CAN BE NEGATIVE OR ZERO, in which
|
||||||
// case reverb should be disabled.
|
// case reverb should be disabled.
|
||||||
s32 EffectsBufferSize;
|
s32 EffectsBufferSize;
|
||||||
|
|
||||||
// Registers
|
V_CoreRegs Regs; // Registers
|
||||||
V_CoreRegs Regs;
|
|
||||||
|
|
||||||
// Last samples to pass through the effects processor.
|
// Last samples to pass through the effects processor.
|
||||||
// Used because the effects processor works at 24khz and just pulls
|
// Used because the effects processor works at 24khz and just pulls
|
||||||
// from this for the odd Ts.
|
// from this for the odd Ts.
|
||||||
StereoOut32 LastEffect;
|
StereoOut32 LastEffect;
|
||||||
|
|
||||||
u8 InitDelay;
|
u8 InitDelay;
|
||||||
|
u8 CoreEnabled;
|
||||||
|
|
||||||
u8 CoreEnabled;
|
u8 AttrBit0;
|
||||||
|
u8 AttrBit4;
|
||||||
|
u8 AttrBit5;
|
||||||
|
|
||||||
u8 AttrBit0;
|
u16* DMAPtr;
|
||||||
u8 AttrBit4;
|
u32 MADR;
|
||||||
u8 AttrBit5;
|
u32 TADR;
|
||||||
|
|
||||||
u16*DMAPtr;
|
// HACK -- This is a temp buffer which is (or isn't?) used to circumvent some memory
|
||||||
u32 MADR;
|
// corruption that originates elsewhere in the plugin. >_< The actual ADMA buffer
|
||||||
u32 TADR;
|
// is an area mapped to SPU2 main memory.
|
||||||
|
s16 ADMATempBuffer[0x1000];
|
||||||
|
|
||||||
s16 ADMATempBuffer[0x1000];
|
// ----------------------------------------------------------------------------------
|
||||||
|
// V_Core Methods
|
||||||
|
// ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
u32 ADMAPV;
|
V_Core() : Index( -1 ) {} // uninitialized constructor
|
||||||
StereoOut32 ADMAP;
|
V_Core( int idx ); // our badass constructor
|
||||||
|
virtual ~V_Core() throw();
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
void UpdateEffectsBufferSize();
|
void UpdateEffectsBufferSize();
|
||||||
|
|
||||||
V_Core(); // our badass constructor
|
s32 EffectsBufferIndexer( s32 offset ) const;
|
||||||
s32 EffectsBufferIndexer( s32 offset ) const;
|
void UpdateFeedbackBuffersA();
|
||||||
void UpdateFeedbackBuffersA();
|
void UpdateFeedbackBuffersB();
|
||||||
void UpdateFeedbackBuffersB();
|
|
||||||
|
void WriteRegPS1( u32 mem, u16 value );
|
||||||
|
u16 ReadRegPS1( u32 mem );
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// Mixer Section
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
StereoOut32 Mix( const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext );
|
||||||
|
void Reverb_AdvanceBuffer();
|
||||||
|
StereoOut32 DoReverb( const StereoOut32& Input );
|
||||||
|
s32 RevbGetIndexer( s32 offset );
|
||||||
|
|
||||||
|
StereoOut32 ReadInput();
|
||||||
|
StereoOut32 ReadInputPV();
|
||||||
|
StereoOut32 ReadInput_HiFi( bool isCDDA );
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// DMA Section
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Returns the index of the DMA channel (4 for Core 0, or 7 for Core 1)
|
||||||
|
int GetDmaIndex() const
|
||||||
|
{
|
||||||
|
return (Index == 0) ? 4 : 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns either '4' or '7'
|
||||||
|
char GetDmaIndexChar() const
|
||||||
|
{
|
||||||
|
return 0x30 + GetDmaIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline u16 DmaRead()
|
||||||
|
{
|
||||||
|
const u16 ret = (u16)spu2M_Read(TDA);
|
||||||
|
++TDA; TDA &= 0xfffff;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void DmaWrite(u16 value)
|
||||||
|
{
|
||||||
|
spu2M_Write( TSA, value );
|
||||||
|
++TSA; TSA &= 0xfffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogAutoDMA( FILE* fp );
|
||||||
|
|
||||||
|
void DoDMAwrite(u16* pMem, u32 size);
|
||||||
|
void DoDMAread(u16* pMem, u32 size);
|
||||||
|
|
||||||
|
void AutoDMAReadBuffer(int mode);
|
||||||
|
void StartADMAWrite(u16 *pMem, u32 sz);
|
||||||
|
void PlainDMAWrite(u16 *pMem, u32 sz);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern V_Core Cores[2];
|
extern V_Core Cores[2];
|
||||||
extern V_SPDIF Spdif;
|
extern V_SPDIF Spdif;
|
||||||
|
|
||||||
// Output Buffer Writing Position (the same for all data);
|
// Output Buffer Writing Position (the same for all data);
|
||||||
extern s16 OutPos;
|
extern s16 OutPos;
|
||||||
// Input Buffer Reading Position (the same for all data);
|
// Input Buffer Reading Position (the same for all data);
|
||||||
extern s16 InputPos;
|
extern s16 InputPos;
|
||||||
// SPU Mixing Cycles ("Ticks mixed" counter)
|
// SPU Mixing Cycles ("Ticks mixed" counter)
|
||||||
extern u32 Cycles;
|
extern u32 Cycles;
|
||||||
|
|
||||||
#ifdef __LINUX__
|
extern short* spu2regs;
|
||||||
|
extern short* _spu2mem;
|
||||||
|
extern int PlayMode;
|
||||||
|
|
||||||
#include <sys/types.h>
|
extern void SetIrqCall();
|
||||||
#include <sys/timeb.h>
|
extern void StartVoices(int core, u32 value);
|
||||||
|
extern void StopVoices(int core, u32 value);
|
||||||
|
extern void InitADSR();
|
||||||
|
extern void CalculateADSR( V_Voice& vc );
|
||||||
|
|
||||||
static __forceinline u32 timeGetTime()
|
extern void spdif_set51(u32 is_5_1_out);
|
||||||
|
extern u32 spdif_init();
|
||||||
|
extern void spdif_shutdown();
|
||||||
|
extern void spdif_get_samples(s32 *samples); // fills the buffer with [l,r,c,lfe,sl,sr] if using 5.1 output, or [l,r] if using stereo
|
||||||
|
extern void UpdateSpdifMode();
|
||||||
|
|
||||||
|
namespace Savestate
|
||||||
{
|
{
|
||||||
struct timeb t;
|
struct DataBlock;
|
||||||
ftime(&t);
|
|
||||||
return (u32)(t.time*1000+t.millitm);
|
extern s32 __fastcall FreezeIt( DataBlock& spud );
|
||||||
|
extern s32 __fastcall ThawIt( DataBlock& spud );
|
||||||
|
extern s32 __fastcall SizeIt();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// ADPCM Decoder Cache
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// The SPU2 has a dynamic memory range which is used for several internal operations, such as
|
||||||
|
// registers, CORE 1/2 mixing, AutoDMAs, and some other fancy stuff. We exclude this range
|
||||||
|
// from the cache here:
|
||||||
|
static const s32 SPU2_DYN_MEMLINE = 0x2800;
|
||||||
|
|
||||||
|
// 8 short words per encoded PCM block. (as stored in SPU2 ram)
|
||||||
|
static const int pcm_WordsPerBlock = 8;
|
||||||
|
|
||||||
|
// number of cachable ADPCM blocks (any blocks above the SPU2_DYN_MEMLINE)
|
||||||
|
static const int pcm_BlockCount = 0x100000 / pcm_WordsPerBlock;
|
||||||
|
|
||||||
|
// 28 samples per decoded PCM block (as stored in our cache)
|
||||||
|
static const int pcm_DecodedSamplesPerBlock = 28;
|
||||||
|
|
||||||
|
struct PcmCacheEntry
|
||||||
|
{
|
||||||
|
bool Validated;
|
||||||
|
s16 Sampledata[pcm_DecodedSamplesPerBlock];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern PcmCacheEntry* pcm_cache_data;
|
||||||
|
|
|
@ -147,21 +147,21 @@ Core attributes (SD_C)
|
||||||
|
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
|
||||||
#define SPDIF_OUT_OFF 0x0000 //no spdif output
|
#define SPDIF_OUT_OFF 0x0000 // no spdif output
|
||||||
#define SPDIF_OUT_PCM 0x0020 //encode spdif from spu2 pcm output
|
#define SPDIF_OUT_PCM 0x0020 // encode spdif from spu2 pcm output
|
||||||
#define SPDIF_OUT_BYPASS 0x0100 //bypass spu2 processing
|
#define SPDIF_OUT_BYPASS 0x0100 // bypass spu2 processing
|
||||||
|
|
||||||
#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 //bypass mode for digital bitstream data
|
#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 // bypass mode for digital bitstream data
|
||||||
#define SPDIF_MODE_BYPASS_PCM 0x0000 //bypass mode for pcm data (using analog output)
|
#define SPDIF_MODE_BYPASS_PCM 0x0000 // bypass mode for pcm data (using analog output)
|
||||||
|
|
||||||
#define SPDIF_MODE_MEDIA_CD 0x0800 //source media is a CD
|
#define SPDIF_MODE_MEDIA_CD 0x0800 // source media is a CD
|
||||||
#define SPDIF_MODE_MEDIA_DVD 0x0000 //source media is a DVD
|
#define SPDIF_MODE_MEDIA_DVD 0x0000 // source media is a DVD
|
||||||
|
|
||||||
#define SPDIF_MEDIA_CDVD 0x0200
|
#define SPDIF_MEDIA_CDVD 0x0200
|
||||||
#define SPDIF_MEDIA_400 0x0000
|
#define SPDIF_MEDIA_400 0x0000
|
||||||
|
|
||||||
#define SPDIF_PROTECT_NORMAL 0x0000 // spdif stream is not protected
|
#define SPDIF_PROTECT_NORMAL 0x0000 // spdif stream is not protected
|
||||||
#define SPDIF_PROTECT_PROHIBIT 0x8000 // spdif stream can't be copied
|
#define SPDIF_PROTECT_PROHIBIT 0x8000 // spdif stream can't be copied
|
||||||
|
|
||||||
/********************************************************************/
|
/********************************************************************/
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -15,50 +15,31 @@
|
||||||
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Spu2.h"
|
// ======================================================================================
|
||||||
|
// spu2sys.cpp -- Emulation module for the SPU2 'virtual machine'
|
||||||
|
// ======================================================================================
|
||||||
|
// This module contains (most!) stuff which is directly related to SPU2 emulation.
|
||||||
|
// Contents should be cross-platform compatible whenever possible.
|
||||||
|
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
#include "RegTable.h"
|
#include "RegTable.h"
|
||||||
|
#include "dma.h"
|
||||||
|
|
||||||
#ifdef __LINUX__
|
#include "PS2E-spu2.h" // needed until I figure out a nice solution for irqcallback dependencies.
|
||||||
#include "Linux.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void StartVoices(int core, u32 value);
|
|
||||||
void StopVoices(int core, u32 value);
|
|
||||||
|
|
||||||
void InitADSR();
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
DWORD CALLBACK TimeThread(PVOID /* unused param */);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void (* _irqcallback)();
|
|
||||||
void (* dma4callback)();
|
|
||||||
void (* dma7callback)();
|
|
||||||
|
|
||||||
short *spu2regs;
|
short *spu2regs;
|
||||||
short *_spu2mem;
|
short *_spu2mem;
|
||||||
|
|
||||||
u8 callirq;
|
V_CoreDebug DebugCores[2];
|
||||||
|
V_Core Cores[2];
|
||||||
|
V_SPDIF Spdif;
|
||||||
|
|
||||||
V_CoreDebug DebugCores[2];
|
s16 OutPos;
|
||||||
V_Core Cores[2];
|
s16 InputPos;
|
||||||
V_SPDIF Spdif;
|
u32 Cycles;
|
||||||
|
|
||||||
s16 OutPos;
|
int PlayMode;
|
||||||
s16 InputPos;
|
|
||||||
u32 Cycles;
|
|
||||||
|
|
||||||
u32* cyclePtr = NULL;
|
|
||||||
u32 lClocks = 0;
|
|
||||||
|
|
||||||
int PlayMode;
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
HINSTANCE hInstance;
|
|
||||||
CRITICAL_SECTION threadSync;
|
|
||||||
HANDLE hThreadFunc;
|
|
||||||
u32 ThreadFuncID;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool has_to_call_irq=false;
|
bool has_to_call_irq=false;
|
||||||
|
|
||||||
|
@ -67,33 +48,6 @@ void SetIrqCall()
|
||||||
has_to_call_irq=true;
|
has_to_call_irq=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef __LINUX__
|
|
||||||
void SysMessage(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list list;
|
|
||||||
char tmp[512];
|
|
||||||
wchar_t wtmp[512];
|
|
||||||
|
|
||||||
va_start(list,fmt);
|
|
||||||
sprintf_s(tmp,fmt,list);
|
|
||||||
va_end(list);
|
|
||||||
swprintf_s(wtmp, L"%S", tmp);
|
|
||||||
MessageBox(0, wtmp, L"SPU2-X System Message", 0);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void SysMessage(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list list;
|
|
||||||
char tmp[512];
|
|
||||||
wchar_t wtmp[512];
|
|
||||||
|
|
||||||
va_start(list,fmt);
|
|
||||||
sprintf(tmp,fmt,list);
|
|
||||||
va_end(list);
|
|
||||||
printf("%s", tmp);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
__forceinline s16 * __fastcall GetMemPtr(u32 addr)
|
__forceinline s16 * __fastcall GetMemPtr(u32 addr)
|
||||||
{
|
{
|
||||||
#ifndef DEBUG_FAST
|
#ifndef DEBUG_FAST
|
||||||
|
@ -111,9 +65,7 @@ __forceinline s16 __fastcall spu2M_Read( u32 addr )
|
||||||
|
|
||||||
// writes a signed value to the SPU2 ram
|
// writes a signed value to the SPU2 ram
|
||||||
// Invalidates the ADPCM cache in the process.
|
// Invalidates the ADPCM cache in the process.
|
||||||
// Optimization note: don't use __forceinline because the footprint of this
|
__forceinline void __fastcall spu2M_Write( u32 addr, s16 value )
|
||||||
// function is a little too heavy now. Better to let the compiler decide.
|
|
||||||
__inline void __fastcall spu2M_Write( u32 addr, s16 value )
|
|
||||||
{
|
{
|
||||||
// Make sure the cache is invalidated:
|
// Make sure the cache is invalidated:
|
||||||
// (note to self : addr address WORDs, not bytes)
|
// (note to self : addr address WORDs, not bytes)
|
||||||
|
@ -135,50 +87,55 @@ __inline void __fastcall spu2M_Write( u32 addr, u16 value )
|
||||||
spu2M_Write( addr, (s16)value );
|
spu2M_Write( addr, (s16)value );
|
||||||
}
|
}
|
||||||
|
|
||||||
V_VolumeLR V_VolumeLR::Max( 0x7FFFFFFF );
|
V_VolumeLR V_VolumeLR::Max( 0x7FFFFFFF );
|
||||||
V_VolumeSlideLR V_VolumeSlideLR::Max( 0x3FFF, 0x7FFFFFFF );
|
V_VolumeSlideLR V_VolumeSlideLR::Max( 0x3FFF, 0x7FFFFFFF );
|
||||||
|
|
||||||
V_Core::V_Core()
|
V_Core::V_Core( int coreidx ) : Index( coreidx )
|
||||||
|
//LogFile_AutoDMA( NULL )
|
||||||
{
|
{
|
||||||
|
/*char fname[128];
|
||||||
|
sprintf( fname, "logs/adma%d.raw", GetDmaIndex() );
|
||||||
|
LogFile_AutoDMA = fopen( fname, "wb" );*/
|
||||||
|
}
|
||||||
|
|
||||||
|
V_Core::~V_Core() throw()
|
||||||
|
{
|
||||||
|
// Can't use this yet because we dumb V_Core into savestates >_<
|
||||||
|
/*if( LogFile_AutoDMA != NULL )
|
||||||
|
{
|
||||||
|
fclose( LogFile_AutoDMA );
|
||||||
|
LogFile_AutoDMA = NULL;
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void V_Core::Reset()
|
void V_Core::Reset()
|
||||||
{
|
{
|
||||||
memset( this, 0, sizeof(V_Core) );
|
memset( this, 0, sizeof(V_Core) );
|
||||||
|
|
||||||
const int c = (this == Cores) ? 0 : 1;
|
const int c = Index;
|
||||||
|
|
||||||
Regs.STATX=0;
|
Regs.STATX = 0;
|
||||||
Regs.ATTR=0;
|
Regs.ATTR = 0;
|
||||||
ExtVol = V_VolumeLR::Max;
|
ExtVol = V_VolumeLR::Max;
|
||||||
InpVol = V_VolumeLR::Max;
|
InpVol = V_VolumeLR::Max;
|
||||||
FxVol = V_VolumeLR::Max;
|
FxVol = V_VolumeLR::Max;
|
||||||
|
|
||||||
MasterVol = V_VolumeSlideLR::Max;
|
MasterVol = V_VolumeSlideLR::Max;
|
||||||
|
|
||||||
DryGate.ExtL = -1;
|
memset( &DryGate, -1, sizeof(DryGate) );
|
||||||
DryGate.ExtR = -1;
|
memset( &WetGate, -1, sizeof(WetGate) );
|
||||||
WetGate.ExtL = -1;
|
|
||||||
WetGate.ExtR = -1;
|
|
||||||
DryGate.InpL = -1;
|
|
||||||
DryGate.InpR = -1;
|
|
||||||
WetGate.InpR = -1;
|
|
||||||
WetGate.InpL = -1;
|
|
||||||
DryGate.SndL = -1;
|
|
||||||
DryGate.SndR = -1;
|
|
||||||
WetGate.SndL = -1;
|
|
||||||
WetGate.SndR = -1;
|
|
||||||
|
|
||||||
Regs.MMIX = 0xFFCF;
|
Regs.MMIX = 0xFFCF;
|
||||||
Regs.VMIXL = 0xFFFFFF;
|
Regs.VMIXL = 0xFFFFFF;
|
||||||
Regs.VMIXR = 0xFFFFFF;
|
Regs.VMIXR = 0xFFFFFF;
|
||||||
Regs.VMIXEL = 0xFFFFFF;
|
Regs.VMIXEL = 0xFFFFFF;
|
||||||
Regs.VMIXER = 0xFFFFFF;
|
Regs.VMIXER = 0xFFFFFF;
|
||||||
EffectsStartA= 0xEFFF8 + 0x10000*c;
|
EffectsStartA = 0xEFFF8 + (0x10000*c);
|
||||||
EffectsEndA = 0xEFFFF + 0x10000*c;
|
EffectsEndA = 0xEFFFF + (0x10000*c);
|
||||||
FxEnable=0;
|
|
||||||
IRQA=0xFFFF0;
|
FxEnable = 0;
|
||||||
IRQEnable=1;
|
IRQA = 0xFFFF0;
|
||||||
|
IRQEnable = 1;
|
||||||
|
|
||||||
for( uint v=0; v<NumVoices; ++v )
|
for( uint v=0; v<NumVoices; ++v )
|
||||||
{
|
{
|
||||||
|
@ -187,19 +144,20 @@ void V_Core::Reset()
|
||||||
VoiceGates[v].WetL = -1;
|
VoiceGates[v].WetL = -1;
|
||||||
VoiceGates[v].WetR = -1;
|
VoiceGates[v].WetR = -1;
|
||||||
|
|
||||||
Voices[v].Volume = V_VolumeSlideLR::Max;
|
Voices[v].Volume = V_VolumeSlideLR::Max;
|
||||||
|
|
||||||
Voices[v].ADSR.Value = 0;
|
Voices[v].ADSR.Value = 0;
|
||||||
Voices[v].ADSR.Phase = 0;
|
Voices[v].ADSR.Phase = 0;
|
||||||
Voices[v].Pitch = 0x3FFF;
|
Voices[v].Pitch = 0x3FFF;
|
||||||
Voices[v].NextA = 2800;
|
Voices[v].NextA = 2800;
|
||||||
Voices[v].StartA = 2800;
|
Voices[v].StartA = 2800;
|
||||||
Voices[v].LoopStartA = 2800;
|
Voices[v].LoopStartA = 2800;
|
||||||
}
|
}
|
||||||
DMAICounter = 0;
|
|
||||||
AdmaInProgress = 0;
|
|
||||||
|
|
||||||
Regs.STATX = 0x80;
|
DMAICounter = 0;
|
||||||
|
AdmaInProgress = 0;
|
||||||
|
|
||||||
|
Regs.STATX = 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 V_Core::EffectsBufferIndexer( s32 offset ) const
|
s32 V_Core::EffectsBufferIndexer( s32 offset ) const
|
||||||
|
@ -456,7 +414,7 @@ __forceinline void TimeUpdate(u32 cClocks)
|
||||||
lClocks+=TickInterval;
|
lClocks+=TickInterval;
|
||||||
Cycles++;
|
Cycles++;
|
||||||
|
|
||||||
// Note: IPU does not use MMX regs, so no need to save them.
|
// Note: IOP does not use MMX regs, so no need to save them.
|
||||||
//SaveMMXRegs();
|
//SaveMMXRegs();
|
||||||
Mix();
|
Mix();
|
||||||
//RestoreMMXRegs();
|
//RestoreMMXRegs();
|
||||||
|
@ -516,11 +474,12 @@ void V_VolumeSlide::RegSet( u16 src )
|
||||||
Value = GetVol32( src );
|
Value = GetVol32( src );
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPU_ps1_write(u32 mem, u16 value)
|
void V_Core::WriteRegPS1( u32 mem, u16 value )
|
||||||
{
|
{
|
||||||
bool show=true;
|
jASSUME( Index == 0 ); // Valid on Core 0 only!
|
||||||
|
|
||||||
u32 reg = mem&0xffff;
|
bool show = true;
|
||||||
|
u32 reg = mem & 0xffff;
|
||||||
|
|
||||||
if((reg>=0x1c00)&&(reg<0x1d80))
|
if((reg>=0x1c00)&&(reg<0x1d80))
|
||||||
{
|
{
|
||||||
|
@ -530,42 +489,42 @@ void SPU_ps1_write(u32 mem, u16 value)
|
||||||
switch(vval)
|
switch(vval)
|
||||||
{
|
{
|
||||||
case 0: //VOLL (Volume L)
|
case 0: //VOLL (Volume L)
|
||||||
Cores[0].Voices[voice].Volume.Left.Mode = 0;
|
Voices[voice].Volume.Left.Mode = 0;
|
||||||
Cores[0].Voices[voice].Volume.Left.RegSet( value << 1 );
|
Voices[voice].Volume.Left.RegSet( value << 1 );
|
||||||
Cores[0].Voices[voice].Volume.Left.Reg_VOL = value;
|
Voices[voice].Volume.Left.Reg_VOL = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: //VOLR (Volume R)
|
case 1: //VOLR (Volume R)
|
||||||
Cores[0].Voices[voice].Volume.Right.Mode = 0;
|
Voices[voice].Volume.Right.Mode = 0;
|
||||||
Cores[0].Voices[voice].Volume.Right.RegSet( value << 1 );
|
Voices[voice].Volume.Right.RegSet( value << 1 );
|
||||||
Cores[0].Voices[voice].Volume.Right.Reg_VOL = value;
|
Voices[voice].Volume.Right.Reg_VOL = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: Cores[0].Voices[voice].Pitch = value; break;
|
case 2: Voices[voice].Pitch = value; break;
|
||||||
case 3: Cores[0].Voices[voice].StartA = (u32)value<<8; break;
|
case 3: Voices[voice].StartA = (u32)value<<8; break;
|
||||||
|
|
||||||
case 4: // ADSR1 (Envelope)
|
case 4: // ADSR1 (Envelope)
|
||||||
Cores[0].Voices[voice].ADSR.AttackMode = (value & 0x8000)>>15;
|
Voices[voice].ADSR.AttackMode = (value & 0x8000)>>15;
|
||||||
Cores[0].Voices[voice].ADSR.AttackRate = (value & 0x7F00)>>8;
|
Voices[voice].ADSR.AttackRate = (value & 0x7F00)>>8;
|
||||||
Cores[0].Voices[voice].ADSR.DecayRate = (value & 0xF0)>>4;
|
Voices[voice].ADSR.DecayRate = (value & 0xF0)>>4;
|
||||||
Cores[0].Voices[voice].ADSR.SustainLevel = (value & 0xF);
|
Voices[voice].ADSR.SustainLevel = (value & 0xF);
|
||||||
Cores[0].Voices[voice].ADSR.Reg_ADSR1 = value;
|
Voices[voice].ADSR.Reg_ADSR1 = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5: // ADSR2 (Envelope)
|
case 5: // ADSR2 (Envelope)
|
||||||
Cores[0].Voices[voice].ADSR.SustainMode = (value & 0xE000)>>13;
|
Voices[voice].ADSR.SustainMode = (value & 0xE000)>>13;
|
||||||
Cores[0].Voices[voice].ADSR.SustainRate = (value & 0x1FC0)>>6;
|
Voices[voice].ADSR.SustainRate = (value & 0x1FC0)>>6;
|
||||||
Cores[0].Voices[voice].ADSR.ReleaseMode = (value & 0x20)>>5;
|
Voices[voice].ADSR.ReleaseMode = (value & 0x20)>>5;
|
||||||
Cores[0].Voices[voice].ADSR.ReleaseRate = (value & 0x1F);
|
Voices[voice].ADSR.ReleaseRate = (value & 0x1F);
|
||||||
Cores[0].Voices[voice].ADSR.Reg_ADSR2 = value;
|
Voices[voice].ADSR.Reg_ADSR2 = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
Cores[0].Voices[voice].ADSR.Value = ((s32)value<<16) | value;
|
Voices[voice].ADSR.Value = ((s32)value<<16) | value;
|
||||||
ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value );
|
ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7: Cores[0].Voices[voice].LoopStartA = (u32)value <<8; break;
|
case 7: Voices[voice].LoopStartA = (u32)value <<8; break;
|
||||||
|
|
||||||
jNO_DEFAULT;
|
jNO_DEFAULT;
|
||||||
}
|
}
|
||||||
|
@ -574,21 +533,21 @@ void SPU_ps1_write(u32 mem, u16 value)
|
||||||
else switch(reg)
|
else switch(reg)
|
||||||
{
|
{
|
||||||
case 0x1d80:// Mainvolume left
|
case 0x1d80:// Mainvolume left
|
||||||
Cores[0].MasterVol.Left.Mode = 0;
|
MasterVol.Left.Mode = 0;
|
||||||
Cores[0].MasterVol.Left.RegSet( value );
|
MasterVol.Left.RegSet( value );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1d82:// Mainvolume right
|
case 0x1d82:// Mainvolume right
|
||||||
Cores[0].MasterVol.Right.Mode = 0;
|
MasterVol.Right.Mode = 0;
|
||||||
Cores[0].MasterVol.Right.RegSet( value );
|
MasterVol.Right.RegSet( value );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1d84:// Reverberation depth left
|
case 0x1d84:// Reverberation depth left
|
||||||
Cores[0].FxVol.Left = GetVol32( value );
|
FxVol.Left = GetVol32( value );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1d86:// Reverberation depth right
|
case 0x1d86:// Reverberation depth right
|
||||||
Cores[0].FxVol.Right = GetVol32( value );
|
FxVol.Right = GetVol32( value );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1d88:// Voice ON (0-15)
|
case 0x1d88:// Voice ON (0-15)
|
||||||
|
@ -652,11 +611,11 @@ void SPU_ps1_write(u32 mem, u16 value)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1da4:
|
case 0x1da4:
|
||||||
Cores[0].IRQA=(u32)value<<8;
|
IRQA = (u32)value<<8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1da6:
|
case 0x1da6:
|
||||||
Cores[0].TSA=(u32)value<<8;
|
TSA = (u32)value<<8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1daa:
|
case 0x1daa:
|
||||||
|
@ -668,7 +627,7 @@ void SPU_ps1_write(u32 mem, u16 value)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1da8:// Spu Write to Memory
|
case 0x1da8:// Spu Write to Memory
|
||||||
DmaWrite(0,value);
|
DmaWrite(value);
|
||||||
show=false;
|
show=false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -678,8 +637,10 @@ void SPU_ps1_write(u32 mem, u16 value)
|
||||||
spu2Ru16(mem)=value;
|
spu2Ru16(mem)=value;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 SPU_ps1_read(u32 mem)
|
u16 V_Core::ReadRegPS1(u32 mem)
|
||||||
{
|
{
|
||||||
|
jASSUME( Index == 0 ); // Valid on Core 0 only!
|
||||||
|
|
||||||
bool show=true;
|
bool show=true;
|
||||||
u16 value = spu2Ru16(mem);
|
u16 value = spu2Ru16(mem);
|
||||||
|
|
||||||
|
@ -693,60 +654,60 @@ u16 SPU_ps1_read(u32 mem)
|
||||||
switch(vval)
|
switch(vval)
|
||||||
{
|
{
|
||||||
case 0: //VOLL (Volume L)
|
case 0: //VOLL (Volume L)
|
||||||
//value=Cores[0].Voices[voice].VolumeL.Mode;
|
//value=Voices[voice].VolumeL.Mode;
|
||||||
//value=Cores[0].Voices[voice].VolumeL.Value;
|
//value=Voices[voice].VolumeL.Value;
|
||||||
value = Cores[0].Voices[voice].Volume.Left.Reg_VOL;
|
value = Voices[voice].Volume.Left.Reg_VOL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: //VOLR (Volume R)
|
case 1: //VOLR (Volume R)
|
||||||
//value=Cores[0].Voices[voice].VolumeR.Mode;
|
//value=Voices[voice].VolumeR.Mode;
|
||||||
//value=Cores[0].Voices[voice].VolumeR.Value;
|
//value=Voices[voice].VolumeR.Value;
|
||||||
value = Cores[0].Voices[voice].Volume.Right.Reg_VOL;
|
value = Voices[voice].Volume.Right.Reg_VOL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: value = Cores[0].Voices[voice].Pitch; break;
|
case 2: value = Voices[voice].Pitch; break;
|
||||||
case 3: value = Cores[0].Voices[voice].StartA; break;
|
case 3: value = Voices[voice].StartA; break;
|
||||||
case 4: value = Cores[0].Voices[voice].ADSR.Reg_ADSR1; break;
|
case 4: value = Voices[voice].ADSR.Reg_ADSR1; break;
|
||||||
case 5: value = Cores[0].Voices[voice].ADSR.Reg_ADSR2; break;
|
case 5: value = Voices[voice].ADSR.Reg_ADSR2; break;
|
||||||
case 6: value = Cores[0].Voices[voice].ADSR.Value >> 16; break;
|
case 6: value = Voices[voice].ADSR.Value >> 16; break;
|
||||||
case 7: value = Cores[0].Voices[voice].LoopStartA; break;
|
case 7: value = Voices[voice].LoopStartA; break;
|
||||||
|
|
||||||
jNO_DEFAULT;
|
jNO_DEFAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else switch(reg)
|
else switch(reg)
|
||||||
{
|
{
|
||||||
case 0x1d80: value = Cores[0].MasterVol.Left.Value >> 16; break;
|
case 0x1d80: value = MasterVol.Left.Value >> 16; break;
|
||||||
case 0x1d82: value = Cores[0].MasterVol.Right.Value >> 16; break;
|
case 0x1d82: value = MasterVol.Right.Value >> 16; break;
|
||||||
case 0x1d84: value = Cores[0].FxVol.Left >> 16; break;
|
case 0x1d84: value = FxVol.Left >> 16; break;
|
||||||
case 0x1d86: value = Cores[0].FxVol.Right >> 16; break;
|
case 0x1d86: value = FxVol.Right >> 16; break;
|
||||||
|
|
||||||
case 0x1d88: value = 0; break;
|
case 0x1d88: value = 0; break;
|
||||||
case 0x1d8a: value = 0; break;
|
case 0x1d8a: value = 0; break;
|
||||||
case 0x1d8c: value = 0; break;
|
case 0x1d8c: value = 0; break;
|
||||||
case 0x1d8e: value = 0; break;
|
case 0x1d8e: value = 0; break;
|
||||||
|
|
||||||
case 0x1d90: value = Cores[0].Regs.PMON&0xFFFF; break;
|
case 0x1d90: value = Regs.PMON&0xFFFF; break;
|
||||||
case 0x1d92: value = Cores[0].Regs.PMON>>16; break;
|
case 0x1d92: value = Regs.PMON>>16; break;
|
||||||
|
|
||||||
case 0x1d94: value = Cores[0].Regs.NON&0xFFFF; break;
|
case 0x1d94: value = Regs.NON&0xFFFF; break;
|
||||||
case 0x1d96: value = Cores[0].Regs.NON>>16; break;
|
case 0x1d96: value = Regs.NON>>16; break;
|
||||||
|
|
||||||
case 0x1d98: value = Cores[0].Regs.VMIXEL&0xFFFF; break;
|
case 0x1d98: value = Regs.VMIXEL&0xFFFF; break;
|
||||||
case 0x1d9a: value = Cores[0].Regs.VMIXEL>>16; break;
|
case 0x1d9a: value = Regs.VMIXEL>>16; break;
|
||||||
case 0x1d9c: value = Cores[0].Regs.VMIXL&0xFFFF; break;
|
case 0x1d9c: value = Regs.VMIXL&0xFFFF; break;
|
||||||
case 0x1d9e: value = Cores[0].Regs.VMIXL>>16; break;
|
case 0x1d9e: value = Regs.VMIXL>>16; break;
|
||||||
|
|
||||||
case 0x1da2:
|
case 0x1da2:
|
||||||
if( value != Cores[0].EffectsStartA>>3 )
|
if( value != EffectsStartA>>3 )
|
||||||
{
|
{
|
||||||
value = Cores[0].EffectsStartA>>3;
|
value = EffectsStartA>>3;
|
||||||
Cores[0].UpdateEffectsBufferSize();
|
UpdateEffectsBufferSize();
|
||||||
Cores[0].ReverbX = 0;
|
ReverbX = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x1da4: value = Cores[0].IRQA>>3; break;
|
case 0x1da4: value = IRQA>>3; break;
|
||||||
case 0x1da6: value = Cores[0].TSA>>3; break;
|
case 0x1da6: value = TSA>>3; break;
|
||||||
|
|
||||||
case 0x1daa:
|
case 0x1daa:
|
||||||
value = SPU2read(REG_C_ATTR);
|
value = SPU2read(REG_C_ATTR);
|
||||||
|
@ -755,7 +716,7 @@ u16 SPU_ps1_read(u32 mem)
|
||||||
value = 0; //SPU2read(REG_P_STATX)<<3;
|
value = 0; //SPU2read(REG_P_STATX)<<3;
|
||||||
break;
|
break;
|
||||||
case 0x1da8:
|
case 0x1da8:
|
||||||
value = DmaRead(0);
|
value = DmaRead();
|
||||||
show=false;
|
show=false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -930,6 +891,30 @@ void SPU2_FastWrite( u32 rmem, u16 value )
|
||||||
V_Core& thiscore = Cores[core];
|
V_Core& thiscore = Cores[core];
|
||||||
switch(omem)
|
switch(omem)
|
||||||
{
|
{
|
||||||
|
case 0x1ac:
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// 0x1ac / 0x5ac : direct-write to DMA address : special register (undocumented)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// On the GS, DMAs are actually pushed through a hardware register. Chances are the
|
||||||
|
// SPU works the same way, and "technically" *all* DMA data actually passes through
|
||||||
|
// the HW registers at 0x1ac (core0) and 0x5ac (core1). We handle normal DMAs in
|
||||||
|
// optimized block copy fashion elsewhere, but some games will write this register
|
||||||
|
// directly, so handle those here:
|
||||||
|
|
||||||
|
// Performance Note: If a game uses this extensively, it *will* be slow. I plan to
|
||||||
|
// fix that using a proper paged LUT someday.
|
||||||
|
|
||||||
|
for( int i=0; i<2; i++ )
|
||||||
|
{
|
||||||
|
if(Cores[i].IRQEnable && (Cores[i].IRQA == Cores[i].TSA))
|
||||||
|
{
|
||||||
|
Spdif.Info = 4 << i;
|
||||||
|
SetIrqCall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thiscore.DmaWrite( value );
|
||||||
|
break;
|
||||||
|
|
||||||
case REG_C_ATTR:
|
case REG_C_ATTR:
|
||||||
{
|
{
|
||||||
int irqe = thiscore.IRQEnable;
|
int irqe = thiscore.IRQEnable;
|
Loading…
Reference in New Issue