mirror of https://github.com/PCSX2/pcsx2.git
SPU2-X: Added a lowpass filter to the reverb output, which should produce more correct audio (still experimental). Plus many code cleanups.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@509 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
d5b0ff7fa3
commit
340db13caa
|
@ -51,7 +51,37 @@ 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
|
||||
static const bool IsDevBuild = true;
|
||||
|
||||
#else
|
||||
|
||||
# define DevCon 0&&Console
|
||||
# define DevMsg
|
||||
static const bool IsDevBuild = false;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
# define DbgCon Console
|
||||
static const bool IsDebugBuild = true;
|
||||
|
||||
#else
|
||||
|
||||
# define DbgCon 0&&Console
|
||||
static const bool IsDebugBuild = false;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -187,14 +187,14 @@ void DoFullDump()
|
|||
" - Value: %x\n",
|
||||
Cores[c].Voices[v].ADSR.Reg_ADSR1,
|
||||
Cores[c].Voices[v].ADSR.Reg_ADSR2,
|
||||
Cores[c].Voices[v].ADSR.Ar,
|
||||
Cores[c].Voices[v].ADSR.Am,
|
||||
Cores[c].Voices[v].ADSR.Dr,
|
||||
Cores[c].Voices[v].ADSR.Sl,
|
||||
Cores[c].Voices[v].ADSR.Sr,
|
||||
Cores[c].Voices[v].ADSR.Sm,
|
||||
Cores[c].Voices[v].ADSR.Rr,
|
||||
Cores[c].Voices[v].ADSR.Rm,
|
||||
Cores[c].Voices[v].ADSR.AttackRate,
|
||||
Cores[c].Voices[v].ADSR.AttackMode,
|
||||
Cores[c].Voices[v].ADSR.DecayRate,
|
||||
Cores[c].Voices[v].ADSR.SustainLevel,
|
||||
Cores[c].Voices[v].ADSR.SustainRate,
|
||||
Cores[c].Voices[v].ADSR.SustainMode,
|
||||
Cores[c].Voices[v].ADSR.ReleaseRate,
|
||||
Cores[c].Voices[v].ADSR.ReleaseMode,
|
||||
Cores[c].Voices[v].ADSR.Phase,
|
||||
Cores[c].Voices[v].ADSR.Value);
|
||||
fprintf(dump," - Pitch: %x\n",Cores[c].Voices[v].Pitch);
|
||||
|
|
|
@ -45,46 +45,49 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD dwReason,LPVOID lpvReserved)
|
|||
|
||||
static void InitLibraryName()
|
||||
{
|
||||
#ifdef PUBLIC
|
||||
if( !IsDevBuild )
|
||||
{
|
||||
// Public Release!
|
||||
// Output a simplified string that's just our name:
|
||||
|
||||
// Public Release!
|
||||
// Output a simplified string that's just our name:
|
||||
strcpy( libraryName, "SPU2-X" );
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef SVN_REV_UNKNOWN
|
||||
|
||||
strcpy( libraryName, "SPU2-X" );
|
||||
// Unknown revision.
|
||||
// Output a name that includes devbuild status but not
|
||||
// subversion revision tags:
|
||||
|
||||
#elif defined( SVN_REV_UNKNOWN )
|
||||
|
||||
// Unknown revision.
|
||||
// Output a name that includes devbuild status but not
|
||||
// subversion revision tags:
|
||||
|
||||
strcpy( libraryName, "SPU2-X"
|
||||
# ifdef _DEBUG_FAST
|
||||
"-Debug"
|
||||
# elif defined( DEBUG )
|
||||
"-Debug/Strict" // strict debugging is slow!
|
||||
# else
|
||||
"-Dev"
|
||||
# endif
|
||||
strcpy( libraryName, "SPU2-X"
|
||||
#ifdef _DEBUG_FAST
|
||||
"-Debug"
|
||||
#elif defined( DEBUG )
|
||||
"-Debug/Strict" // strict debugging is slow!
|
||||
#else
|
||||
"-Dev"
|
||||
#endif
|
||||
);
|
||||
#else
|
||||
|
||||
// Use TortoiseSVN's SubWCRev utility's output
|
||||
// to label the specific revision:
|
||||
#else
|
||||
|
||||
sprintf_s( libraryName, "SPU2-X r%d%s"
|
||||
# ifdef _DEBUG_FAST
|
||||
"-Debug"
|
||||
# elif defined( _DEBUG )
|
||||
"-Debug/Strict" // strict debugging is slow!
|
||||
# else
|
||||
"-Dev"
|
||||
# endif
|
||||
,SVN_REV,
|
||||
SVN_MODS ? "m" : ""
|
||||
// Use TortoiseSVN's SubWCRev utility's output
|
||||
// to label the specific revision:
|
||||
|
||||
sprintf_s( libraryName, "SPU2-X r%d%s"
|
||||
#ifdef _DEBUG_FAST
|
||||
"-Debug"
|
||||
#elif defined( _DEBUG )
|
||||
"-Debug/Strict" // strict debugging is slow!
|
||||
#else
|
||||
"-Dev"
|
||||
#endif
|
||||
,SVN_REV,
|
||||
SVN_MODS ? "m" : ""
|
||||
);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_C_(u32) PS2EgetLibType()
|
||||
|
@ -309,29 +312,31 @@ bool numpad_plus = false, numpad_plus_old = false;
|
|||
|
||||
EXPORT_C_(void) SPU2async(u32 cycles)
|
||||
{
|
||||
#ifndef PUBLIC
|
||||
u32 oldClocks = lClocks;
|
||||
static u32 timer=0,time1=0,time2=0;
|
||||
timer++;
|
||||
if (timer == 1){
|
||||
time1=timeGetTime();
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (timer == 3000){
|
||||
time2 = timeGetTime()-time1 ;
|
||||
timer=0;
|
||||
}
|
||||
#endif
|
||||
|
||||
DspUpdate();
|
||||
|
||||
#ifndef PUBLIC
|
||||
/*numpad_plus = (GetAsyncKeyState(VK_ADD)&0x8000)!=0;
|
||||
if(numpad_plus && !numpad_plus_old)
|
||||
if( IsDevBuild )
|
||||
{
|
||||
DoFullDump();
|
||||
/*numpad_plus = (GetAsyncKeyState(VK_ADD)&0x8000)!=0;
|
||||
if(numpad_plus && !numpad_plus_old)
|
||||
{
|
||||
DoFullDump();
|
||||
}
|
||||
numpad_plus_old = numpad_plus;*/
|
||||
}
|
||||
numpad_plus_old = numpad_plus;*/
|
||||
#endif
|
||||
|
||||
if(hasPtr)
|
||||
{
|
||||
|
|
|
@ -438,9 +438,9 @@ void SPU2writeDMA(int core, u16* pMem, u32 size)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifndef PUBLIC
|
||||
DebugCores[core].lastsize=size;
|
||||
#endif
|
||||
if( IsDevBuild )
|
||||
DebugCores[core].lastsize = size;
|
||||
|
||||
Cores[core].TSA&=~7;
|
||||
|
||||
bool adma_enable = ((Cores[core].AutoDMACtrl&(core+1))==(core+1));
|
||||
|
|
|
@ -28,8 +28,7 @@ void ADMAOutLogWrite(void *lpData, u32 ulSize);
|
|||
|
||||
u32 core, voice;
|
||||
|
||||
static const s32 ADSR_MAX_VOL = 0x7fffffff;
|
||||
static const s32 f[5][2] =
|
||||
static const s32 tbl_XA_Factor[5][2] =
|
||||
{
|
||||
{ 0, 0 },
|
||||
{ 60, 0 },
|
||||
|
@ -38,13 +37,10 @@ static const s32 f[5][2] =
|
|||
{ 122, -60 }
|
||||
};
|
||||
|
||||
static const int InvExpOffsets[] = { 0,4,6,8,9,10,11,12 };
|
||||
static u32 PsxRates[160];
|
||||
|
||||
|
||||
// Performs a 64-bit multiplication between two values and returns the
|
||||
// high 32 bits as a result (discarding the fractional 32 bits).
|
||||
// The combined fracional bits of both inputs must be 32 bits for this
|
||||
// The combined fractional bits of both inputs must be 32 bits for this
|
||||
// to work properly.
|
||||
//
|
||||
// This is meant to be a drop-in replacement for times when the 'div' part
|
||||
|
@ -70,29 +66,12 @@ __forceinline s32 clamp_mix(s32 x, u8 bitshift)
|
|||
return GetClamped( x, -0x8000<<bitshift, 0x7fff<<bitshift );
|
||||
}
|
||||
|
||||
void InitADSR() // INIT ADSR
|
||||
{
|
||||
for (int i=0; i<(32+128); i++)
|
||||
{
|
||||
int shift=(i-32)>>2;
|
||||
s64 rate=(i&3)+4;
|
||||
if (shift<0)
|
||||
rate >>= -shift;
|
||||
else
|
||||
rate <<= shift;
|
||||
|
||||
PsxRates[i] = (int)min( rate, 0x3fffffffLL );
|
||||
}
|
||||
}
|
||||
|
||||
#define VOL(x) (((s32)x)) //24.8 volume
|
||||
|
||||
static void __forceinline XA_decode_block(s16* buffer, const s16* block, s32& prev1, s32& prev2)
|
||||
{
|
||||
const s32 header = *block;
|
||||
s32 shift = ((header>> 0)&0xF)+16;
|
||||
s32 pred1 = f[(header>> 4)&0xF][0];
|
||||
s32 pred2 = f[(header>> 4)&0xF][1];
|
||||
s32 pred1 = tbl_XA_Factor[(header>> 4)&0xF][0];
|
||||
s32 pred2 = tbl_XA_Factor[(header>> 4)&0xF][1];
|
||||
|
||||
const s8* blockbytes = (s8*)&block[1];
|
||||
|
||||
|
@ -129,8 +108,8 @@ static void __forceinline XA_decode_block_unsaturated(s16* buffer, const s16* bl
|
|||
{
|
||||
const s32 header = *block;
|
||||
s32 shift = ((header>> 0)&0xF)+16;
|
||||
s32 pred1 = f[(header>> 4)&0xF][0];
|
||||
s32 pred2 = f[(header>> 4)&0xF][1];
|
||||
s32 pred1 = tbl_XA_Factor[(header>> 4)&0xF][0];
|
||||
s32 pred2 = tbl_XA_Factor[(header>> 4)&0xF][1];
|
||||
|
||||
const s8* blockbytes = (s8*)&block[1];
|
||||
|
||||
|
@ -167,10 +146,10 @@ static void __forceinline IncrementNextA( const V_Core& thiscore, V_Voice& vc )
|
|||
{
|
||||
if( Cores[i].IRQEnable && (vc.NextA==Cores[i].IRQA ) )
|
||||
{
|
||||
#ifndef PUBLIC
|
||||
ConLog(" * SPU2 Core %d: IRQ Called (IRQ passed).\n", i);
|
||||
#endif
|
||||
Spdif.Info=4<<i;
|
||||
if( IsDevBuild )
|
||||
ConLog(" * SPU2 Core %d: IRQ Called (IRQ passed).\n", i);
|
||||
|
||||
Spdif.Info = 4 << i;
|
||||
SetIrqCall();
|
||||
}
|
||||
}
|
||||
|
@ -184,11 +163,9 @@ static void __forceinline IncrementNextA( const V_Core& thiscore, V_Voice& vc )
|
|||
// invalided when DMA transfers and memory writes are performed.
|
||||
PcmCacheEntry *pcm_cache_data = NULL;
|
||||
|
||||
#ifndef PUBLIC
|
||||
int g_counter_cache_hits=0;
|
||||
int g_counter_cache_misses=0;
|
||||
int g_counter_cache_ignores=0;
|
||||
#endif
|
||||
int g_counter_cache_hits = 0;
|
||||
int g_counter_cache_misses = 0;
|
||||
int g_counter_cache_ignores = 0;
|
||||
|
||||
#define XAFLAG_LOOP_END (1ul<<0)
|
||||
#define XAFLAG_LOOP (1ul<<1)
|
||||
|
@ -213,12 +190,12 @@ static void __forceinline __fastcall GetNextDataBuffered( V_Core& thiscore, V_Vo
|
|||
}
|
||||
else
|
||||
{
|
||||
VoiceStop(core,voice);
|
||||
thiscore.Regs.ENDX|=1<<voice;
|
||||
#ifndef PUBLIC
|
||||
if(MsgVoiceOff()) ConLog(" * SPU2: Voice Off by EndPoint: %d \n", voice);
|
||||
DebugCores[core].Voices[voice].lastStopReason = 1;
|
||||
#endif
|
||||
vc.Stop();
|
||||
if( IsDevBuild )
|
||||
{
|
||||
if(MsgVoiceOff()) ConLog(" * SPU2: Voice Off by EndPoint: %d \n", voice);
|
||||
DebugCores[core].Voices[voice].lastStopReason = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,9 +219,8 @@ static void __forceinline __fastcall GetNextDataBuffered( V_Core& thiscore, V_Vo
|
|||
|
||||
//ConLog( " * SPU2 : Cache Hit! NextA=0x%x, cacheIdx=0x%x\n", vc.NextA, cacheIdx );
|
||||
|
||||
#ifndef PUBLIC
|
||||
g_counter_cache_hits++;
|
||||
#endif
|
||||
if( IsDevBuild )
|
||||
g_counter_cache_hits++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -252,12 +228,13 @@ static void __forceinline __fastcall GetNextDataBuffered( V_Core& thiscore, V_Vo
|
|||
if( vc.NextA >= SPU2_DYN_MEMLINE )
|
||||
cacheLine.Validated = true;
|
||||
|
||||
#ifndef PUBLIC
|
||||
if( vc.NextA < SPU2_DYN_MEMLINE )
|
||||
g_counter_cache_ignores++;
|
||||
else
|
||||
g_counter_cache_misses++;
|
||||
#endif
|
||||
if( IsDevBuild )
|
||||
{
|
||||
if( vc.NextA < SPU2_DYN_MEMLINE )
|
||||
g_counter_cache_ignores++;
|
||||
else
|
||||
g_counter_cache_misses++;
|
||||
}
|
||||
|
||||
s16* sbuffer = cacheLine.Sampledata;
|
||||
|
||||
|
@ -284,166 +261,6 @@ _skipIncrement:
|
|||
Data = vc.SBuffer[vc.SCurrent++];
|
||||
}
|
||||
|
||||
// Returns the linear slide value for AR and SR inputs.
|
||||
static int GetLinearSrAr( uint SrAr )
|
||||
{
|
||||
// The Sr/Ar settings work in quarter steps, which means
|
||||
// the bottom 2 bits go on the left side of the shift, and
|
||||
// the right side of the shift gets divided by 4:
|
||||
|
||||
const uint newSr = 0x7f - SrAr;
|
||||
return ((1|(newSr&3)) << (newSr>>2));
|
||||
}
|
||||
|
||||
static void __forceinline CalculateADSR( V_Voice& vc )
|
||||
{
|
||||
V_ADSR& env(vc.ADSR);
|
||||
|
||||
jASSUME( env.Phase != 0 );
|
||||
|
||||
if(env.Releasing && (env.Phase < 5))
|
||||
env.Phase = 5;
|
||||
|
||||
switch (env.Phase)
|
||||
{
|
||||
case 1: // attack
|
||||
if( env.Value == ADSR_MAX_VOL )
|
||||
{
|
||||
// Already maxed out. Progress phase and nothing more:
|
||||
env.Phase++;
|
||||
break;
|
||||
}
|
||||
|
||||
// Case 1 below is for pseudo exponential below 75%.
|
||||
// Pseudo Exp > 75% and Linear are the same.
|
||||
|
||||
if (env.Am && (env.Value>=0x60000000))
|
||||
env.Value += PsxRates[(env.Ar^0x7f)-0x18+32];
|
||||
else //if( env.Ar < 0x7f )
|
||||
env.Value+=PsxRates[(env.Ar^0x7f)-0x10+32];
|
||||
//env.Value += GetLinearSrAr( env.Ar );
|
||||
|
||||
if( env.Value < 0 )
|
||||
{
|
||||
// We hit the ceiling.
|
||||
env.Phase++;
|
||||
env.Value = ADSR_MAX_VOL;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // decay
|
||||
{
|
||||
u32 off = InvExpOffsets[(env.Value>>28)&7];
|
||||
env.Value-=PsxRates[((env.Dr^0x1f)*4)-0x18+off+32];
|
||||
|
||||
// calculate sustain level by mirroring the bits
|
||||
// of the sustain var into the lower bits as we shift up
|
||||
// (total shift, 27 bits)
|
||||
|
||||
//s32 suslev8 = (env.Sl << 4) | env.Sl;
|
||||
//s32 suslev = (suslev8 << 8) | suslev8; // brings us to 16 bits!
|
||||
//suslev = (suslev << 8) | suslev8; // 24 bits!
|
||||
|
||||
s32 suslev = 0x7fffffff / (0x10 - env.Sl);
|
||||
|
||||
if( env.Value <= suslev )
|
||||
{
|
||||
if (env.Value < 0)
|
||||
env.Value = 0;
|
||||
env.Phase++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // sustain
|
||||
{
|
||||
// 0x7f disables sustain (infinite sustain)
|
||||
if( env.Sr == 0x7f ) return;
|
||||
|
||||
if (env.Sm&2) // decreasing
|
||||
{
|
||||
if (env.Sm&4) // exponential
|
||||
{
|
||||
u32 off = InvExpOffsets[(env.Value>>28)&7];
|
||||
env.Value-=PsxRates[(env.Sr^0x7f)-0x1b+off+32];
|
||||
}
|
||||
else // linear
|
||||
{
|
||||
env.Value-=PsxRates[(env.Sr^0x7f)-0xf+32];
|
||||
//env.Value -= GetLinearSrAr( env.Sr );
|
||||
}
|
||||
|
||||
if( env.Value <= 0 )
|
||||
{
|
||||
env.Value = 0;
|
||||
env.Phase++;
|
||||
}
|
||||
}
|
||||
else // increasing
|
||||
{
|
||||
if( (env.Sm&4) && (env.Value>=0x60000000) )
|
||||
env.Value+=PsxRates[(env.Sr^0x7f)-0x18+32];
|
||||
else
|
||||
{
|
||||
// linear / Pseudo below 75% (they're the same)
|
||||
env.Value+=PsxRates[(env.Sr^0x7f)-0x10+32];
|
||||
//env.Value += GetLinearSrAr( env.Sr );
|
||||
}
|
||||
|
||||
if( env.Value < 0 )
|
||||
{
|
||||
env.Value = ADSR_MAX_VOL;
|
||||
env.Phase++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // sustain end
|
||||
env.Value = (env.Sm&2) ? 0 : ADSR_MAX_VOL;
|
||||
if(env.Value==0)
|
||||
env.Phase=6;
|
||||
break;
|
||||
|
||||
case 5: // release
|
||||
|
||||
if (env.Rm) // exponential
|
||||
{
|
||||
u32 off=InvExpOffsets[(env.Value>>28)&7];
|
||||
env.Value-=PsxRates[((env.Rr^0x1f)*4)-0x18+off+32];
|
||||
}
|
||||
else // linear
|
||||
{
|
||||
//env.Value-=PsxRates[((env.Rr^0x1f)*4)-0xc+32];
|
||||
if( env.Rr != 0x1f )
|
||||
env.Value -= (1 << (0x1f-env.Rr));
|
||||
}
|
||||
|
||||
if( env.Value <= 0 )
|
||||
{
|
||||
env.Value=0;
|
||||
env.Phase++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: // release end
|
||||
env.Value=0;
|
||||
break;
|
||||
|
||||
jNO_DEFAULT
|
||||
}
|
||||
|
||||
if (env.Phase==6) {
|
||||
#ifndef PUBLIC
|
||||
if(MsgVoiceOff()) ConLog(" * SPU2: Voice Off by ADSR: %d \n", voice);
|
||||
DebugCores[core].Voices[voice].lastStopReason = 2;
|
||||
#endif
|
||||
VoiceStop(core,voice);
|
||||
Cores[core].Regs.ENDX|=(1<<voice);
|
||||
env.Phase=0;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
|
@ -497,27 +314,41 @@ static void __forceinline UpdatePitch( V_Voice& vc )
|
|||
vc.SP+=pitch;
|
||||
}
|
||||
|
||||
|
||||
static __forceinline void CalculateADSR( V_Core& thiscore, V_Voice& vc )
|
||||
{
|
||||
if( vc.ADSR.Phase==0 )
|
||||
{
|
||||
vc.ADSR.Value = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if( !vc.ADSR.Calculate() )
|
||||
{
|
||||
if( IsDevBuild )
|
||||
{
|
||||
if(MsgVoiceOff()) ConLog(" * SPU2: Voice Off by ADSR: %d \n", voice);
|
||||
DebugCores[core].Voices[voice].lastStopReason = 2;
|
||||
}
|
||||
vc.Stop();
|
||||
}
|
||||
|
||||
jASSUME( vc.ADSR.Value >= 0 ); // ADSR should never be negative...
|
||||
}
|
||||
|
||||
// Returns a 16 bit result in Value.
|
||||
static void __forceinline GetVoiceValues_Linear(V_Core& thiscore, V_Voice& vc, s32& Value)
|
||||
{
|
||||
while( vc.SP > 0 )
|
||||
{
|
||||
vc.PV2=vc.PV1;
|
||||
vc.PV2 = vc.PV1;
|
||||
|
||||
GetNextDataBuffered( thiscore, vc, vc.PV1 );
|
||||
|
||||
vc.SP-=4096;
|
||||
vc.SP -= 4096;
|
||||
}
|
||||
|
||||
if( vc.ADSR.Phase==0 )
|
||||
{
|
||||
Value = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
CalculateADSR( vc );
|
||||
|
||||
jASSUME( vc.ADSR.Value >= 0 ); // ADSR should never be negative...
|
||||
CalculateADSR( thiscore, vc );
|
||||
|
||||
// Note! It's very important that ADSR stay as accurate as possible. By the way
|
||||
// it is used, various sound effects can end prematurely if we truncate more than
|
||||
|
@ -549,15 +380,7 @@ static void __forceinline GetVoiceValues_Cubic(V_Core& thiscore, V_Voice& vc, s3
|
|||
vc.SP-=4096;
|
||||
}
|
||||
|
||||
if( vc.ADSR.Phase==0 )
|
||||
{
|
||||
Value = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
CalculateADSR( vc );
|
||||
|
||||
jASSUME( vc.ADSR.Value >= 0 ); // ADSR should never be negative...
|
||||
CalculateADSR( thiscore, vc );
|
||||
|
||||
s32 z0 = vc.PV3 - vc.PV4 + vc.PV1 - vc.PV2;
|
||||
s32 z1 = (vc.PV4 - vc.PV3 - z0);
|
||||
|
@ -591,7 +414,7 @@ static void __forceinline __fastcall GetNoiseValues(V_Core& thiscore, V_Voice& v
|
|||
// like GetVoiceValues can. Better assert just in case though..
|
||||
jASSUME( vc.ADSR.Phase != 0 );
|
||||
|
||||
CalculateADSR( vc );
|
||||
CalculateADSR( thiscore, vc );
|
||||
|
||||
// Yup, ADSR applies even to noise sources...
|
||||
Data = MulShr32( Data, vc.ADSR.Value );
|
||||
|
@ -649,12 +472,13 @@ void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR)
|
|||
{
|
||||
FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7');
|
||||
|
||||
#ifndef PUBLIC
|
||||
if(thiscore.InputDataLeft>0)
|
||||
if( IsDevBuild )
|
||||
{
|
||||
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
|
||||
if(thiscore.InputDataLeft>0)
|
||||
{
|
||||
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
thiscore.InputDataLeft=0;
|
||||
thiscore.DMAICounter=1;
|
||||
}
|
||||
|
@ -689,12 +513,13 @@ void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR)
|
|||
{
|
||||
FileLog("[%10d] Spdif AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7');
|
||||
|
||||
#ifndef PUBLIC
|
||||
if(thiscore.InputDataLeft>0)
|
||||
if( IsDevBuild )
|
||||
{
|
||||
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
|
||||
if(thiscore.InputDataLeft>0)
|
||||
{
|
||||
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
thiscore.InputDataLeft=0;
|
||||
thiscore.DMAICounter=1;
|
||||
}
|
||||
|
@ -741,15 +566,17 @@ void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR)
|
|||
{
|
||||
thiscore.AutoDMACtrl |= ~3;
|
||||
|
||||
#ifndef PUBLIC
|
||||
FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7');
|
||||
if(thiscore.InputDataLeft>0)
|
||||
if( IsDevBuild )
|
||||
{
|
||||
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
|
||||
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");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
thiscore.InputDataLeft=0;
|
||||
thiscore.DMAICounter=1;
|
||||
|
||||
thiscore.InputDataLeft = 0;
|
||||
thiscore.DMAICounter = 1;
|
||||
}
|
||||
}
|
||||
thiscore.InputPos&=0x1ff;
|
||||
|
@ -795,57 +622,6 @@ static void __forceinline __fastcall ReadInputPV(V_Core& thiscore, s32& ValL,s32
|
|||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
|
||||
#define VOLFLAG_REVERSE_PHASE (1ul<<0)
|
||||
#define VOLFLAG_DECREMENT (1ul<<1)
|
||||
#define VOLFLAG_EXPONENTIAL (1ul<<2)
|
||||
#define VOLFLAG_SLIDE_ENABLE (1ul<<3)
|
||||
|
||||
static void __fastcall UpdateVolume(V_Volume& Vol)
|
||||
{
|
||||
// Volume slides use the same basic logic as ADSR, but simplified (single-stage
|
||||
// instead of multi-stage)
|
||||
|
||||
if (Vol.Mode & VOLFLAG_DECREMENT)
|
||||
{
|
||||
// Decrement
|
||||
|
||||
if(Vol.Mode & VOLFLAG_EXPONENTIAL)
|
||||
{
|
||||
u32 off = InvExpOffsets[(Vol.Value>>28)&7];
|
||||
Vol.Value -= PsxRates[(Vol.Increment^0x7f)-0x1b+off+32];
|
||||
}
|
||||
else
|
||||
Vol.Value -= Vol.Increment;
|
||||
|
||||
if (Vol.Value < 0)
|
||||
{
|
||||
Vol.Value = 0;
|
||||
Vol.Mode = 0; // disable slide
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Increment
|
||||
// Pseudo-exponential increments, as done by the SPU2 (really!)
|
||||
// Above 75% slides slow, below 75% slides fast. It's exponential, pseudo'ly speaking.
|
||||
|
||||
if( (Vol.Mode & VOLFLAG_EXPONENTIAL) && (Vol.Value>=0x60000000))
|
||||
Vol.Value += PsxRates[(Vol.Increment^0x7f)-0x18+32];
|
||||
else
|
||||
Vol.Value += Vol.Increment;
|
||||
|
||||
if( Vol.Value < 0 ) // wrapped around the "top"?
|
||||
{
|
||||
Vol.Value = 0x7fffffff;
|
||||
Vol.Mode = 0; // disable slide
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
|
||||
// writes a signed value to the SPU2 ram
|
||||
// Performs no cache invalidation -- use only for dynamic memory ranges
|
||||
// of the SPU2 (between 0x0000 and SPU2_DYN_MEMLINE)
|
||||
|
@ -869,8 +645,8 @@ static __forceinline void MixVoice( V_Core& thiscore, V_Voice& vc, s32& VValL, s
|
|||
// Most games don't use much volume slide effects. So only call the UpdateVolume
|
||||
// methods when needed by checking the flag outside the method here...
|
||||
|
||||
if( vc.VolumeL.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume( vc.VolumeL );
|
||||
if( vc.VolumeR.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume( vc.VolumeR );
|
||||
vc.VolumeL.Update();
|
||||
vc.VolumeR.Update();
|
||||
|
||||
if( vc.ADSR.Phase > 0 )
|
||||
{
|
||||
|
@ -889,9 +665,8 @@ static __forceinline void MixVoice( V_Core& thiscore, V_Voice& vc, s32& VValL, s
|
|||
// Record the output (used for modulation effects)
|
||||
vc.OutX = Value;
|
||||
|
||||
#ifndef PUBLIC
|
||||
DebugCores[core].Voices[voice].displayPeak = max(DebugCores[core].Voices[voice].displayPeak,abs(Value));
|
||||
#endif
|
||||
if( IsDevBuild )
|
||||
DebugCores[core].Voices[voice].displayPeak = max(DebugCores[core].Voices[voice].displayPeak,abs(Value));
|
||||
|
||||
// TODO : Implement this using high-def MulShr32.
|
||||
// vc.VolumeL/R are 15 bits. Value should be 32 bits (but is currently 16)
|
||||
|
@ -1017,8 +792,8 @@ static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR)
|
|||
|
||||
// Apply Master Volume. The core will need this when the function returns.
|
||||
|
||||
if( thiscore.MasterL.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume(thiscore.MasterL);
|
||||
if( thiscore.MasterR.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume(thiscore.MasterR);
|
||||
thiscore.MasterL.Update();
|
||||
thiscore.MasterR.Update();
|
||||
}
|
||||
|
||||
// used to throttle the output rate of cache stat reports
|
||||
|
@ -1107,21 +882,22 @@ void Mix()
|
|||
OutPos++;
|
||||
if (OutPos>=0x200) OutPos=0;
|
||||
|
||||
#ifndef PUBLIC
|
||||
p_cachestat_counter++;
|
||||
if(p_cachestat_counter > (48000*10) )
|
||||
if( IsDevBuild )
|
||||
{
|
||||
p_cachestat_counter = 0;
|
||||
if( MsgCache() ) ConLog( " * SPU2 > CacheStats > Hits: %d Misses: %d Ignores: %d\n",
|
||||
g_counter_cache_hits,
|
||||
g_counter_cache_misses,
|
||||
g_counter_cache_ignores );
|
||||
p_cachestat_counter++;
|
||||
if(p_cachestat_counter > (48000*10) )
|
||||
{
|
||||
p_cachestat_counter = 0;
|
||||
if( MsgCache() ) ConLog( " * SPU2 > CacheStats > Hits: %d Misses: %d Ignores: %d\n",
|
||||
g_counter_cache_hits,
|
||||
g_counter_cache_misses,
|
||||
g_counter_cache_ignores );
|
||||
|
||||
g_counter_cache_hits =
|
||||
g_counter_cache_misses =
|
||||
g_counter_cache_ignores = 0;
|
||||
g_counter_cache_hits =
|
||||
g_counter_cache_misses =
|
||||
g_counter_cache_ignores = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -30,7 +30,8 @@ __forceinline void RegLog(int level, char *RName,u32 mem,u32 core,u16 value)
|
|||
|
||||
void SPU2writeLog(u32 rmem, u16 value)
|
||||
{
|
||||
#ifndef PUBLIC
|
||||
if( !IsDevBuild ) return;
|
||||
|
||||
u32 vx=0, vc=0, core=0, omem, mem;
|
||||
omem=mem=rmem & 0x7FF; //FFFF;
|
||||
if (mem & 0x400) { omem^=0x400; core=1; }
|
||||
|
@ -247,6 +248,5 @@ void SPU2writeLog(u32 rmem, u16 value)
|
|||
RegLog(2,"UNKNOWN",rmem,core,value); spu2Ru16(mem) = value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
#include "spu2.h"
|
||||
|
||||
//static LPF_data lowpass_left( 11000, SampleRate );
|
||||
//static LPF_data lowpass_right( 11000, SampleRate );
|
||||
static LPF_data lowpass_left( 11000, SampleRate );
|
||||
static LPF_data lowpass_right( 11000, SampleRate );
|
||||
|
||||
static s32 EffectsBufferIndexer( V_Core& thiscore, s32 offset )
|
||||
{
|
||||
|
@ -34,14 +34,10 @@ static s32 EffectsBufferIndexer( V_Core& thiscore, s32 offset )
|
|||
if( pos > thiscore.EffectsEndA )
|
||||
{
|
||||
pos = thiscore.EffectsStartA + ((thiscore.ReverbX + offset) % (u32)thiscore.EffectsBufferSize);
|
||||
//pos -= thiscore.EffectsEndA+1;
|
||||
//pos += thiscore.EffectsStartA;
|
||||
}
|
||||
else if( pos < thiscore.EffectsStartA )
|
||||
{
|
||||
pos = thiscore.EffectsEndA+1 - ((thiscore.ReverbX + offset) % (u32)thiscore.EffectsBufferSize );
|
||||
//pos -= thiscore.EffectsStartA;
|
||||
//pos += thiscore.EffectsEndA+1;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
@ -176,7 +172,12 @@ void DoReverb( V_Core& thiscore, s32& OutL, s32& OutR, s32 InL, s32 InR)
|
|||
_spu2mem[mix_dest_b0] = clamp_mix( (MulShr32(thiscore.Revb.FB_ALPHA<<14, ACC0) - fb_xor_a0 - ((_spu2mem[fb_src_b0] * thiscore.Revb.FB_X)>>2)) >> 14 );
|
||||
_spu2mem[mix_dest_b1] = clamp_mix( (MulShr32(thiscore.Revb.FB_ALPHA<<14, ACC1) - fb_xor_a1 - ((_spu2mem[fb_src_b1] * thiscore.Revb.FB_X)>>2)) >> 14 );
|
||||
|
||||
OutL = thiscore.LastEffectL = clamp_mix(_spu2mem[mix_dest_a0] + _spu2mem[mix_dest_b0]);
|
||||
OutR = thiscore.LastEffectR = clamp_mix(_spu2mem[mix_dest_a1] + _spu2mem[mix_dest_b1]);
|
||||
thiscore.LastEffectL = clamp_mix(_spu2mem[mix_dest_a0] + _spu2mem[mix_dest_b0]);
|
||||
thiscore.LastEffectR = clamp_mix(_spu2mem[mix_dest_a1] + _spu2mem[mix_dest_b1]);
|
||||
|
||||
//OutL = thiscore.LastEffectL;
|
||||
//OutR = thiscore.LastEffectR;
|
||||
OutL = (s32)(lowpass_left.sample( thiscore.LastEffectL / 32768.0 ) * 32768.0);
|
||||
OutR = (s32)(lowpass_right.sample( thiscore.LastEffectR / 32768.0 ) * 32768.0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,6 @@ s32 __fastcall FreezeIt( SPU2freezeData& spud )
|
|||
spud.OutPos = OutPos;
|
||||
spud.InputPos = InputPos;
|
||||
spud.Cycles = Cycles;
|
||||
spud.uTicks = uTicks;
|
||||
spud.PlayMode = PlayMode;
|
||||
|
||||
// Save our cache:
|
||||
|
@ -156,7 +155,6 @@ s32 __fastcall ThawIt( SPU2freezeData& spud )
|
|||
OutPos = spud.OutPos;
|
||||
InputPos = spud.InputPos;
|
||||
Cycles = spud.Cycles;
|
||||
uTicks = spud.uTicks;
|
||||
PlayMode = spud.PlayMode;
|
||||
|
||||
// Load the ADPCM cache:
|
||||
|
|
|
@ -51,9 +51,7 @@ u8 callirq;
|
|||
HANDLE hThreadFunc;
|
||||
u32 ThreadFuncID;
|
||||
|
||||
#ifndef PUBLIC
|
||||
V_CoreDebug DebugCores[2];
|
||||
#endif
|
||||
V_Core Cores[2];
|
||||
V_SPDIF Spdif;
|
||||
|
||||
|
@ -206,6 +204,44 @@ void V_Core::UpdateEffectsBufferSize()
|
|||
EffectsBufferSize = EffectsEndA - EffectsStartA + 1;
|
||||
}
|
||||
|
||||
void V_Voice::Start()
|
||||
{
|
||||
if((Cycles-PlayCycle)>=4)
|
||||
{
|
||||
if(StartA&7)
|
||||
{
|
||||
fprintf( stderr, " *** Misaligned StartA %05x!\n",StartA);
|
||||
StartA=(StartA+0xFFFF8)+0x8;
|
||||
}
|
||||
|
||||
ADSR.Releasing=false;
|
||||
ADSR.Value=1;
|
||||
ADSR.Phase=1;
|
||||
PlayCycle=Cycles;
|
||||
SCurrent=28;
|
||||
LoopMode=0;
|
||||
LoopFlags=0;
|
||||
LoopStartA=StartA;
|
||||
NextA=StartA;
|
||||
Prev1=0;
|
||||
Prev2=0;
|
||||
|
||||
PV1=PV2=0;
|
||||
PV3=PV4=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" *** KeyOn after less than 4 T disregarded.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void V_Voice::Stop()
|
||||
{
|
||||
ADSR.Value = 0;
|
||||
ADSR.Phase = 0;
|
||||
//Cores[core].Regs.ENDX|=(1<<vc);
|
||||
}
|
||||
|
||||
static const int TickInterval = 768;
|
||||
static const int SanityInterval = 4800;
|
||||
|
||||
|
@ -368,16 +404,16 @@ void SPU_ps1_write(u32 mem, u16 value)
|
|||
case 2: Cores[0].Voices[voice].Pitch=value; break;
|
||||
case 3: Cores[0].Voices[voice].StartA=(u32)value<<8; break;
|
||||
case 4: // ADSR1 (Envelope)
|
||||
Cores[0].Voices[voice].ADSR.Am=(value & 0x8000)>>15;
|
||||
Cores[0].Voices[voice].ADSR.Ar=(value & 0x7F00)>>8;
|
||||
Cores[0].Voices[voice].ADSR.Dr=(value & 0xF0)>>4;
|
||||
Cores[0].Voices[voice].ADSR.Sl=(value & 0xF);
|
||||
Cores[0].Voices[voice].ADSR.AttackMode=(value & 0x8000)>>15;
|
||||
Cores[0].Voices[voice].ADSR.AttackRate=(value & 0x7F00)>>8;
|
||||
Cores[0].Voices[voice].ADSR.DecayRate=(value & 0xF0)>>4;
|
||||
Cores[0].Voices[voice].ADSR.SustainLevel=(value & 0xF);
|
||||
Cores[0].Voices[voice].ADSR.Reg_ADSR1 = value; break;
|
||||
case 5: // ADSR2 (Envelope)
|
||||
Cores[0].Voices[voice].ADSR.Sm=(value & 0xE000)>>13;
|
||||
Cores[0].Voices[voice].ADSR.Sr=(value & 0x1FC0)>>6;
|
||||
Cores[0].Voices[voice].ADSR.Rm=(value & 0x20)>>5;
|
||||
Cores[0].Voices[voice].ADSR.Rr=(value & 0x1F);
|
||||
Cores[0].Voices[voice].ADSR.SustainMode=(value & 0xE000)>>13;
|
||||
Cores[0].Voices[voice].ADSR.SustainRate=(value & 0x1FC0)>>6;
|
||||
Cores[0].Voices[voice].ADSR.ReleaseMode=(value & 0x20)>>5;
|
||||
Cores[0].Voices[voice].ADSR.ReleaseRate=(value & 0x1F);
|
||||
Cores[0].Voices[voice].ADSR.Reg_ADSR2 = value; break;
|
||||
case 6:
|
||||
Cores[0].Voices[voice].ADSR.Value = ((s32)value<<16) | value;
|
||||
|
@ -614,16 +650,16 @@ __forceinline void SPU2_FastWrite( u32 rmem, u16 value )
|
|||
|
||||
case 2: thisvoice.Pitch=value; break;
|
||||
case 3: // ADSR1 (Envelope)
|
||||
thisvoice.ADSR.Am = (value & 0x8000)>>15;
|
||||
thisvoice.ADSR.Ar = (value & 0x7F00)>>8;
|
||||
thisvoice.ADSR.Dr = (value & 0xF0)>>4;
|
||||
thisvoice.ADSR.Sl = (value & 0xF);
|
||||
thisvoice.ADSR.AttackMode = (value & 0x8000)>>15;
|
||||
thisvoice.ADSR.AttackRate = (value & 0x7F00)>>8;
|
||||
thisvoice.ADSR.DecayRate = (value & 0xF0)>>4;
|
||||
thisvoice.ADSR.SustainLevel = (value & 0xF);
|
||||
thisvoice.ADSR.Reg_ADSR1 = value; break;
|
||||
case 4: // ADSR2 (Envelope)
|
||||
thisvoice.ADSR.Sm = (value & 0xE000)>>13;
|
||||
thisvoice.ADSR.Sr = (value & 0x1FC0)>>6;
|
||||
thisvoice.ADSR.Rm = (value & 0x20)>>5;
|
||||
thisvoice.ADSR.Rr = (value & 0x1F);
|
||||
thisvoice.ADSR.SustainMode = (value & 0xE000)>>13;
|
||||
thisvoice.ADSR.SustainRate = (value & 0x1FC0)>>6;
|
||||
thisvoice.ADSR.ReleaseMode = (value & 0x20)>>5;
|
||||
thisvoice.ADSR.ReleaseRate = (value & 0x1F);
|
||||
thisvoice.ADSR.Reg_ADSR2 = value; break;
|
||||
case 5:
|
||||
// [Air] : Mysterious ADSR set code. Too bad none of my games ever use it.
|
||||
|
@ -646,24 +682,35 @@ __forceinline void SPU2_FastWrite( u32 rmem, u16 value )
|
|||
|
||||
switch (address)
|
||||
{
|
||||
case 0: thisvoice.StartA = ((value & 0x0F) << 16) | (thisvoice.StartA & 0xFFF8);
|
||||
#ifndef PUBLIC
|
||||
case 0:
|
||||
thisvoice.StartA = ((value & 0x0F) << 16) | (thisvoice.StartA & 0xFFF8);
|
||||
if( IsDevBuild )
|
||||
DebugCores[core].Voices[voice].lastSetStartA = thisvoice.StartA;
|
||||
#endif
|
||||
break;
|
||||
case 1: thisvoice.StartA = (thisvoice.StartA & 0x0F0000) | (value & 0xFFF8);
|
||||
#ifndef PUBLIC
|
||||
break;
|
||||
|
||||
case 1:
|
||||
thisvoice.StartA = (thisvoice.StartA & 0x0F0000) | (value & 0xFFF8);
|
||||
if( IsDevBuild )
|
||||
DebugCores[core].Voices[voice].lastSetStartA = thisvoice.StartA;
|
||||
#endif
|
||||
break;
|
||||
case 2: thisvoice.LoopStartA = ((value & 0x0F) << 16) | (thisvoice.LoopStartA & 0xFFF8);
|
||||
thisvoice.LoopMode = 3; break;
|
||||
case 3: thisvoice.LoopStartA = (thisvoice.LoopStartA & 0x0F0000) | (value & 0xFFF8);break;
|
||||
thisvoice.LoopMode = 3; break;
|
||||
case 4: thisvoice.NextA = ((value & 0x0F) << 16) | (thisvoice.NextA & 0xFFF8);
|
||||
break;
|
||||
case 5: thisvoice.NextA = (thisvoice.NextA & 0x0F0000) | (value & 0xFFF8);
|
||||
break;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
thisvoice.LoopStartA = ((value & 0x0F) << 16) | (thisvoice.LoopStartA & 0xFFF8);
|
||||
thisvoice.LoopMode = 3;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
thisvoice.LoopStartA = (thisvoice.LoopStartA & 0x0F0000) | (value & 0xFFF8);
|
||||
thisvoice.LoopMode = 3;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
thisvoice.NextA = ((value & 0x0F) << 16) | (thisvoice.NextA & 0xFFF8);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
thisvoice.NextA = (thisvoice.NextA & 0x0F0000) | (value & 0xFFF8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if((mem>=0x07C0) && (mem<0x07CE))
|
||||
|
@ -930,60 +977,6 @@ __forceinline void SPU2_FastWrite( u32 rmem, u16 value )
|
|||
}
|
||||
|
||||
|
||||
void VoiceStart(int core,int vc)
|
||||
{
|
||||
if((Cycles-Cores[core].Voices[vc].PlayCycle)>=4)
|
||||
{
|
||||
if(Cores[core].Voices[vc].StartA&7)
|
||||
{
|
||||
fprintf( stderr, " *** Misaligned StartA %05x!\n",Cores[core].Voices[vc].StartA);
|
||||
Cores[core].Voices[vc].StartA=(Cores[core].Voices[vc].StartA+0xFFFF8)+0x8;
|
||||
}
|
||||
|
||||
Cores[core].Voices[vc].ADSR.Releasing=false;
|
||||
Cores[core].Voices[vc].ADSR.Value=1;
|
||||
Cores[core].Voices[vc].ADSR.Phase=1;
|
||||
Cores[core].Voices[vc].PlayCycle=Cycles;
|
||||
Cores[core].Voices[vc].SCurrent=28;
|
||||
Cores[core].Voices[vc].LoopMode=0;
|
||||
Cores[core].Voices[vc].LoopFlags=0;
|
||||
Cores[core].Voices[vc].LoopStartA=Cores[core].Voices[vc].StartA;
|
||||
Cores[core].Voices[vc].NextA=Cores[core].Voices[vc].StartA;
|
||||
Cores[core].Voices[vc].Prev1=0;
|
||||
Cores[core].Voices[vc].Prev2=0;
|
||||
|
||||
Cores[core].Voices[vc].PV1=Cores[core].Voices[vc].PV2=0;
|
||||
Cores[core].Voices[vc].PV3=Cores[core].Voices[vc].PV4=0;
|
||||
|
||||
Cores[core].Regs.ENDX&=~(1<<vc);
|
||||
|
||||
#ifndef PUBLIC
|
||||
DebugCores[core].Voices[vc].FirstBlock=1;
|
||||
|
||||
if(MsgKeyOnOff()) ConLog(" * SPU2: KeyOn: C%dV%02d: SSA: %8x; M: %s%s%s%s; H: %02x%02x; P: %04x V: %04x/%04x; ADSR: %04x%04x\n",
|
||||
core,vc,Cores[core].Voices[vc].StartA,
|
||||
(Cores[core].Voices[vc].DryL)?"+":"-",(Cores[core].Voices[vc].DryR)?"+":"-",
|
||||
(Cores[core].Voices[vc].WetL)?"+":"-",(Cores[core].Voices[vc].WetR)?"+":"-",
|
||||
*(u8*)GetMemPtr(Cores[core].Voices[vc].StartA),*(u8 *)GetMemPtr((Cores[core].Voices[vc].StartA)+1),
|
||||
Cores[core].Voices[vc].Pitch,
|
||||
Cores[core].Voices[vc].VolumeL.Value,Cores[core].Voices[vc].VolumeR.Value,
|
||||
Cores[core].Voices[vc].ADSR.Reg_ADSR1,Cores[core].Voices[vc].ADSR.Reg_ADSR2);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" *** KeyOn after less than 4 T disregarded.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void VoiceStop(int core,int vc)
|
||||
{
|
||||
Cores[core].Voices[vc].ADSR.Value=0;
|
||||
Cores[core].Voices[vc].ADSR.Phase=0;
|
||||
|
||||
//Cores[core].Regs.ENDX|=(1<<vc);
|
||||
}
|
||||
|
||||
void StartVoices(int core, u32 value)
|
||||
{
|
||||
// Optimization: Games like to write zero to the KeyOn reg a lot, so shortcut
|
||||
|
@ -996,7 +989,24 @@ void StartVoices(int core, u32 value)
|
|||
for( u8 vc=0; vc<24; vc++ )
|
||||
{
|
||||
if ((value>>vc) & 1)
|
||||
VoiceStart(core,vc);
|
||||
{
|
||||
Cores[core].Voices[vc].Start();
|
||||
Cores[core].Regs.ENDX &= ~( 1 << vc );
|
||||
|
||||
if( IsDevBuild )
|
||||
{
|
||||
V_Voice& thisvc( Cores[core].Voices[vc] );
|
||||
|
||||
if(MsgKeyOnOff()) ConLog(" * SPU2: KeyOn: C%dV%02d: SSA: %8x; M: %s%s%s%s; H: %02x%02x; P: %04x V: %04x/%04x; ADSR: %04x%04x\n",
|
||||
core,vc,thisvc.StartA,
|
||||
(thisvc.DryL)?"+":"-",(thisvc.DryR)?"+":"-",
|
||||
(thisvc.WetL)?"+":"-",(thisvc.WetR)?"+":"-",
|
||||
*(u8*)GetMemPtr(thisvc.StartA),*(u8 *)GetMemPtr((thisvc.StartA)+1),
|
||||
thisvc.Pitch,
|
||||
thisvc.VolumeL.Value,thisvc.VolumeR.Value,
|
||||
thisvc.ADSR.Reg_ADSR1,thisvc.ADSR.Reg_ADSR2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -142,9 +142,6 @@ extern void __inline __fastcall spu2M_Write( u32 addr, u16 value );
|
|||
#define spu2Rs16(mmem) (*(s16 *)((s8 *)spu2regs + ((mmem) & 0x1fff)))
|
||||
#define spu2Ru16(mmem) (*(u16 *)((s8 *)spu2regs + ((mmem) & 0x1fff)))
|
||||
|
||||
extern void VoiceStart(int core,int vc);
|
||||
extern void VoiceStop(int core,int vc);
|
||||
|
||||
extern u8 callirq;
|
||||
|
||||
extern void (* _irqcallback)();
|
||||
|
@ -162,8 +159,6 @@ extern int PlayMode;
|
|||
extern int recording;
|
||||
extern bool disableFreezes;
|
||||
|
||||
|
||||
extern s32 uTicks;
|
||||
extern u32 lClocks;
|
||||
extern u32* cPtr;
|
||||
extern bool hasPtr;
|
||||
|
@ -192,7 +187,7 @@ extern void RecordWrite(s16 left, s16 right);
|
|||
extern void UpdateSpdifMode();
|
||||
extern void LowPassFilterInit();
|
||||
extern void InitADSR();
|
||||
extern void SndUpdateLimitMode();
|
||||
extern void CalculateADSR( V_Voice& vc );
|
||||
|
||||
//////////////////////////////
|
||||
// The Mixer Section //
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace WaveDump
|
|||
|
||||
void Open()
|
||||
{
|
||||
#ifndef PUBLIC
|
||||
if( !IsDevBuild ) return;
|
||||
if( !WaveLog() ) return;
|
||||
|
||||
char wavfilename[256];
|
||||
|
@ -69,12 +69,11 @@ namespace WaveDump
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
#ifndef PUBLIC
|
||||
if( !IsDevBuild ) return;
|
||||
for( uint cidx=0; cidx<2; cidx++ )
|
||||
{
|
||||
for( int srcidx=0; srcidx<CoreSrc_Count; srcidx++ )
|
||||
|
@ -82,18 +81,16 @@ namespace WaveDump
|
|||
SAFE_DELETE_OBJ( m_CoreWav[cidx][srcidx] );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void WriteCore( uint coreidx, CoreSourceType src, s16 left, s16 right )
|
||||
{
|
||||
#ifndef PUBLIC
|
||||
if( !IsDevBuild ) return;
|
||||
if( m_CoreWav[coreidx][src] != NULL )
|
||||
{
|
||||
s16 buffer[2] = { left, right };
|
||||
m_CoreWav[coreidx][src]->write( buffer, 2 );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,12 +36,12 @@ static LRESULT WINAPI AboutProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
|||
ConvertStaticToHyperlink( hDlg, IDC_LINK_WEBSITE );
|
||||
|
||||
wchar_t outstr[256];
|
||||
#ifdef PUBLIC
|
||||
swprintf_s( outstr, _T("Release v%d.%d -- Compiled on ") _T(__DATE__),
|
||||
VersionInfo::Release, VersionInfo::Revision );
|
||||
#else
|
||||
swprintf_s( outstr, _T("Build r%d -- Compiled on ") _T(__DATE__), SVN_REV );
|
||||
#endif
|
||||
if( IsDevBuild )
|
||||
swprintf_s( outstr, _T("Build r%d -- Compiled on ") _T(__DATE__), SVN_REV );
|
||||
else
|
||||
swprintf_s( outstr, _T("Release v%d.%d -- Compiled on ") _T(__DATE__),
|
||||
VersionInfo::Release, VersionInfo::Revision );
|
||||
|
||||
SetWindowText( GetDlgItem(hDlg, IDC_LABEL_VERSION_INFO), outstr );
|
||||
ShowWindow( hDlg, true );
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "spu2.h"
|
||||
#include "dialogs.h"
|
||||
|
||||
#ifndef PUBLIC
|
||||
#ifdef SPU2X_DEVBUILD
|
||||
static const int LATENCY_MAX = 3000;
|
||||
#else
|
||||
static const int LATENCY_MAX = 750;
|
||||
|
|
|
@ -132,13 +132,8 @@ void EnableControls( HWND hWnd )
|
|||
{
|
||||
EnableMessages( hWnd );
|
||||
ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled);
|
||||
#ifdef PUBLIC
|
||||
ENABLE_CONTROL(IDC_LOGREGS, false);
|
||||
ENABLE_CONTROL(IDC_LOGWAVE, false);
|
||||
#else
|
||||
ENABLE_CONTROL(IDC_LOGREGS, DebugEnabled);
|
||||
ENABLE_CONTROL(IDC_LOGWAVE, DebugEnabled);
|
||||
#endif
|
||||
ENABLE_CONTROL(IDC_LOGREGS, IsDevBuild ? DebugEnabled : false);
|
||||
ENABLE_CONTROL(IDC_LOGWAVE, IsDevBuild ? DebugEnabled : false);
|
||||
ENABLE_CONTROL(IDC_DUMPCORE,DebugEnabled);
|
||||
ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled);
|
||||
ENABLE_CONTROL(IDC_DUMPREGS,DebugEnabled);
|
||||
|
@ -174,11 +169,7 @@ static BOOL CALLBACK DialogProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
|||
SET_CHECK(IDC_DUMPMEM, _MemDump);
|
||||
SET_CHECK(IDC_DUMPREGS,_RegDump);
|
||||
|
||||
#ifdef PUBLIC
|
||||
ShowWindow( GetDlgItem( hWnd, IDC_MSG_PUBLIC_BUILD ), true );
|
||||
#else
|
||||
ShowWindow( GetDlgItem( hWnd, IDC_MSG_PUBLIC_BUILD ), false );
|
||||
#endif
|
||||
ShowWindow( GetDlgItem( hWnd, IDC_MSG_PUBLIC_BUILD ), !IsDevBuild );
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ static BOOL CALLBACK DebugProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
#ifndef PUBLIC
|
||||
#ifdef SPU2X_DEVBUILD
|
||||
|
||||
int FillRectangle(HDC dc, int left, int top, int width, int height)
|
||||
{
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
EnableFiberSafeOptimizations="true"
|
||||
PreprocessorDefinitions="FLOAT_SAMPLES;NDEBUG;_USRDLL"
|
||||
PreprocessorDefinitions="SPU2X_DEVBUILD;FLOAT_SAMPLES;NDEBUG;_USRDLL"
|
||||
StringPooling="true"
|
||||
RuntimeLibrary="0"
|
||||
StructMemberAlignment="5"
|
||||
|
@ -148,7 +148,7 @@
|
|||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="FLOAT_SAMPLES;_DEBUG;_USRDLL"
|
||||
PreprocessorDefinitions="SPU2X_DEVBUILD;FLOAT_SAMPLES;_DEBUG;_USRDLL"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
|
@ -245,7 +245,7 @@
|
|||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
EnableFiberSafeOptimizations="true"
|
||||
PreprocessorDefinitions="FLOAT_SAMPLES;NDEBUG;PUBLIC;_USRDLL"
|
||||
PreprocessorDefinitions="FLOAT_SAMPLES;NDEBUG;_USRDLL"
|
||||
StringPooling="true"
|
||||
RuntimeLibrary="0"
|
||||
StructMemberAlignment="5"
|
||||
|
@ -344,7 +344,7 @@
|
|||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="FLOAT_SAMPLES;_DEBUG_FAST;_DEBUG;_USRDLL"
|
||||
PreprocessorDefinitions="SPU2X_DEVBUILD;FLOAT_SAMPLES;_DEBUG_FAST;_DEBUG;_USRDLL"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
|
@ -727,6 +727,10 @@
|
|||
<Filter
|
||||
Name="SPU2"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\ADSR.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\defs.h"
|
||||
>
|
||||
|
|
|
@ -31,6 +31,9 @@ struct V_Volume
|
|||
s32 Value;
|
||||
s8 Increment;
|
||||
s8 Mode;
|
||||
|
||||
public:
|
||||
void Update();
|
||||
};
|
||||
|
||||
struct V_ADSR
|
||||
|
@ -38,29 +41,22 @@ struct V_ADSR
|
|||
u16 Reg_ADSR1;
|
||||
u16 Reg_ADSR2;
|
||||
|
||||
//also Reg_ENVX
|
||||
s32 Value; // Ranges from 0 to 0x7fffffff (signed values are clamped to 0)
|
||||
// Phase
|
||||
s32 Value; // Ranges from 0 to 0x7fffffff (signed values are clamped to 0) [Reg_ENVX]
|
||||
u8 Phase;
|
||||
//Attack Rate
|
||||
u8 Ar;
|
||||
//Attack Mode
|
||||
u8 Am;
|
||||
//Decay Rate
|
||||
u8 Dr;
|
||||
//Sustain Level
|
||||
u8 Sl;
|
||||
//Sustain Rate
|
||||
u8 Sr;
|
||||
//Sustain Mode
|
||||
u8 Sm;
|
||||
//Release Rate
|
||||
u8 Rr;
|
||||
//Release Mode
|
||||
u8 Rm;
|
||||
u8 AttackRate; // Ar
|
||||
u8 AttackMode; // Am
|
||||
u8 DecayRate; // Dr
|
||||
u8 SustainLevel; // Sl
|
||||
u8 SustainRate; // Sr
|
||||
u8 SustainMode; // Sm
|
||||
u8 ReleaseRate; // Rr
|
||||
u8 ReleaseMode; // Rm
|
||||
|
||||
//Ready To Release
|
||||
bool Releasing;
|
||||
bool Releasing; // Ready To Release, triggered by Voice.Stop();
|
||||
|
||||
|
||||
public:
|
||||
bool Calculate();
|
||||
};
|
||||
|
||||
|
||||
|
@ -133,9 +129,10 @@ struct V_Voice
|
|||
// sample position within the current decoded packet.
|
||||
s32 SCurrent;
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
};
|
||||
|
||||
#ifndef PUBLIC
|
||||
// ** Begin Debug-only variables section **
|
||||
// Separated from the V_Voice struct to improve cache performance of
|
||||
// the Public Release build.
|
||||
|
@ -158,7 +155,6 @@ struct V_CoreDebug
|
|||
|
||||
// Debug tracking information - 24 voices and 2 cores.
|
||||
extern V_CoreDebug DebugCores[2];
|
||||
#endif
|
||||
|
||||
struct V_Reverb
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue