SPU2ghz: Significant overhaul of the volume system! Volumes for most games should be much more accurate now, and distortion greatly reduced. This is still a work-in-progress, and I intend to follow up with another commit soon that should improve performance in a few areas, improve overall audio quality and (hopefully!) fix up the Special Effects system as well.

Pcsx2: This time the Pg icon really has been replaced/reverted to the original (dunno why my last attempt didn't commit, oh well).  Also improved the syntax of the SourceLogs; fixing if/else statement scoping problems.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@470 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-02-11 07:20:14 +00:00
parent 9ee9d817c4
commit d5bc5099d1
13 changed files with 508 additions and 527 deletions

View File

@ -78,72 +78,72 @@ extern u32 varLog;
void SourceLog( u16 protocol, u8 source, u32 cpuPc, u32 cpuCycle, const char *fmt, ...);
void __Log( const char* fmt, ... );
extern void SrcLog_CPU( const char* fmt, ... );
extern void SrcLog_COP0( const char* fmt, ... );
extern void SrcLog_FPU( const char* fmt, ... );
extern void SrcLog_MMI( const char* fmt, ... );
extern bool SrcLog_CPU( const char* fmt, ... );
extern bool SrcLog_COP0( const char* fmt, ... );
extern bool SrcLog_FPU( const char* fmt, ... );
extern bool SrcLog_MMI( const char* fmt, ... );
extern void SrcLog_MEM( const char* fmt, ... );
extern void SrcLog_HW( const char* fmt, ... );
extern void SrcLog_DMA( const char* fmt, ... );
extern void SrcLog_BIOS( const char* fmt, ... );
extern void SrcLog_ELF( const char* fmt, ... );
extern void SrcLog_VU0( const char* fmt, ... );
extern bool SrcLog_MEM( const char* fmt, ... );
extern bool SrcLog_HW( const char* fmt, ... );
extern bool SrcLog_DMA( const char* fmt, ... );
extern bool SrcLog_BIOS( const char* fmt, ... );
extern bool SrcLog_ELF( const char* fmt, ... );
extern bool SrcLog_VU0( const char* fmt, ... );
extern void SrcLog_VIF( const char* fmt, ... );
extern void SrcLog_SPR( const char* fmt, ... );
extern void SrcLog_GIF( const char* fmt, ... );
extern void SrcLog_SIF( const char* fmt, ... );
extern void SrcLog_IPU( const char* fmt, ... );
extern void SrcLog_VUM( const char* fmt, ... );
extern void SrcLog_RPC( const char* fmt, ... );
extern void SrcLog_EECNT( const char* fmt, ... );
extern bool SrcLog_VIF( const char* fmt, ... );
extern bool SrcLog_SPR( const char* fmt, ... );
extern bool SrcLog_GIF( const char* fmt, ... );
extern bool SrcLog_SIF( const char* fmt, ... );
extern bool SrcLog_IPU( const char* fmt, ... );
extern bool SrcLog_VUM( const char* fmt, ... );
extern bool SrcLog_RPC( const char* fmt, ... );
extern bool SrcLog_EECNT( const char* fmt, ... );
extern void SrcLog_PSXCPU( const char* fmt, ... );
extern void SrcLog_PSXMEM( const char* fmt, ... );
extern void SrcLog_PSXHW( const char* fmt, ... );
extern void SrcLog_PSXBIOS( const char* fmt, ... );
extern void SrcLog_PSXDMA( const char* fmt, ... );
extern void SrcLog_PSXCNT( const char* fmt, ... );
extern bool SrcLog_PSXCPU( const char* fmt, ... );
extern bool SrcLog_PSXMEM( const char* fmt, ... );
extern bool SrcLog_PSXHW( const char* fmt, ... );
extern bool SrcLog_PSXBIOS( const char* fmt, ... );
extern bool SrcLog_PSXDMA( const char* fmt, ... );
extern bool SrcLog_PSXCNT( const char* fmt, ... );
extern void SrcLog_MEMCARDS( const char* fmt, ... );
extern void SrcLog_PAD( const char* fmt, ... );
extern void SrcLog_GTE( const char* fmt, ... );
extern void SrcLog_CDR( const char* fmt, ... );
extern void SrcLog_GPU( const char* fmt, ... );
extern bool SrcLog_MEMCARDS( const char* fmt, ... );
extern bool SrcLog_PAD( const char* fmt, ... );
extern bool SrcLog_GTE( const char* fmt, ... );
extern bool SrcLog_CDR( const char* fmt, ... );
extern bool SrcLog_GPU( const char* fmt, ... );
#define CPU_LOG if (varLog & 0x00000001) SrcLog_CPU
#define MEM_LOG if (varLog & 0x00000002) SrcLog_MEM
#define HW_LOG if (varLog & 0x00000004) SrcLog_HW
#define DMA_LOG if (varLog & 0x00000008) SrcLog_DMA
#define BIOS_LOG if (varLog & 0x00000010) SrcLog_BIOS
#define ELF_LOG if (varLog & 0x00000020) SrcLog_ELF
#define FPU_LOG if (varLog & 0x00000040) SrcLog_FPU
#define MMI_LOG if (varLog & 0x00000080) SrcLog_MMI
#define VU0_LOG if (varLog & 0x00000100) SrcLog_VU0
#define COP0_LOG if (varLog & 0x00000200) SrcLog_COP0
#define VIF_LOG if (varLog & 0x00000400) SrcLog_VIF
#define SPR_LOG if (varLog & 0x00000800) SrcLog_SPR
#define GIF_LOG if (varLog & 0x00001000) SrcLog_GIF
#define SIF_LOG if (varLog & 0x00002000) SrcLog_SIF
#define IPU_LOG if (varLog & 0x00004000) SrcLog_IPU
#define VUM_LOG if (varLog & 0x00008000) SrcLog_VUM
#define RPC_LOG if (varLog & 0x00010000) SrcLog_RPC
#define EECNT_LOG if (varLog & 0x40000000) SrcLog_EECNT
#define CPU_LOG (varLog & 0x00000001) && SrcLog_CPU
#define MEM_LOG (varLog & 0x00000002) && SrcLog_MEM
#define HW_LOG (varLog & 0x00000004) && SrcLog_HW
#define DMA_LOG (varLog & 0x00000008) && SrcLog_DMA
#define BIOS_LOG (varLog & 0x00000010) && SrcLog_BIOS
#define ELF_LOG (varLog & 0x00000020) && SrcLog_ELF
#define FPU_LOG (varLog & 0x00000040) && SrcLog_FPU
#define MMI_LOG (varLog & 0x00000080) && SrcLog_MMI
#define VU0_LOG (varLog & 0x00000100) && SrcLog_VU0
#define COP0_LOG (varLog & 0x00000200) && SrcLog_COP0
#define VIF_LOG (varLog & 0x00000400) && SrcLog_VIF
#define SPR_LOG (varLog & 0x00000800) && SrcLog_SPR
#define GIF_LOG (varLog & 0x00001000) && SrcLog_GIF
#define SIF_LOG (varLog & 0x00002000) && SrcLog_SIF
#define IPU_LOG (varLog & 0x00004000) && SrcLog_IPU
#define VUM_LOG (varLog & 0x00008000) && SrcLog_VUM
#define RPC_LOG (varLog & 0x00010000) && SrcLog_RPC
#define EECNT_LOG (varLog & 0x40000000) && SrcLog_EECNT
#define PSXCPU_LOG if (varLog & 0x00100000) SrcLog_PSXCPU
#define PSXMEM_LOG if (varLog & 0x00200000) SrcLog_PSXMEM
#define PSXHW_LOG if (varLog & 0x00400000) SrcLog_PSXHW
#define PSXBIOS_LOG if (varLog & 0x00800000) SrcLog_PSXBIOS
#define PSXDMA_LOG if (varLog & 0x01000000) SrcLog_PSXDMA
#define PSXCNT_LOG if (varLog & 0x20000000) SrcLog_PSXCNT
#define PSXCPU_LOG (varLog & 0x00100000) && SrcLog_PSXCPU
#define PSXMEM_LOG (varLog & 0x00200000) && SrcLog_PSXMEM
#define PSXHW_LOG (varLog & 0x00400000) && SrcLog_PSXHW
#define PSXBIOS_LOG (varLog & 0x00800000) && SrcLog_PSXBIOS
#define PSXDMA_LOG (varLog & 0x01000000) && SrcLog_PSXDMA
#define PSXCNT_LOG (varLog & 0x20000000) && SrcLog_PSXCNT
//memcard has the same number as PAD_LOG for now
#define MEMCARDS_LOG if (varLog & 0x02000000) SrcLog_MEMCARDS
#define PAD_LOG if (varLog & 0x02000000) SrcLog_PAD
#define GTE_LOG if (varLog & 0x04000000) SrcLog_GTE
#define CDR_LOG if (varLog & 0x08000000) SrcLog_CDR
#define GPU_LOG if (varLog & 0x10000000) SrcLog_GPU
#define MEMCARDS_LOG (varLog & 0x02000000) && SrcLog_MEMCARDS
#define PAD_LOG (varLog & 0x02000000) && SrcLog_PAD
#define GTE_LOG (varLog & 0x04000000) && SrcLog_GTE
#define CDR_LOG (varLog & 0x08000000) && SrcLog_CDR
#define GPU_LOG (varLog & 0x10000000) && SrcLog_GPU
// fixme - currently we don't log cache
#define CACHE_LOG 0&&

View File

@ -67,6 +67,7 @@ u8 sio_xor(u8 *buf, uint length){
void sioInit()
{
memzero_obj(sio);
memzero_obj(m_PostSavestateCards);
// Transfer(?) Ready and the Buffer is Empty
sio.StatReg = TX_RDY | TX_EMPTY;

View File

@ -129,7 +129,7 @@ void SourceLog( u16 protocol, u8 source, u32 cpuPc, u32 cpuCycle, const char *fm
// Functions with variable argument lists can't be inlined.
#define IMPLEMENT_SOURCE_LOG( unit, source, protocol ) \
void SrcLog_##unit( const char* fmt, ... ) \
bool SrcLog_##unit( const char* fmt, ... ) \
{ \
va_list list; \
va_start( list, fmt ); \
@ -137,6 +137,7 @@ void SourceLog( u16 protocol, u8 source, u32 cpuPc, u32 cpuCycle, const char *fm
(source == 'E') ? cpuRegs.pc : psxRegs.pc, \
(source == 'E') ? cpuRegs.cycle : psxRegs.cycle, fmt, list ); \
va_end( list ); \
return false; \
} \
IMPLEMENT_SOURCE_LOG( EECNT, 'E', 0 )

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -26,11 +26,42 @@ void ConLog(const char *fmt, ...);
void DoFullDump();
extern int wavedump_ok;
namespace WaveDump
{
enum CoreSourceType
{
// Core's input stream, usually pulled from ADMA streams.
CoreSrc_Input = 0
int wavedump_open();
void wavedump_close();
void wavedump_write(s16 left,s16 right);
// Output of the actual 24 input voices which have dry output enabled.
, CoreSrc_DryVoiceMix
// Output of the actual 24 input voices that have wet output enabled.
, CoreSrc_WetVoiceMix
// Wet mix including inputs and externals, prior to the application of reverb.
, CoreSrc_PreReverb
// Wet mix after reverb has turned it into a pile of garbly gook.
, CoreSrc_PostReverb
// Final output of the core. For core 0, it's the feed into Core1.
// For Core1, it's the feed into SndOut.
, CoreSrc_External
, CoreSrc_Count
};
void Open();
void Close();
void WriteCore( uint coreidx, CoreSourceType src, s16 left, s16 right );
}
using WaveDump::CoreSrc_Input;
using WaveDump::CoreSrc_DryVoiceMix;
using WaveDump::CoreSrc_WetVoiceMix;
using WaveDump::CoreSrc_PreReverb;
using WaveDump::CoreSrc_PostReverb;
using WaveDump::CoreSrc_External;
#endif // DEBUG_H_INCLUDED //

View File

@ -180,14 +180,6 @@ EXPORT_C_(s32) SPU2init()
DMALogOpen();
if(WaveLog())
{
if(!wavedump_open())
{
SysMessage("Can't open '%s'.\nWave Log disabled.",WaveLogFileName);
}
}
for(v=0;v<16384;v++)
{
logvolume[v]=(s32)(s32)floor(log((double)(v+1))*3376.7);
@ -237,6 +229,8 @@ EXPORT_C_(s32) SPU2open(void *pDsp)
DspLoadLibrary(dspPlugin,dspPluginModule);
WaveDump::Open();
return 0;
}
else
@ -280,7 +274,7 @@ EXPORT_C_(void) SPU2shutdown()
fclose(el0);
fclose(el1);
#endif
if(WaveLog() && wavedump_ok) wavedump_close();
WaveDump::Close();
DMALogClose();
@ -452,18 +446,9 @@ EXPORT_C_(int) SPU2setupRecording(int start, void* pData)
if( disableFreezes ) return 0;
if(start==0)
{
//stop recording
RecordStop();
if(recording==0)
return 1;
}
else if(start==1)
{
//start recording
RecordStart();
if(recording!=0)
return 1;
}
return 0;
}

View File

@ -25,11 +25,17 @@
//
#include "spu2.h"
#include <assert.h>
#include <math.h>
#include <float.h>
#include "lowpass.h"
#undef min
#undef max
#include <algorithm>
using std::min;
using std::max;
extern void spdif_update();
void ADMAOutLogWrite(void *lpData, u32 ulSize);
@ -39,19 +45,54 @@ extern void VoiceStop(int core,int vc);
double pow_2_31 = pow(2.0,31.0);
LPF_data L,R;
extern u32 core;
u32 core, voice;
extern u8 callirq;
double srate_pv=1.0;
extern u32 PsxRates[160];
static const s32 ADSR_MAX_VOL = 0x7fffffff;
static const s32 f[5][2] =
{
{ 0, 0 },
{ 60, 0 },
{ 115, -52 },
{ 98, -55 },
{ 122, -60 }
};
static const int InvExpOffsets[] = { 0,4,6,8,9,10,11,12 };
static u32 PsxRates[160];
/*=
{
//for +Lin: PsxRates[value+8]
//for -Lin: PsxRates[value+7]
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xD744FCCB,0xB504F334,0x9837F052,0x80000000,0x6BA27E65,0x5A82799A,0x4C1BF829,0x40000000,
0x35D13F33,0x2D413CCD,0x260DFC14,0x20000000,0x1AE89F99,0x16A09E66,0x1306FE0A,0x10000000,
0x0D744FCD,0x0B504F33,0x09837F05,0x08000000,0x06BA27E6,0x05A8279A,0x04C1BF83,0x04000000,
0x035D13F3,0x02D413CD,0x0260DFC1,0x02000000,0x01AE89FA,0x016A09E6,0x01306FE1,0x01000000,
0x00D744FD,0x00B504F3,0x009837F0,0x00800000,0x006BA27E,0x005A827A,0x004C1BF8,0x00400000,
0x0035D13F,0x002D413D,0x00260DFC,0x00200000,0x001AE8A0,0x0016A09E,0x001306FE,0x00100000,
0x000D7450,0x000B504F,0x0009837F,0x00080000,0x0006BA28,0x0005A828,0x0004C1C0,0x00040000,
0x00035D14,0x0002D414,0x000260E0,0x00020000,0x0001AE8A,0x00016A0A,0x00013070,0x00010000,
0x0000D745,0x0000B505,0x00009838,0x00008000,0x00006BA2,0x00005A82,0x00004C1C,0x00004000,
0x000035D1,0x00002D41,0x0000260E,0x00002000,0x00001AE9,0x000016A1,0x00001307,0x00001000,
0x00000D74,0x00000B50,0x00000983,0x00000800,0x000006BA,0x000005A8,0x000004C2,0x00000400,
0x0000035D,0x000002D4,0x00000261,0x00000200,0x000001AF,0x0000016A,0x00000130,0x00000100,
0x000000D7,0x000000B5,0x00000098,0x00000080,0x0000006C,0x0000005B,0x0000004C,0x00000040,
0x00000036,0x0000002D,0x00000026,0x00000020,0x0000001B,0x00000017,0x00000013,0x00000010,
0x0000000D,0x0000000B,0x0000000A,0x00000008,0x00000007,0x00000006,0x00000005,0x00000004,
0x00000003,0x00000003,0x00000002,0x00000002,0x00000002,0x00000001,0x00000001,0x00000000,
//128+8
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
};*/
// 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
@ -93,22 +134,12 @@ void InitADSR() // INIT ADSR
else
rate <<= shift;
PsxRates[i]=(int)min(rate,0x3fffffff);
PsxRates[i] = (int)min( rate, 0x3fffffffLL );
}
}
#define VOL(x) (((s32)x)) //24.8 volume
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// //
const s32 f[5][2] ={{ 0, 0 },
{ 60, 0 },
{ 115, -52 },
{ 98, -55 },
{ 122, -60 }};
static void __forceinline XA_decode_block(s16* buffer, const s16* block, s32& prev1, s32& prev2)
{
const s32 header = *block;
@ -306,11 +337,16 @@ _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 int InvExpOffsets[] = { 0,4,6,8,9,10,11,12 };
const uint newSr = 0x127 - SrAr;
return (1+(newSr&3)) << (30UL-(newSr>>2));
}
static void __forceinline CalculateADSR( V_Voice& vc )
{
@ -318,17 +354,8 @@ static void __forceinline CalculateADSR( V_Voice& vc )
jASSUME( env.Phase != 0 );
s32 SLevel = ((s32)env.Sl)<<27;
jASSUME( SLevel >= 0 );
if(env.Releasing)
{
if( env.Phase < 5)
{
if(env.Releasing && (env.Phase < 5))
env.Phase = 5;
}
}
switch (env.Phase)
{
@ -340,21 +367,14 @@ static void __forceinline CalculateADSR( V_Voice& vc )
break;
}
if (env.Am) // pseudo exponential
{
if (env.Value<0x60000000) // below 75%
{
env.Value+=PsxRates[(env.Ar^0x7f)-0x10+32];
}
else // above 75%
{
// 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 // linear
{
env.Value+=PsxRates[(env.Ar^0x7f)-0x10+32];
}
else if( env.Ar < 0x7f )
//env.Value+=PsxRates[(env.Ar^0x7f)-0x10+32];
env.Value += GetLinearSrAr( env.Ar );
if( env.Value < 0 )
{
@ -362,29 +382,37 @@ static void __forceinline CalculateADSR( V_Voice& vc )
env.Phase++;
env.Value = ADSR_MAX_VOL;
}
break;
case 2: // decay
{
u32 off = InvExpOffsets[(env.Value>>28)&7];
env.Value-=PsxRates[((env.Dr^0x1f)<<2)-0x18+off+32];
env.Value-=PsxRates[((env.Dr^0x1f)*4)-0x18+off+32];
if(env.Value <= SLevel)
{
// Clamp decay to SLevel or Zero
if (env.Value < 0)
env.Value = 0;
else
env.Value = SLevel;
{
// calculate sustain level by mirroring the bits
// of the sustain var into the lower bits as we shift up
// (total shift, 27 bits)
u32 suslev = (env.Sl << 4) | env.Sl;
suslev = (suslev << 8) | suslev; // brings us to 12 bits!
suslev = (suslev << 12) | suslev; // 24 bits!
if( env.Value <= (suslev<<3) )
env.Phase++;
}
break;
}
break;
case 3: // sustain
{
// 0x7f disables sustain (infinite sustain)
if( env.Sr == 0x7f ) return;
if (env.Sm&2) // decreasing
{
if (env.Sm&4) // exponential
@ -394,8 +422,10 @@ static void __forceinline CalculateADSR( V_Voice& vc )
}
else // linear
{
env.Value-=PsxRates[(env.Sr^0x7f)-0xf+32];
//env.Value-=PsxRates[(env.Sr^0x7f)-0xf+32];
env.Value -= GetLinearSrAr( env.Sr );
}
if( env.Value <= 0 )
{
env.Value = 0;
@ -404,22 +434,15 @@ static void __forceinline CalculateADSR( V_Voice& vc )
}
else // increasing
{
if (env.Sm&4) // pseudo exponential
{
if (env.Value<0x60000000) // below 75%
{
env.Value+=PsxRates[(env.Sr^0x7f)-0x10+32];
}
else // above 75%
{
if( (env.Sm&4) && (env.Value>=0x60000000) )
env.Value+=PsxRates[(env.Sr^0x7f)-0x18+32];
}
}
else
{
// linear
// linear / Pseudo below 75% (they're the same)
//env.Value+=PsxRates[(env.Sr^0x7f)-0x10+32];
env.Value+=PsxRates[(env.Sr^0x7f)-0x10+32];
int newSr = 0x7f-env.Sr;
env.Value += GetLinearSrAr( env.Sr );
}
if( env.Value < 0 )
@ -428,7 +451,7 @@ static void __forceinline CalculateADSR( V_Voice& vc )
env.Phase++;
}
}
}
break;
case 4: // sustain end
@ -442,11 +465,13 @@ static void __forceinline CalculateADSR( V_Voice& vc )
if (env.Rm) // exponential
{
u32 off=InvExpOffsets[(env.Value>>28)&7];
env.Value-=PsxRates[((env.Rr^0x1f)<<2)-0x18+off+32];
env.Value-=PsxRates[((env.Rr^0x1f)*4)-0x18+off+32];
}
else // linear
{
env.Value-=PsxRates[((env.Rr^0x1f)<<2)-0xc+32];
//env.Value-=PsxRates[((env.Rr^0x1f)*4)-0xc+32];
if( env.Rr != 0x1f )
env.Value -= 1 << (30UL-env.Rr);
}
if( env.Value <= 0 )
@ -454,7 +479,6 @@ static void __forceinline CalculateADSR( V_Voice& vc )
env.Value=0;
env.Phase++;
}
break;
case 6: // release end
@ -515,12 +539,11 @@ void LowPass(s32& VL, s32& VR)
VR = (s32)(LPF(&R,(VR)/pow_2_31)*pow_2_31);
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// //
// Data is expected to be 16 bit signed (typical stuff!).
// Volume is the SPU2 register value, usually ranged from 0 to 0x7fff.
static __forceinline s32 ApplyVolume(s32 data, s32 volume)
{
return (volume * data) >> 7; // >> 6 is more correct, but causes a few overflows
return (volume * data) >> 15;
}
static void __forceinline UpdatePitch( V_Voice& vc )
@ -539,6 +562,7 @@ static void __forceinline UpdatePitch( V_Voice& vc )
vc.SP+=pitch;
}
// Returns a 16 bit result in Value.
static void __forceinline GetVoiceValues_Linear(V_Core& thiscore, V_Voice& vc, s32& Value)
{
while( vc.SP > 0 )
@ -560,19 +584,22 @@ static void __forceinline GetVoiceValues_Linear(V_Core& thiscore, V_Voice& vc, s
jASSUME( vc.ADSR.Value >= 0 ); // ADSR should never be negative...
// Note! It's very important that ADSR stay as accurate as possible. By the way
// it is used, various sound effects can end prematurely if we truncate more than
// one or two bits.
if(Interpolation==0)
{
Value = MulShr32( vc.PV1, vc.ADSR.Value );
Value = MulShr32( vc.PV1<<1, vc.ADSR.Value );
}
else //if(Interpolation==1) //must be linear
{
s32 t0 = vc.PV2 - vc.PV1;
s32 t1 = vc.PV1;
Value = MulShr32( t1 - ((t0*vc.SP)>>12), vc.ADSR.Value );
Value = MulShr32( (vc.PV1<<1) - ((t0*vc.SP)>>11), vc.ADSR.Value );
}
}
// Returns a 16 bit result in Value.
static void __forceinline GetVoiceValues_Cubic(V_Core& thiscore, V_Voice& vc, s32& Value)
{
while( vc.SP > 0 )
@ -582,7 +609,7 @@ static void __forceinline GetVoiceValues_Cubic(V_Core& thiscore, V_Voice& vc, s3
vc.PV2=vc.PV1;
GetNextDataBuffered( thiscore, vc, vc.PV1 );
vc.PV1<<=3;
vc.PV1<<=2;
vc.SPc = vc.SP&4095; // just the fractional part, please!
vc.SP-=4096;
}
@ -608,11 +635,15 @@ static void __forceinline GetVoiceValues_Cubic(V_Core& thiscore, V_Voice& vc, s3
val = ((val + z2) * mu) >> 12;
val += vc.PV2;
Value = MulShr32( val, vc.ADSR.Value>>3 );
// Note! It's very important that ADSR stay as accurate as possible. By the way
// it is used, various sound effects can end prematurely if we truncate more than
// one or two bits.
Value = MulShr32( val, vc.ADSR.Value>>1 );
}
// [Air]: Noise values need to be mixed without going through interpolation, since it
// can wreak havoc on the noise (causing muffling or popping).
// Noise values need to be mixed without going through interpolation, since it
// can wreak havoc on the noise (causing muffling or popping). Not that this noise
// generator is accurate in its own right.. but eh, ah well :)
static void __forceinline __fastcall GetNoiseValues(V_Core& thiscore, V_Voice& vc, s32& Data)
{
while(vc.SP>=4096)
@ -622,10 +653,13 @@ static void __forceinline __fastcall GetNoiseValues(V_Core& thiscore, V_Voice& v
}
// GetNoiseValues can't set the phase zero on us unexpectedly
// like GetVoiceValues can. Better asster just in case though..
// like GetVoiceValues can. Better assert just in case though..
jASSUME( vc.ADSR.Phase != 0 );
CalculateADSR( vc );
// Yup, ADSR applies even to noise sources...
Data = MulShr32( Data, vc.ADSR.Value );
}
/////////////////////////////////////////////////////////////////////////////////////////
@ -643,6 +677,10 @@ void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR)
thiscore.InputPos&=~1;
// CDDA mode
// Source audio data is 32 bits.
// We don't yet have the capability to handle this high res input data
// so we just downgrade it to 16 bits for now.
#ifdef PCM24_S1_INTERLEAVE
*PDataL=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1))));
*PDataR=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)+2)));
@ -653,8 +691,8 @@ void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR)
PDataR=*pr;
#endif
PDataL>>=4; //give 16.8 data
PDataR>>=4;
PDataL>>=1; //give 31 bit data (SndOut downsamples the rest of the way)
PDataR>>=1;
thiscore.InputPos+=2;
if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) {
@ -821,11 +859,6 @@ static void __forceinline __fastcall ReadInputPV(V_Core& thiscore, s32& ValL,s32
// Apply volumes:
ValL = ApplyVolume( ValL, thiscore.InpL );
ValR = ApplyVolume( ValR, thiscore.InpR );
// These make XS2 intro too quiet.
//ValL >>= 1;
//ValR >>= 1;
}
/////////////////////////////////////////////////////////////////////////////////////////
@ -839,23 +872,10 @@ static void __forceinline __fastcall ReadInputPV(V_Core& thiscore, s32& ValL,s32
static void __fastcall UpdateVolume(V_Volume& Vol)
{
// TIMINGS ARE FAKE!!! Need to investigate.
// TODO : Vol.Value should be a 32 bit internal value, same as ADSR.
// [Air]: Cleaned up this code... may have broken it. Can't really
// test it here since none of my games seem to use it. If anything's
// not sounding right, we should revert the code in this method first.
// [Air] Reverse phasing?
// Invert our value so that exponential mathematics are applied
// as if the volume were sliding the other direction. This makes
// a lot more sense than the old method's likeliness to chop off
// sound volumes to zero abruptly.
if(Vol.Mode & VOLFLAG_REVERSE_PHASE)
{
ConLog( " *** SPU2 > Reverse Phase in progress!\n" );
Vol.Value = 0x7fff - Vol.Value;
}
// Volume slides use the same basic logic as ADSR, but simplified (single-stage
// instead of multi-stage)
if (Vol.Mode & VOLFLAG_DECREMENT)
{
@ -863,14 +883,11 @@ static void __fastcall UpdateVolume(V_Volume& Vol)
if(Vol.Mode & VOLFLAG_EXPONENTIAL)
{
ConLog( " *** SPU2 > Exponential Volume Slide Down!\n" );
Vol.Value *= Vol.Increment >> 7;
Vol.Value-=((32768*5)>>(Vol.Increment));
u32 off = InvExpOffsets[(Vol.Value>>12)&7];
Vol.Value -= PsxRates[(Vol.Increment^0x7f)-0x1b+off+32] >> 16;
}
else
{
Vol.Value -= Vol.Increment;
}
if (Vol.Value < 0)
{
@ -880,31 +897,21 @@ static void __fastcall UpdateVolume(V_Volume& Vol)
}
else
{
//ConLog( " *** SPU2 > Volflag > Increment!\n" );
// Increment
if(Vol.Mode & VOLFLAG_EXPONENTIAL)
{
ConLog( " *** SPU2 > Exponential Volume Slide Up!\n" );
int T = Vol.Increment>>(Vol.Value>>12);
Vol.Value+=T;
}
else
{
Vol.Value+=Vol.Increment;
}
// Pseudo-exponential increments, as done by the SPU2 (really!)
// Above 75% slides slow, below 75% slides fast. It's exponential, pseudoly speaking.
if( Vol.Value > 0x7fff )
if( (Vol.Mode & VOLFLAG_EXPONENTIAL) && (Vol.Value>=0x6000))
Vol.Value += PsxRates[(Vol.Increment^0x7f)-0x18+32] >> 16;
else
Vol.Value += Vol.Increment;
if( Vol.Value < 0 ) // wrapped around the "top"?
{
Vol.Value = 0x7fff;
Vol.Mode = 0; // disable slide
}
}
// Reverse phasing
// Invert the value back into output form:
if(Vol.Mode & VOLFLAG_REVERSE_PHASE) Vol.Value = 0x7fff-Vol.Value;
//Vol.Value=NVal;
}
/////////////////////////////////////////////////////////////////////////////////////////
@ -1025,9 +1032,8 @@ static __forceinline void MixVoice( V_Core& thiscore, V_Voice& vc, s32& VValL, s
VValL = 0;
VValR = 0;
// [Air] : 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...
// 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 );
@ -1053,12 +1059,17 @@ static __forceinline void MixVoice( V_Core& thiscore, V_Voice& vc, s32& VValL, s
DebugCores[core].Voices[voice].displayPeak = max(DebugCores[core].Voices[voice].displayPeak,abs(Value));
#endif
VValL=ApplyVolume(Value,(vc.VolumeL.Value));
VValR=ApplyVolume(Value,(vc.VolumeR.Value));
// TODO : Implement this using high-def MulShr32.
// vc.VolumeL/R are 15 bits. Value should be 32 bits (but is currently 16)
VValL = ApplyVolume(Value,vc.VolumeL.Value);
VValR = ApplyVolume(Value,vc.VolumeR.Value);
}
if (voice==1) spu2M_WriteFast( 0x400 + (core<<12) + OutPos, (s16)Value );
else if (voice==3) spu2M_WriteFast( 0x600 + (core<<12) + OutPos, (s16)Value );
// Write-back of raw voice data (post ADSR applied)
if (voice==1) spu2M_WriteFast( 0x400 + (core<<12) + OutPos, (s16)Value>>3 );
else if (voice==3) spu2M_WriteFast( 0x600 + (core<<12) + OutPos, (s16)Value>>3 );
}
@ -1078,22 +1089,35 @@ static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR)
V_Voice& vc( thiscore.Voices[voice] );
MixVoice( thiscore, vc, VValL, VValR );
// Note: Results from MixVoice are ranged at 16 bits.
// Following muls are toggles only (0 or 1)
SDL += VValL * vc.DryL;
SDR += VValR * vc.DryR;
SWL += VValL * vc.WetL;
SWR += VValR * vc.WetR;
}
//Write To Output Area
spu2M_WriteFast( 0x1000 + (core<<12) + OutPos, (s16)(SDL>>16) );
spu2M_WriteFast( 0x1200 + (core<<12) + OutPos, (s16)(SDR>>16) );
spu2M_WriteFast( 0x1400 + (core<<12) + OutPos, (s16)(SWL>>16) );
spu2M_WriteFast( 0x1600 + (core<<12) + OutPos, (s16)(SWR>>16) );
// Saturate final result to standard 16 bit range.
SDL = min( max( SDL, -0x8000 ), 0x7fff );
SDR = min( max( SDR, -0x8000 ), 0x7fff );
SWL = min( max( SWL, -0x8000 ), 0x7fff );
SWR = min( max( SWR, -0x8000 ), 0x7fff );
// Write Mixed results To Output Area
spu2M_WriteFast( 0x1000 + (core<<12) + OutPos, (s16)SDL );
spu2M_WriteFast( 0x1200 + (core<<12) + OutPos, (s16)SDR );
spu2M_WriteFast( 0x1400 + (core<<12) + OutPos, (s16)SWL );
spu2M_WriteFast( 0x1600 + (core<<12) + OutPos, (s16)SWR );
// Write mixed results to logfile (if enabled)
WaveDump::WriteCore( core, CoreSrc_DryVoiceMix, SDL, SDR );
WaveDump::WriteCore( core, CoreSrc_WetVoiceMix, SWL, SWR );
s32 TDL,TDR;
// Mix in the Input data
// divide by 3 fixes some volume problems.
TDL = OutL * thiscore.InpDryL;
TDR = OutR * thiscore.InpDryR;
@ -1107,7 +1131,7 @@ static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR)
if(EffectsEnabled)
{
s32 TWL=0,TWR=0;
s32 TWL,TWR;
// Mix Input, Voice, and External data:
TWL = OutL * thiscore.InpWetL;
@ -1117,12 +1141,16 @@ static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR)
TWL += ExtL * thiscore.ExtWetL;
TWR += ExtR * thiscore.ExtWetR;
WaveDump::WriteCore( core, CoreSrc_PreReverb, TWL, TWR );
//Apply Effects
DoReverb( thiscore, RVL,RVR,TWL>>16,TWR>>16);
DoReverb( thiscore, RVL, RVR, TWL, TWR );
TWL = ApplyVolume(RVL,VOL(thiscore.FxL));
TWR = ApplyVolume(RVR,VOL(thiscore.FxR));
WaveDump::WriteCore( core, CoreSrc_PostReverb, TWL, TWR );
//Mix Wet,Dry
OutL = (TDL + TWL);
OutR = (TDR + TWR);
@ -1139,8 +1167,11 @@ static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR)
if (thiscore.Mute==0)
{
OutL = MulShr32( OutL, ((s32)thiscore.MasterL.Value)<<16 );
OutR = MulShr32( OutR, ((s32)thiscore.MasterR.Value)<<16 );
// Final output value -- We don't use ApplyVolume sot hat we can leave the 15 bits of
// fixed point accuracy in place for SoundTouch and other post processing.
OutL = OutL * thiscore.MasterL.Value;
OutR = OutR * thiscore.MasterR.Value;
}
else
{
@ -1159,10 +1190,11 @@ void __fastcall Mix()
// **** CORE ZERO ****
core=0;
if( (PlayMode&4) != 4 )
if( (PlayMode&4) == 0 )
{
// get input data from input buffers
ReadInputPV(Cores[0], ExtL, ExtR);
WaveDump::WriteCore( 0, CoreSrc_Input, ExtL, ExtR );
}
MixCore( ExtL, ExtR, 0, 0 );
@ -1174,10 +1206,16 @@ void __fastcall Mix()
}
// Commit Core 0 output to ram before mixing Core 1:
ExtL>>=14;
ExtR>>=14;
spu2M_WriteFast( 0x800 + OutPos, ExtL>>3 );
spu2M_WriteFast( 0xA00 + OutPos, ExtR>>3 );
ExtL>>=15;
ExtR>>=15;
ExtL = min( max( ExtL, -0x8000 ), 0x7fff );
ExtR = min( max( ExtR, -0x8000 ), 0x7fff );
spu2M_WriteFast( 0x800 + OutPos, ExtL );
spu2M_WriteFast( 0xA00 + OutPos, ExtR );
WaveDump::WriteCore( 0, CoreSrc_External, ExtL, ExtR );
// **** CORE ONE ****
@ -1185,15 +1223,20 @@ void __fastcall Mix()
if( (PlayMode&8) != 8 )
{
ReadInputPV(Cores[1], OutL, OutR); // get input data from input buffers
WaveDump::WriteCore( 1, CoreSrc_Input, OutL, OutR );
}
// Apply volume to the external (Core 0) input data.
MixCore( OutL, OutR, ExtL*Cores[1].ExtL, ExtR*Cores[1].ExtR );
MixCore( OutL, OutR, ApplyVolume( ExtL, Cores[1].ExtL), ApplyVolume( ExtR, Cores[1].ExtR) );
if( PlayMode & 8 )
{
// Experimental CDDA support
// The CDDA overrides all other mixer output. It's a direct feed!
ReadInput(Cores[1], OutL, OutR);
//WaveLog::WriteCore( 1, "CDDA-32", OutL, OutR );
}
#ifndef PUBLIC
@ -1206,12 +1249,13 @@ void __fastcall Mix()
// Update spdif (called each sample)
if(PlayMode&4)
{
spdif_update();
}
OutL >>= 6;
OutR >>= 6;
// AddToBuffer
SndWrite(OutL, OutR); //ExtL,ExtR);
SndWrite(OutL, OutR);
OutPos++;
if (OutPos>=0x200) OutPos=0;
@ -1233,36 +1277,6 @@ void __fastcall Mix()
#endif
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// //
u32 PsxRates[160]={
//for +Lin: PsxRates[value+8]
//for -Lin: PsxRates[value+7]
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xD744FCCB,0xB504F334,0x9837F052,0x80000000,0x6BA27E65,0x5A82799A,0x4C1BF829,0x40000000,
0x35D13F33,0x2D413CCD,0x260DFC14,0x20000000,0x1AE89F99,0x16A09E66,0x1306FE0A,0x10000000,
0x0D744FCD,0x0B504F33,0x09837F05,0x08000000,0x06BA27E6,0x05A8279A,0x04C1BF83,0x04000000,
0x035D13F3,0x02D413CD,0x0260DFC1,0x02000000,0x01AE89FA,0x016A09E6,0x01306FE1,0x01000000,
0x00D744FD,0x00B504F3,0x009837F0,0x00800000,0x006BA27E,0x005A827A,0x004C1BF8,0x00400000,
0x0035D13F,0x002D413D,0x00260DFC,0x00200000,0x001AE8A0,0x0016A09E,0x001306FE,0x00100000,
0x000D7450,0x000B504F,0x0009837F,0x00080000,0x0006BA28,0x0005A828,0x0004C1C0,0x00040000,
0x00035D14,0x0002D414,0x000260E0,0x00020000,0x0001AE8A,0x00016A0A,0x00013070,0x00010000,
0x0000D745,0x0000B505,0x00009838,0x00008000,0x00006BA2,0x00005A82,0x00004C1C,0x00004000,
0x000035D1,0x00002D41,0x0000260E,0x00002000,0x00001AE9,0x000016A1,0x00001307,0x00001000,
0x00000D74,0x00000B50,0x00000983,0x00000800,0x000006BA,0x000005A8,0x000004C2,0x00000400,
0x0000035D,0x000002D4,0x00000261,0x00000200,0x000001AF,0x0000016A,0x00000130,0x00000100,
0x000000D7,0x000000B5,0x00000098,0x00000080,0x0000006C,0x0000005B,0x0000004C,0x00000040,
0x00000036,0x0000002D,0x00000026,0x00000020,0x0000001B,0x00000017,0x00000013,0x00000010,
0x0000000D,0x0000000B,0x0000000A,0x00000008,0x00000007,0x00000006,0x00000005,0x00000004,
0x00000003,0x00000003,0x00000002,0x00000002,0x00000002,0x00000001,0x00000001,0x00000000,
//128+8
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
};
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// //

View File

@ -131,7 +131,7 @@ EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data)
{
printf("\n*** SPU2Ghz Warning:\n");
printf("\tSavestate version is from an older version of this plugin.\n");
printf("\tAudio may not recover correctly.");
printf("\tAudio may not recover correctly.\n\n");
const PcmCacheEntry* pcmSrc = &spud->cacheData;
int blksLoaded=0;

View File

@ -693,14 +693,11 @@ void SndUpdateLimitMode()
s32 SndWrite(s32 ValL, s32 ValR)
{
// Log final output to wavefile.
#ifndef PUBLIC
if(WaveLog() && wavedump_ok)
{
wavedump_write(SndScaleVol(ValL),SndScaleVol(ValR));
}
WaveDump::WriteCore( 1, CoreSrc_External, SndScaleVol(ValL), SndScaleVol(ValR) );
#endif
if(recording!=0)
RecordWrite(SndScaleVol(ValL),SndScaleVol(ValR));
if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p

View File

@ -23,7 +23,7 @@
// SndOut.
static const int SndOutPacketSize = 1024;
static const int SndOutVolumeShiftBase = 8;
static const int SndOutVolumeShiftBase = 10;
extern int SndOutVolumeShift;
#define pcmlog

View File

@ -155,10 +155,7 @@ void AssignVolume(V_Volume& vol, s16 value)
else {
vol.Mode=0;
vol.Increment=0;
value<<=1;
vol.Value=value;
vol.Value=value<<1;
}
}
@ -173,10 +170,10 @@ void CoreReset(int c)
Cores[c].Regs.STATX=0;
Cores[c].Regs.ATTR=0;
Cores[c].ExtL=0x3FFF;
Cores[c].ExtR=0x3FFF;
Cores[c].InpL=0x3FFF;
Cores[c].InpR=0x3FFF;
Cores[c].ExtL=0x7FFF;
Cores[c].ExtR=0x7FFF;
Cores[c].InpL=0x7FFF;
Cores[c].InpR=0x7FFF;
Cores[c].FxL=0x7FFF;
Cores[c].FxR=0x7FFF;
Cores[c].MasterL.Reg_VOL=0x3FFF;
@ -519,7 +516,8 @@ void UpdateSpdifMode()
}
if(OPM!=PlayMode)
{
ConLog(" * SPU2: Play Mode Set to %s (%d).\n",(PlayMode==0)?"Normal":((PlayMode==1)?"PCM Clone":((PlayMode==2)?"PCM Bypass":"BitStream Bypass")),PlayMode);
ConLog(" * SPU2: Play Mode Set to %s (%d).\n",
(PlayMode==0) ? "Normal" : ((PlayMode==1) ? "PCM Clone" : ((PlayMode==2) ? "PCM Bypass" : "BitStream Bypass")),PlayMode);
}
}
@ -748,19 +746,24 @@ void SPU2writeLog(u32 rmem, u16 value)
omem=mem=rmem & 0x7FF; //FFFF;
if (mem & 0x400) { omem^=0x400; core=1; }
/*
if ((omem >= 0x0000) && (omem < 0x0180)) { // Voice Params
u32 voice=(omem & 0x1F0) >> 4;
u32 param=(omem & 0xF)>>1;
FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Param %s) value %x\n",Cycles,rmem,core,voice,ParamNames[param],value);
if( omem < 0x0180 ) // Voice Params (VP)
{
const u32 voice = (omem & 0x1F0) >> 4;
const u32 param = (omem & 0xF) >> 1;
char dest[192];
sprintf( dest, "Voice %d %s", voice,ParamNames[param] );
RegLog( 2, dest, rmem, core, value );
}
else if ((omem >= 0x01C0) && (omem < 0x02DE)) {
u32 voice =((omem-0x01C0) / 12);
u32 address =((omem-0x01C0) % 12)>>1;
FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Address %s) value %x\n",Cycles,rmem,core,voice,AddressNames[address],value);
else if ((omem >= 0x01C0) && (omem < 0x02DE)) // Voice Addressing Params (VA)
{
const u32 voice = ((omem-0x01C0) / 12);
const u32 address = ((omem-0x01C0) % 12)>>1;
char dest[192];
sprintf( dest, "Voice %d %s", voice, AddressNames[address] );
RegLog( 2, dest, rmem, core, value );
}
*/
if ((mem >= 0x0760) && (mem < 0x07b0))
else if ((mem >= 0x0760) && (mem < 0x07b0))
{
omem=mem; core=0;
if (mem >= 0x0788) {omem-=0x28; core=1;}
@ -869,16 +872,16 @@ void SPU2writeLog(u32 rmem, u16 value)
RegLog(2,"IRQAL",rmem,core,value);
break;
case (REG_S_KON + 2):
RegLog(2,"KON1",rmem,core,value);
RegLog(1,"KON1",rmem,core,value);
break;
case REG_S_KON:
RegLog(2,"KON0",rmem,core,value);
RegLog(1,"KON0",rmem,core,value);
break;
case (REG_S_KOFF + 2):
RegLog(2,"KOFF1",rmem,core,value);
RegLog(1,"KOFF1",rmem,core,value);
break;
case REG_S_KOFF:
RegLog(2,"KOFF0",rmem,core,value);
RegLog(1,"KOFF0",rmem,core,value);
break;
case REG_A_TSA:
RegLog(2,"TSAH",rmem,core,value);
@ -973,35 +976,31 @@ __forceinline void SPU2_FastWrite( u32 rmem, u16 value )
switch (param)
{
case 0: //VOLL (Volume L)
case 1: //VOLR (Volume R)
{
V_Volume& thisvol = (param==0) ? Cores[core].Voices[voice].VolumeL : Cores[core].Voices[voice].VolumeR;
if (value & 0x8000) // +Lin/-Lin/+Exp/-Exp
{
Cores[core].Voices[voice].VolumeL.Mode=(value & 0xF000)>>12;
Cores[core].Voices[voice].VolumeL.Increment=(value & 0x3F);
thisvol.Mode=(value & 0xF000)>>12;
thisvol.Increment=(value & 0x3F);
}
else
{
Cores[core].Voices[voice].VolumeL.Mode=0;
Cores[core].Voices[voice].VolumeL.Increment=0;
// Constant Volume mode (no slides or envelopes)
// Volumes range from 0x3fff to -0x4000. Values below zero invert the waveform (unimplemented)
thisvol.Mode=0;
thisvol.Increment=0;
s16 newval = value & 0x3fff;
if( value & 0x4000 )
value=0x3fff - (value&0x3fff);
Cores[core].Voices[voice].VolumeL.Value=value<<1;
newval = 0x3fff - newval;
thisvol.Value = newval<<1;
}
thisvol.Reg_VOL = value;
}
Cores[core].Voices[voice].VolumeL.Reg_VOL = value;
break;
case 1: //VOLR (Volume R)
if (value & 0x8000)
{
Cores[core].Voices[voice].VolumeR.Mode=(value & 0xF000)>>12;
Cores[core].Voices[voice].VolumeR.Increment=(value & 0x3F);
}
else
{
Cores[core].Voices[voice].VolumeR.Mode=0;
Cores[core].Voices[voice].VolumeR.Increment=0;
Cores[core].Voices[voice].VolumeR.Value=value<<1;
}
Cores[core].Voices[voice].VolumeR.Reg_VOL = value; break;
case 2: Cores[core].Voices[voice].Pitch=value; break;
case 3: // ADSR1 (Envelope)
Cores[core].Voices[voice].ADSR.Am=(value & 0x8000)>>15;
@ -1021,6 +1020,7 @@ __forceinline void SPU2_FastWrite( u32 rmem, u16 value )
Cores[core].Voices[voice].ADSR.Value = value << 15;
ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value );
break;
case 6: Cores[core].Voices[voice].VolumeL.Value=value; break;
case 7: Cores[core].Voices[voice].VolumeR.Value=value; break;
@ -1214,29 +1214,55 @@ __forceinline void SPU2_FastWrite( u32 rmem, u16 value )
return;
case REG_P_MVOLL:
if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp
Cores[core].MasterL.Mode=(value & 0xE000)/0x2000;
Cores[core].MasterL.Increment=(value & 0x3F) | ((value & 0x800)/0x10);
case REG_P_MVOLR:
{
V_Volume& thisvol = (omem==REG_P_MVOLL) ? Cores[core].MasterL : Cores[core].MasterR;
if( value & 0x8000 ) // +Lin/-Lin/+Exp/-Exp
{
thisvol.Mode = (value & 0xE000) / 0x2000;
thisvol.Increment = (value & 0x7F); // | ((value & 0x800)/0x10);
}
else {
Cores[core].MasterL.Mode=0;
Cores[core].MasterL.Increment=0;
Cores[core].MasterL.Value=value;
else
{
thisvol.Mode = 0;
thisvol.Increment = 0;
// Constant Volume mode (no slides or envelopes)
// Volumes range from 0x3fff to -0x4000. Values below zero invert the waveform (unimplemented)
s16 newval = value & 0x3fff;
if( value & 0x4000 )
newval = 0x3fff - newval;
thisvol.Value = newval<<1;
}
thisvol.Reg_VOL = value;
}
Cores[core].MasterL.Reg_VOL=value;
return;
case REG_P_MVOLR:
if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp
Cores[core].MasterR.Mode=(value & 0xE000)/0x2000;
Cores[core].MasterR.Increment=(value & 0x3F) | ((value & 0x800)/0x10);
}
else {
Cores[core].MasterR.Mode=0;
Cores[core].MasterR.Increment=0;
Cores[core].MasterR.Value=value;
}
Cores[core].MasterR.Reg_VOL=value;
case REG_P_EVOLL:
Cores[core].FxL = ( value & 0x8000 ) ? -value : value;
return;
case REG_P_EVOLR:
Cores[core].FxR = ( value & 0x8000 ) ? -value : value;
return;
case REG_P_AVOLL:
Cores[core].ExtL = ( value & 0x8000 ) ? -value : value;
return;
case REG_P_AVOLR:
Cores[core].ExtR = ( value & 0x8000 ) ? -value : value;
return;
case REG_P_BVOLL:
Cores[core].InpL = ( value & 0x8000 ) ? -value : value;
return;
case REG_P_BVOLR:
Cores[core].InpR = ( value & 0x8000 ) ? -value : value;
return;
case REG_S_ADMAS:

View File

@ -135,7 +135,7 @@ default: \
#ifndef SAFE_DELETE_ARRAY
# define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
#endif
#ifndef SAFE_DELETE
#ifndef SAFE_DELETE_OBJ
# define SAFE_DELETE_OBJ(p) { if(p) { delete (p); (p)=NULL; } }
#endif
#ifndef SAFE_RELEASE

View File

@ -16,181 +16,107 @@
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#include <stdexcept>
#include <new>
#include "spu2.h"
#include <stdio.h>
#define WAVONLY
#include "SoundTouch/WavFile.h"
typedef struct {
//Main Header
char riffID[4];
long riffSize;
char riffTYPE[4];
//Format Tag
char chunkID[4];
long chunkSize;
short wFormatTag;
unsigned short wChannels;
unsigned long dwSamplesPerSec;
unsigned long dwAvgBytesPerSec;
unsigned short wBlockAlign;
unsigned short wBitsPerSample;
//Data Tag
char dataID[4];
long dataSize;
} WAVEHeader;
int wavedump_ok=0;
int datasize;
FILE *fdump;
#ifndef WAVONLY
int flacdump_open();
void flacdump_close();
void flacdump_write(s16 left,s16 right);
int oggvdump_open();
void oggvdump_close();
void oggvdump_write(s16 left,s16 right);
#endif
int wavedump_open()
static WavOutFile* _new_WavOutFile( const char* destfile )
{
#ifndef WAVONLY
if(WaveDumpFormat==1) return flacdump_open();
if(WaveDumpFormat==2) return oggvdump_open();
#endif
fdump=fopen(WaveLogFileName,"wb");
if(fdump==NULL) return 0;
fseek(fdump,sizeof(WAVEHeader),SEEK_SET);
datasize=0;
wavedump_ok=1;
return 1;
return new WavOutFile( destfile, 48000, 16, 2 );
}
void wavedump_flush()
namespace WaveDump
{
WAVEHeader w;
static WavOutFile* m_CoreWav[2][CoreSrc_Count] = { NULL };
memcpy(w.riffID,"RIFF",4);
w.riffSize=datasize+36;
memcpy(w.riffTYPE,"WAVE",4);
memcpy(w.chunkID,"fmt ",4);
w.chunkSize=0x10;
w.wFormatTag=1;
w.wChannels=2;
w.dwSamplesPerSec=48000;
w.dwAvgBytesPerSec=48000*4;
w.wBlockAlign=4;
w.wBitsPerSample=16;
memcpy(w.dataID,"data",4);
w.dataSize=datasize;
static const char* m_tbl_CoreOutputTypeNames[CoreSrc_Count] =
{
"Input",
"DryVoiceMix",
"WetVoiceMix",
"PreReverb",
"PostReverb",
"External"
};
fseek(fdump,0,SEEK_SET);
fwrite(&w,sizeof(w),1,fdump);
void Open()
{
if( !WaveLog() ) return;
fseek(fdump,datasize+sizeof(w),SEEK_SET);
char wavfilename[256];
for( uint cidx=0; cidx<2; cidx++ )
{
for( int srcidx=0; srcidx<CoreSrc_Count; srcidx++ )
{
SAFE_DELETE_OBJ( m_CoreWav[cidx][srcidx] );
sprintf( wavfilename, "logs\\spu2ghz-Core%d-%s.wav",
cidx, m_tbl_CoreOutputTypeNames[ srcidx ] );
try
{
m_CoreWav[cidx][srcidx] = _new_WavOutFile( wavfilename );
}
catch( std::runtime_error& ex )
{
printf( "SPU2ghz > %s.\n\tWave Log for this core source disabled.", ex.what() );
m_CoreWav[cidx][srcidx] = NULL;
}
}
}
}
void wavedump_close()
void Close()
{
if(!wavedump_ok) return;
wavedump_flush();
#ifndef WAVONLY
if(WaveDumpFormat==1) { flacdump_close(); return;}
if(WaveDumpFormat==2) { oggvdump_close(); return;}
#endif
fclose(fdump);
wavedump_ok=0;
for( uint cidx=0; cidx<2; cidx++ )
{
for( int srcidx=0; srcidx<CoreSrc_Count; srcidx++ )
{
SAFE_DELETE_OBJ( m_CoreWav[cidx][srcidx] );
}
}
}
void wavedump_write(s16 left,s16 right)
void WriteCore( uint coreidx, CoreSourceType src, s16 left, s16 right )
{
if( m_CoreWav[coreidx][src] != NULL )
{
s16 buffer[2] = { left, right };
if(!wavedump_ok) return;
#ifndef WAVONLY
if(WaveDumpFormat==1) return flacdump_write(left,right);
if(WaveDumpFormat==2) return oggvdump_write(left,right);
#endif
datasize+=4;
fwrite(buffer,4,1,fdump);
if((datasize&1023)==0)
wavedump_flush();
m_CoreWav[coreidx][src]->write( buffer, 2 );
}
}
}
FILE *recordFile;
int recordSize;
int recording;
WavOutFile* m_wavrecord = NULL;
void RecordStart()
{
if(recording&&recordFile)
fclose(recordFile);
SAFE_DELETE_OBJ( m_wavrecord );
recordFile=fopen("recording.wav","wb");
if(recordFile==NULL) return;
fseek(recordFile,sizeof(WAVEHeader),SEEK_SET);
recordSize=0;
recording=1;
}
void RecordFlush()
try
{
WAVEHeader w;
memcpy(w.riffID,"RIFF",4);
w.riffSize=recordSize+36;
memcpy(w.riffTYPE,"WAVE",4);
memcpy(w.chunkID,"fmt ",4);
w.chunkSize=0x10;
w.wFormatTag=1;
w.wChannels=2;
w.dwSamplesPerSec=48000;
w.dwAvgBytesPerSec=48000*4;
w.wBlockAlign=4;
w.wBitsPerSample=16;
memcpy(w.dataID,"data",4);
w.dataSize=recordSize;
fseek(recordFile,0,SEEK_SET);
fwrite(&w,sizeof(w),1,recordFile);
fseek(recordFile,recordSize+sizeof(w),SEEK_SET);
m_wavrecord = new WavOutFile( "recording.wav", 48000, 16, 2 );
}
catch( std::runtime_error& )
{
SysMessage("SPU2ghz couldn't open file for recording: %s.\nRecording to wavfile disabled.", "recording.wav");
m_wavrecord = NULL;
}
}
void RecordStop()
{
if(!recording)
return;
recording=0;
RecordFlush();
fclose(recordFile);
SAFE_DELETE_OBJ( m_wavrecord );
}
void RecordWrite(s16 left, s16 right)
{
if(!recording)
return;
if( m_wavrecord == NULL ) return;
s16 buffer[2] = { left, right };
recordSize+=4;
fwrite(buffer,4,1,recordFile);
if((recordSize&1023)==0)
RecordFlush();
m_wavrecord->write( buffer, 2 );
}