mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
9ee9d817c4
commit
d5bc5099d1
|
@ -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&&
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 |
|
@ -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 //
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue