clang-format spu2x

Note: it doesn't play well with define around forceinline (might need to fix the inline btw)
And a single macro in RegTable.cpp
This commit is contained in:
Clang Format 2016-10-10 20:35:26 +02:00 committed by Gregory Hainaut
parent 0f022da98c
commit 039573b133
59 changed files with 10023 additions and 10027 deletions

View File

@ -19,219 +19,201 @@
static const s32 ADSR_MAX_VOL = 0x7fffffff;
static const int InvExpOffsets[] = { 0,4,6,8,9,10,11,12 };
static const int InvExpOffsets[] = {0, 4, 6, 8, 9, 10, 11, 12};
static u32 PsxRates[160];
void InitADSR() // INIT ADSR
void InitADSR() // INIT ADSR
{
for (int i=0; i<(32+128); i++)
{
int shift=(i-32)>>2;
s64 rate=(i&3)+4;
if (shift<0)
rate >>= -shift;
else
rate <<= shift;
for (int i = 0; i < (32 + 128); i++) {
int shift = (i - 32) >> 2;
s64 rate = (i & 3) + 4;
if (shift < 0)
rate >>= -shift;
else
rate <<= shift;
PsxRates[i] = (int)std::min( rate, (s64)0x3fffffffLL );
}
PsxRates[i] = (int)std::min(rate, (s64)0x3fffffffLL);
}
}
// Returns the linear slide value for AR and SR inputs.
// (currently not used, it's buggy)
static int GetLinearSrAr( uint SrAr )
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:
// The Sr/Ar settings work in quarter steps, which means
// the bottom 2 bits go on the left side of the shift, and
// the right side of the shift gets divided by 4:
const uint newSr = 0x7f - SrAr;
return ((1|(newSr&3)) << (newSr>>2));
const uint newSr = 0x7f - SrAr;
return ((1 | (newSr & 3)) << (newSr >> 2));
}
bool V_ADSR::Calculate()
{
pxAssume( Phase != 0 );
pxAssume(Phase != 0);
if(Releasing && (Phase < 5))
Phase = 5;
if (Releasing && (Phase < 5))
Phase = 5;
switch (Phase)
{
case 1: // attack
if( Value == ADSR_MAX_VOL )
{
// Already maxed out. Progress phase and nothing more:
Phase++;
break;
}
switch (Phase) {
case 1: // attack
if (Value == ADSR_MAX_VOL) {
// Already maxed out. Progress phase and nothing more:
Phase++;
break;
}
// Case 1 below is for pseudo exponential below 75%.
// Pseudo Exp > 75% and Linear are the same.
// Case 1 below is for pseudo exponential below 75%.
// Pseudo Exp > 75% and Linear are the same.
if( AttackMode && (Value>=0x60000000) )
Value += PsxRates[(AttackRate^0x7f)-0x18+32];
else
Value += PsxRates[(AttackRate^0x7f)-0x10+32];
if (AttackMode && (Value >= 0x60000000))
Value += PsxRates[(AttackRate ^ 0x7f) - 0x18 + 32];
else
Value += PsxRates[(AttackRate ^ 0x7f) - 0x10 + 32];
if( Value < 0 )
{
// We hit the ceiling.
Phase++;
Value = ADSR_MAX_VOL;
}
break;
if (Value < 0) {
// We hit the ceiling.
Phase++;
Value = ADSR_MAX_VOL;
}
break;
case 2: // decay
{
u32 off = InvExpOffsets[(Value>>28)&7];
Value -= PsxRates[((DecayRate^0x1f)*4)-0x18+off+32];
case 2: // decay
{
u32 off = InvExpOffsets[(Value >> 28) & 7];
Value -= PsxRates[((DecayRate ^ 0x1f) * 4) - 0x18 + off + 32];
// calculate sustain level as a factor of the ADSR maximum volume.
// calculate sustain level as a factor of the ADSR maximum volume.
s32 suslev = ((0x80000000 / 0x10 ) * (SustainLevel+1)) - 1;
s32 suslev = ((0x80000000 / 0x10) * (SustainLevel + 1)) - 1;
if( Value <= suslev )
{
if (Value < 0)
Value = 0;
Phase++;
}
}
break;
if (Value <= suslev) {
if (Value < 0)
Value = 0;
Phase++;
}
} break;
case 3: // sustain
{
// 0x7f disables sustain (infinite sustain)
if( SustainRate == 0x7f ) return true;
case 3: // sustain
{
// 0x7f disables sustain (infinite sustain)
if (SustainRate == 0x7f)
return true;
if (SustainMode&2) // decreasing
{
if (SustainMode&4) // exponential
{
u32 off = InvExpOffsets[(Value>>28)&7];
Value -= PsxRates[(SustainRate^0x7f)-0x1b+off+32];
}
else // linear
Value -= PsxRates[(SustainRate^0x7f)-0xf+32];
if (SustainMode & 2) // decreasing
{
if (SustainMode & 4) // exponential
{
u32 off = InvExpOffsets[(Value >> 28) & 7];
Value -= PsxRates[(SustainRate ^ 0x7f) - 0x1b + off + 32];
} else // linear
Value -= PsxRates[(SustainRate ^ 0x7f) - 0xf + 32];
if( Value <= 0 )
{
Value = 0;
Phase++;
}
}
else // increasing
{
if( (SustainMode&4) && (Value>=0x60000000) )
Value += PsxRates[(SustainRate^0x7f)-0x18+32];
else
// linear / Pseudo below 75% (they're the same)
Value += PsxRates[(SustainRate^0x7f)-0x10+32];
if (Value <= 0) {
Value = 0;
Phase++;
}
} else { // increasing
if ((SustainMode & 4) && (Value >= 0x60000000))
Value += PsxRates[(SustainRate ^ 0x7f) - 0x18 + 32];
else
// linear / Pseudo below 75% (they're the same)
Value += PsxRates[(SustainRate ^ 0x7f) - 0x10 + 32];
if( Value < 0 )
{
Value = ADSR_MAX_VOL;
Phase++;
}
}
}
break;
if (Value < 0) {
Value = ADSR_MAX_VOL;
Phase++;
}
}
} break;
case 4: // sustain end
Value = (SustainMode&2) ? 0 : ADSR_MAX_VOL;
if(Value==0)
Phase=6;
break;
case 4: // sustain end
Value = (SustainMode & 2) ? 0 : ADSR_MAX_VOL;
if (Value == 0)
Phase = 6;
break;
case 5: // release
if (ReleaseMode) // exponential
{
u32 off=InvExpOffsets[(Value>>28)&7];
Value-=PsxRates[((ReleaseRate^0x1f)*4)-0x18+off+32];
}
else // linear
{
//Value-=PsxRates[((ReleaseRate^0x1f)*4)-0xc+32];
if( ReleaseRate != 0x1f )
Value -= (1 << (0x1f-ReleaseRate));
}
case 5: // release
if (ReleaseMode) // exponential
{
u32 off = InvExpOffsets[(Value >> 28) & 7];
Value -= PsxRates[((ReleaseRate ^ 0x1f) * 4) - 0x18 + off + 32];
} else { // linear
//Value-=PsxRates[((ReleaseRate^0x1f)*4)-0xc+32];
if (ReleaseRate != 0x1f)
Value -= (1 << (0x1f - ReleaseRate));
}
if( Value <= 0 )
{
Value=0;
Phase++;
}
break;
if (Value <= 0) {
Value = 0;
Phase++;
}
break;
case 6: // release end
Value=0;
break;
case 6: // release end
Value = 0;
break;
jNO_DEFAULT
}
jNO_DEFAULT
}
// returns true if the voice is active, or false if it's stopping.
return Phase != 6;
// returns true if the voice is active, or false if it's stopping.
return Phase != 6;
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// //
#define VOLFLAG_REVERSE_PHASE (1ul<<0)
#define VOLFLAG_DECREMENT (1ul<<1)
#define VOLFLAG_EXPONENTIAL (1ul<<2)
#define VOLFLAG_SLIDE_ENABLE (1ul<<3)
#define VOLFLAG_REVERSE_PHASE (1ul << 0)
#define VOLFLAG_DECREMENT (1ul << 1)
#define VOLFLAG_EXPONENTIAL (1ul << 2)
#define VOLFLAG_SLIDE_ENABLE (1ul << 3)
void V_VolumeSlide::Update()
{
if( !(Mode & VOLFLAG_SLIDE_ENABLE) ) return;
if (!(Mode & VOLFLAG_SLIDE_ENABLE))
return;
// Volume slides use the same basic logic as ADSR, but simplified (single-stage
// instead of multi-stage)
// Volume slides use the same basic logic as ADSR, but simplified (single-stage
// instead of multi-stage)
if( Increment == 0x7f ) return;
if (Increment == 0x7f)
return;
s32 value = abs(Value);
s32 value = abs(Value);
if (Mode & VOLFLAG_DECREMENT)
{
// Decrement
if (Mode & VOLFLAG_DECREMENT) {
// Decrement
if(Mode & VOLFLAG_EXPONENTIAL)
{
u32 off = InvExpOffsets[(value>>28)&7];
value -= PsxRates[(Increment^0x7f)-0x1b+off+32];
}
else
value -= PsxRates[(Increment^0x7f)-0xf+32];
if (Mode & VOLFLAG_EXPONENTIAL) {
u32 off = InvExpOffsets[(value >> 28) & 7];
value -= PsxRates[(Increment ^ 0x7f) - 0x1b + off + 32];
} else
value -= PsxRates[(Increment ^ 0x7f) - 0xf + 32];
if (value < 0)
{
value = 0;
Mode = 0; // disable slide
}
}
else
{
// Increment
// Pseudo-exponential increments, as done by the SPU2 (really!)
// Above 75% slides slow, below 75% slides fast. It's exponential, pseudo'ly speaking.
if (value < 0) {
value = 0;
Mode = 0; // disable slide
}
} else {
// Increment
// Pseudo-exponential increments, as done by the SPU2 (really!)
// Above 75% slides slow, below 75% slides fast. It's exponential, pseudo'ly speaking.
if( (Mode & VOLFLAG_EXPONENTIAL) && (value>=0x60000000))
value += PsxRates[(Increment^0x7f)-0x18+32];
else
// linear / Pseudo below 75% (they're the same)
value += PsxRates[(Increment^0x7f)-0x10+32];
if ((Mode & VOLFLAG_EXPONENTIAL) && (value >= 0x60000000))
value += PsxRates[(Increment ^ 0x7f) - 0x18 + 32];
else
// linear / Pseudo below 75% (they're the same)
value += PsxRates[(Increment ^ 0x7f) - 0x10 + 32];
if( value < 0 ) // wrapped around the "top"?
{
value = 0x7fffffff;
Mode = 0; // disable slide
}
}
Value = (Value < 0) ? -value : value;
if (value < 0) // wrapped around the "top"?
{
value = 0x7fffffff;
Mode = 0; // disable slide
}
}
Value = (Value < 0) ? -value : value;
}

View File

@ -36,23 +36,23 @@ extern bool _MemDump;
extern bool _RegDump;
extern bool _visual_debug_enabled;
static __forceinline bool MsgToConsole() { return _MsgToConsole & DebugEnabled; }
static __forceinline bool MsgToConsole() { return _MsgToConsole & DebugEnabled; }
static __forceinline bool MsgKeyOnOff() { return _MsgKeyOnOff & MsgToConsole(); }
static __forceinline bool MsgVoiceOff() { return _MsgVoiceOff & MsgToConsole(); }
static __forceinline bool MsgDMA() { return _MsgDMA & MsgToConsole(); }
static __forceinline bool MsgAutoDMA() { return _MsgAutoDMA & MsgToConsole(); }
static __forceinline bool MsgOverruns() { return _MsgOverruns & MsgToConsole(); }
static __forceinline bool MsgCache() { return _MsgCache & MsgToConsole(); }
static __forceinline bool MsgKeyOnOff() { return _MsgKeyOnOff & MsgToConsole(); }
static __forceinline bool MsgVoiceOff() { return _MsgVoiceOff & MsgToConsole(); }
static __forceinline bool MsgDMA() { return _MsgDMA & MsgToConsole(); }
static __forceinline bool MsgAutoDMA() { return _MsgAutoDMA & MsgToConsole(); }
static __forceinline bool MsgOverruns() { return _MsgOverruns & MsgToConsole(); }
static __forceinline bool MsgCache() { return _MsgCache & MsgToConsole(); }
static __forceinline bool AccessLog() { return _AccessLog & DebugEnabled; }
static __forceinline bool DMALog() { return _DMALog & DebugEnabled; }
static __forceinline bool WaveLog() { return _WaveLog & DebugEnabled; }
static __forceinline bool AccessLog() { return _AccessLog & DebugEnabled; }
static __forceinline bool DMALog() { return _DMALog & DebugEnabled; }
static __forceinline bool WaveLog() { return _WaveLog & DebugEnabled; }
static __forceinline bool CoresDump() { return _CoresDump & DebugEnabled; }
static __forceinline bool MemDump() { return _MemDump & DebugEnabled; }
static __forceinline bool RegDump() { return _RegDump & DebugEnabled; }
static __forceinline bool VisualDebug() { return _visual_debug_enabled & DebugEnabled; }
static __forceinline bool CoresDump() { return _CoresDump & DebugEnabled; }
static __forceinline bool MemDump() { return _MemDump & DebugEnabled; }
static __forceinline bool RegDump() { return _RegDump & DebugEnabled; }
static __forceinline bool VisualDebug() { return _visual_debug_enabled & DebugEnabled; }
extern wxString AccessLogFileName;
extern wxString DMA4LogFileName;
@ -64,7 +64,7 @@ extern wxString RegDumpFileName;
extern int Interpolation;
extern int numSpeakers;
extern bool EffectsDisabled;
extern float FinalVolume; // Global / pre-scale
extern float FinalVolume; // Global / pre-scale
extern bool AdvancedVolumeControl;
extern float VolumeAdjustFLdb;
extern float VolumeAdjustCdb;
@ -85,14 +85,14 @@ extern int SynchMode;
#ifndef __POSIX__
extern wchar_t dspPlugin[];
extern int dspPluginModule;
extern int dspPluginModule;
extern bool dspPluginEnabled;
extern bool dspPluginEnabled;
#endif
namespace SoundtouchCfg
{
extern void ApplySettings( soundtouch::SoundTouch& sndtouch );
extern void ApplySettings(soundtouch::SoundTouch &sndtouch);
}
//////

View File

@ -24,28 +24,28 @@
class DPLII
{
public:
static const bool UseAveraging = false;
static const bool UseAveraging = false;
protected:
s32 LAccum;
s32 RAccum;
s32 ANum;
s32 LAccum;
s32 RAccum;
s32 ANum;
LPF_data lpf_l;
LPF_data lpf_r;
LPF_data lpf_l;
LPF_data lpf_r;
u8 bufdone;
s32 Gfl,Gfr;
u8 bufdone;
s32 Gfl, Gfr;
s32 spdif_data[6];
s32 LMax,RMax;
s32 spdif_data[6];
s32 LMax, RMax;
s32 LBuff[128];
s32 RBuff[128];
s32 LBuff[128];
s32 RBuff[128];
public:
DPLII( s32 lowpass_freq, s32 samplerate );
void Convert( s16 *obuffer, s32 ValL, s32 ValR );
DPLII(s32 lowpass_freq, s32 samplerate);
void Convert(s16 *obuffer, s32 ValL, s32 ValR);
};
#endif

View File

@ -17,25 +17,28 @@
#include "Global.h"
int crazy_debug=0;
int crazy_debug = 0;
char s[4096];
FILE *spu2Log = NULL;
void FileLog(const char *fmt, ...) {
void FileLog(const char *fmt, ...)
{
#ifdef SPU2_LOG
va_list list;
va_list list;
if(!AccessLog()) return;
if(!spu2Log) return;
if (!AccessLog())
return;
if (!spu2Log)
return;
va_start(list, fmt);
vsprintf(s,fmt, list);
va_end(list);
va_start(list, fmt);
vsprintf(s, fmt, list);
va_end(list);
fputs(s,spu2Log);
fflush(spu2Log);
fputs(s, spu2Log);
fflush(spu2Log);
#if 0
if(crazy_debug)
@ -51,212 +54,205 @@ void FileLog(const char *fmt, ...) {
// while ConLog doesn't print anything if messages to console are disabled at the GUI,
// it's still better to outright not call it on tight loop scenarios, by testing MsgToConsole() (which is inline and very quick).
// Else, there's some (small) overhead in calling and returning from ConLog.
void ConLog(const char *fmt, ...) {
if(!MsgToConsole()) return;
void ConLog(const char *fmt, ...)
{
if (!MsgToConsole())
return;
va_list list;
va_start(list, fmt);
vsprintf(s,fmt, list);
va_end(list);
va_list list;
va_start(list, fmt);
vsprintf(s, fmt, list);
va_end(list);
fputs(s,stderr);
fflush(stderr);
fputs(s, stderr);
fflush(stderr);
if(spu2Log)
{
fputs(s,spu2Log);
fflush(spu2Log);
}
if (spu2Log) {
fputs(s, spu2Log);
fflush(spu2Log);
}
}
void V_VolumeSlide::DebugDump( FILE* dump, const char* title, const char* nameLR )
void V_VolumeSlide::DebugDump(FILE *dump, const char *title, const char *nameLR)
{
fprintf( dump, "%s Volume for %s Channel:\t%x\n"
" - Value: %x\n"
" - Mode: %x\n"
" - Increment: %x\n",
title, nameLR, Reg_VOL, Value, Mode, Increment);
fprintf(dump, "%s Volume for %s Channel:\t%x\n"
" - Value: %x\n"
" - Mode: %x\n"
" - Increment: %x\n",
title, nameLR, Reg_VOL, Value, Mode, Increment);
}
void V_VolumeSlideLR::DebugDump( FILE* dump, const char* title )
void V_VolumeSlideLR::DebugDump(FILE *dump, const char *title)
{
Left.DebugDump( dump, title, "Left" );
Right.DebugDump( dump, title, "Right" );
Left.DebugDump(dump, title, "Left");
Right.DebugDump(dump, title, "Right");
}
void V_VolumeLR::DebugDump( FILE* dump, const char* title )
void V_VolumeLR::DebugDump(FILE *dump, const char *title)
{
fprintf( dump, "Volume for %s (%s Channel):\t%x\n", title, "Left", Left );
fprintf( dump, "Volume for %s (%s Channel):\t%x\n", title, "Right", Right );
fprintf(dump, "Volume for %s (%s Channel):\t%x\n", title, "Left", Left);
fprintf(dump, "Volume for %s (%s Channel):\t%x\n", title, "Right", Right);
}
void DoFullDump()
{
#ifdef _MSC_VER
#ifdef SPU2_LOG
FILE *dump;
u8 c=0, v=0;
FILE *dump;
u8 c = 0, v = 0;
if(MemDump())
{
dump = fopen( wxString(MemDumpFileName).ToUTF8(), "wb" );
if (dump)
{
fwrite(_spu2mem,0x200000,1,dump);
fclose(dump);
}
}
if(RegDump())
{
dump = fopen( wxString(RegDumpFileName).ToUTF8(), "wb" );
if (dump)
{
fwrite(spu2regs,0x2000,1,dump);
fclose(dump);
}
}
if (MemDump()) {
dump = fopen(wxString(MemDumpFileName).ToUTF8(), "wb");
if (dump) {
fwrite(_spu2mem, 0x200000, 1, dump);
fclose(dump);
}
}
if (RegDump()) {
dump = fopen(wxString(RegDumpFileName).ToUTF8(), "wb");
if (dump) {
fwrite(spu2regs, 0x2000, 1, dump);
fclose(dump);
}
}
if(!CoresDump()) return;
dump = fopen( wxString(CoresDumpFileName).ToUTF8(), "wt" );
if (dump)
{
for(c=0;c<2;c++)
{
fprintf(dump,"#### CORE %d DUMP.\n",c);
if (!CoresDump())
return;
dump = fopen(wxString(CoresDumpFileName).ToUTF8(), "wt");
if (dump) {
for (c = 0; c < 2; c++) {
fprintf(dump, "#### CORE %d DUMP.\n", c);
Cores[c].MasterVol.DebugDump( dump, "Master" );
Cores[c].MasterVol.DebugDump(dump, "Master");
Cores[c].ExtVol.DebugDump( dump, "External Data Input" );
Cores[c].InpVol.DebugDump( dump, "Voice Data Input [dry]" );
Cores[c].FxVol.DebugDump( dump, "Effects/Reverb [wet]" );
Cores[c].ExtVol.DebugDump(dump, "External Data Input");
Cores[c].InpVol.DebugDump(dump, "Voice Data Input [dry]");
Cores[c].FxVol.DebugDump(dump, "Effects/Reverb [wet]");
fprintf(dump,"Interrupt Address: %x\n",Cores[c].IRQA);
fprintf(dump,"DMA Transfer Start Address: %x\n",Cores[c].TSA);
fprintf(dump,"External Input to Direct Output (Left): %s\n",Cores[c].DryGate.ExtL?"Yes":"No");
fprintf(dump,"External Input to Direct Output (Right): %s\n",Cores[c].DryGate.ExtR?"Yes":"No");
fprintf(dump,"External Input to Effects (Left): %s\n",Cores[c].WetGate.ExtL?"Yes":"No");
fprintf(dump,"External Input to Effects (Right): %s\n",Cores[c].WetGate.ExtR?"Yes":"No");
fprintf(dump,"Sound Data Input to Direct Output (Left): %s\n",Cores[c].DryGate.SndL?"Yes":"No");
fprintf(dump,"Sound Data Input to Direct Output (Right): %s\n",Cores[c].DryGate.SndR?"Yes":"No");
fprintf(dump,"Sound Data Input to Effects (Left): %s\n",Cores[c].WetGate.SndL?"Yes":"No");
fprintf(dump,"Sound Data Input to Effects (Right): %s\n",Cores[c].WetGate.SndR?"Yes":"No");
fprintf(dump,"Voice Data Input to Direct Output (Left): %s\n",Cores[c].DryGate.InpL?"Yes":"No");
fprintf(dump,"Voice Data Input to Direct Output (Right): %s\n",Cores[c].DryGate.InpR?"Yes":"No");
fprintf(dump,"Voice Data Input to Effects (Left): %s\n",Cores[c].WetGate.InpL?"Yes":"No");
fprintf(dump,"Voice Data Input to Effects (Right): %s\n",Cores[c].WetGate.InpR?"Yes":"No");
fprintf(dump,"IRQ Enabled: %s\n",Cores[c].IRQEnable?"Yes":"No");
fprintf(dump,"Effects Enabled: %s\n",Cores[c].FxEnable?"Yes":"No");
fprintf(dump,"Mute Enabled: %s\n",Cores[c].Mute?"Yes":"No");
fprintf(dump,"Noise Clock: %d\n",Cores[c].NoiseClk);
fprintf(dump,"DMA Bits: %d\n",Cores[c].DMABits);
fprintf(dump,"Effects Start: %x\n",Cores[c].EffectsStartA);
fprintf(dump,"Effects End: %x\n",Cores[c].EffectsEndA);
fprintf(dump,"Registers:\n");
fprintf(dump," - PMON: %x\n",Cores[c].Regs.PMON);
fprintf(dump," - NON: %x\n",Cores[c].Regs.NON);
fprintf(dump," - VMIXL: %x\n",Cores[c].Regs.VMIXL);
fprintf(dump," - VMIXR: %x\n",Cores[c].Regs.VMIXR);
fprintf(dump," - VMIXEL: %x\n",Cores[c].Regs.VMIXEL);
fprintf(dump," - VMIXER: %x\n",Cores[c].Regs.VMIXER);
fprintf(dump," - MMIX: %x\n",Cores[c].Regs.VMIXEL);
fprintf(dump," - ENDX: %x\n",Cores[c].Regs.VMIXER);
fprintf(dump," - STATX: %x\n",Cores[c].Regs.VMIXEL);
fprintf(dump," - ATTR: %x\n",Cores[c].Regs.VMIXER);
for(v=0;v<24;v++)
{
fprintf(dump,"Voice %d:\n",v);
Cores[c].Voices[v].Volume.DebugDump( dump, "" );
fprintf(dump, "Interrupt Address: %x\n", Cores[c].IRQA);
fprintf(dump, "DMA Transfer Start Address: %x\n", Cores[c].TSA);
fprintf(dump, "External Input to Direct Output (Left): %s\n", Cores[c].DryGate.ExtL ? "Yes" : "No");
fprintf(dump, "External Input to Direct Output (Right): %s\n", Cores[c].DryGate.ExtR ? "Yes" : "No");
fprintf(dump, "External Input to Effects (Left): %s\n", Cores[c].WetGate.ExtL ? "Yes" : "No");
fprintf(dump, "External Input to Effects (Right): %s\n", Cores[c].WetGate.ExtR ? "Yes" : "No");
fprintf(dump, "Sound Data Input to Direct Output (Left): %s\n", Cores[c].DryGate.SndL ? "Yes" : "No");
fprintf(dump, "Sound Data Input to Direct Output (Right): %s\n", Cores[c].DryGate.SndR ? "Yes" : "No");
fprintf(dump, "Sound Data Input to Effects (Left): %s\n", Cores[c].WetGate.SndL ? "Yes" : "No");
fprintf(dump, "Sound Data Input to Effects (Right): %s\n", Cores[c].WetGate.SndR ? "Yes" : "No");
fprintf(dump, "Voice Data Input to Direct Output (Left): %s\n", Cores[c].DryGate.InpL ? "Yes" : "No");
fprintf(dump, "Voice Data Input to Direct Output (Right): %s\n", Cores[c].DryGate.InpR ? "Yes" : "No");
fprintf(dump, "Voice Data Input to Effects (Left): %s\n", Cores[c].WetGate.InpL ? "Yes" : "No");
fprintf(dump, "Voice Data Input to Effects (Right): %s\n", Cores[c].WetGate.InpR ? "Yes" : "No");
fprintf(dump, "IRQ Enabled: %s\n", Cores[c].IRQEnable ? "Yes" : "No");
fprintf(dump, "Effects Enabled: %s\n", Cores[c].FxEnable ? "Yes" : "No");
fprintf(dump, "Mute Enabled: %s\n", Cores[c].Mute ? "Yes" : "No");
fprintf(dump, "Noise Clock: %d\n", Cores[c].NoiseClk);
fprintf(dump, "DMA Bits: %d\n", Cores[c].DMABits);
fprintf(dump, "Effects Start: %x\n", Cores[c].EffectsStartA);
fprintf(dump, "Effects End: %x\n", Cores[c].EffectsEndA);
fprintf(dump, "Registers:\n");
fprintf(dump, " - PMON: %x\n", Cores[c].Regs.PMON);
fprintf(dump, " - NON: %x\n", Cores[c].Regs.NON);
fprintf(dump, " - VMIXL: %x\n", Cores[c].Regs.VMIXL);
fprintf(dump, " - VMIXR: %x\n", Cores[c].Regs.VMIXR);
fprintf(dump, " - VMIXEL: %x\n", Cores[c].Regs.VMIXEL);
fprintf(dump, " - VMIXER: %x\n", Cores[c].Regs.VMIXER);
fprintf(dump, " - MMIX: %x\n", Cores[c].Regs.VMIXEL);
fprintf(dump, " - ENDX: %x\n", Cores[c].Regs.VMIXER);
fprintf(dump, " - STATX: %x\n", Cores[c].Regs.VMIXEL);
fprintf(dump, " - ATTR: %x\n", Cores[c].Regs.VMIXER);
for (v = 0; v < 24; v++) {
fprintf(dump, "Voice %d:\n", v);
Cores[c].Voices[v].Volume.DebugDump(dump, "");
fprintf(dump," - ADSR Envelope: %x & %x\n"
" - Ar: %x\n"
" - Am: %x\n"
" - Dr: %x\n"
" - Sl: %x\n"
" - Sr: %x\n"
" - Sm: %x\n"
" - Rr: %x\n"
" - Rm: %x\n"
" - Phase: %x\n"
" - Value: %x\n",
Cores[c].Voices[v].ADSR.regADSR1,
Cores[c].Voices[v].ADSR.regADSR2,
Cores[c].Voices[v].ADSR.AttackRate,
Cores[c].Voices[v].ADSR.AttackMode,
Cores[c].Voices[v].ADSR.DecayRate,
Cores[c].Voices[v].ADSR.SustainLevel,
Cores[c].Voices[v].ADSR.SustainRate,
Cores[c].Voices[v].ADSR.SustainMode,
Cores[c].Voices[v].ADSR.ReleaseRate,
Cores[c].Voices[v].ADSR.ReleaseMode,
Cores[c].Voices[v].ADSR.Phase,
Cores[c].Voices[v].ADSR.Value);
fprintf(dump, " - ADSR Envelope: %x & %x\n"
" - Ar: %x\n"
" - Am: %x\n"
" - Dr: %x\n"
" - Sl: %x\n"
" - Sr: %x\n"
" - Sm: %x\n"
" - Rr: %x\n"
" - Rm: %x\n"
" - Phase: %x\n"
" - Value: %x\n",
Cores[c].Voices[v].ADSR.regADSR1,
Cores[c].Voices[v].ADSR.regADSR2,
Cores[c].Voices[v].ADSR.AttackRate,
Cores[c].Voices[v].ADSR.AttackMode,
Cores[c].Voices[v].ADSR.DecayRate,
Cores[c].Voices[v].ADSR.SustainLevel,
Cores[c].Voices[v].ADSR.SustainRate,
Cores[c].Voices[v].ADSR.SustainMode,
Cores[c].Voices[v].ADSR.ReleaseRate,
Cores[c].Voices[v].ADSR.ReleaseMode,
Cores[c].Voices[v].ADSR.Phase,
Cores[c].Voices[v].ADSR.Value);
fprintf(dump," - Pitch: %x\n",Cores[c].Voices[v].Pitch);
fprintf(dump," - Modulated: %s\n",Cores[c].Voices[v].Modulated?"Yes":"No");
fprintf(dump," - Source: %s\n",Cores[c].Voices[v].Noise?"Noise":"Wave");
fprintf(dump," - Direct Output for Left Channel: %s\n",Cores[c].VoiceGates[v].DryL?"Yes":"No");
fprintf(dump," - Direct Output for Right Channel: %s\n",Cores[c].VoiceGates[v].DryR?"Yes":"No");
fprintf(dump," - Effects Output for Left Channel: %s\n",Cores[c].VoiceGates[v].WetL?"Yes":"No");
fprintf(dump," - Effects Output for Right Channel: %s\n",Cores[c].VoiceGates[v].WetR?"Yes":"No");
fprintf(dump," - Loop Start Address: %x\n",Cores[c].Voices[v].LoopStartA);
fprintf(dump," - Sound Start Address: %x\n",Cores[c].Voices[v].StartA);
fprintf(dump," - Next Data Address: %x\n",Cores[c].Voices[v].NextA);
fprintf(dump," - Play Start Cycle: %d\n",Cores[c].Voices[v].PlayCycle);
fprintf(dump," - Play Status: %s\n",(Cores[c].Voices[v].ADSR.Phase>0)?"Playing":"Not Playing");
fprintf(dump," - Block Sample: %d\n",Cores[c].Voices[v].SCurrent);
}
fprintf(dump,"#### END OF DUMP.\n\n");
}
fclose(dump);
}
dump = fopen( "logs/effects.txt", "wt" );
if (dump)
{
for(c=0;c<2;c++)
{
fprintf(dump,"#### CORE %d EFFECTS PROCESSOR DUMP.\n",c);
fprintf(dump, " - Pitch: %x\n", Cores[c].Voices[v].Pitch);
fprintf(dump, " - Modulated: %s\n", Cores[c].Voices[v].Modulated ? "Yes" : "No");
fprintf(dump, " - Source: %s\n", Cores[c].Voices[v].Noise ? "Noise" : "Wave");
fprintf(dump, " - Direct Output for Left Channel: %s\n", Cores[c].VoiceGates[v].DryL ? "Yes" : "No");
fprintf(dump, " - Direct Output for Right Channel: %s\n", Cores[c].VoiceGates[v].DryR ? "Yes" : "No");
fprintf(dump, " - Effects Output for Left Channel: %s\n", Cores[c].VoiceGates[v].WetL ? "Yes" : "No");
fprintf(dump, " - Effects Output for Right Channel: %s\n", Cores[c].VoiceGates[v].WetR ? "Yes" : "No");
fprintf(dump, " - Loop Start Address: %x\n", Cores[c].Voices[v].LoopStartA);
fprintf(dump, " - Sound Start Address: %x\n", Cores[c].Voices[v].StartA);
fprintf(dump, " - Next Data Address: %x\n", Cores[c].Voices[v].NextA);
fprintf(dump, " - Play Start Cycle: %d\n", Cores[c].Voices[v].PlayCycle);
fprintf(dump, " - Play Status: %s\n", (Cores[c].Voices[v].ADSR.Phase > 0) ? "Playing" : "Not Playing");
fprintf(dump, " - Block Sample: %d\n", Cores[c].Voices[v].SCurrent);
}
fprintf(dump, "#### END OF DUMP.\n\n");
}
fclose(dump);
}
fprintf(dump," - IN_COEF_L: %x\n",Cores[c].Revb.IN_COEF_R);
fprintf(dump," - IN_COEF_R: %x\n",Cores[c].Revb.IN_COEF_L);
dump = fopen("logs/effects.txt", "wt");
if (dump) {
for (c = 0; c < 2; c++) {
fprintf(dump, "#### CORE %d EFFECTS PROCESSOR DUMP.\n", c);
fprintf(dump," - FB_ALPHA: %x\n",Cores[c].Revb.FB_ALPHA);
fprintf(dump," - FB_X: %x\n",Cores[c].Revb.FB_X);
fprintf(dump," - FB_SRC_A: %x\n",Cores[c].Revb.FB_SRC_A);
fprintf(dump," - FB_SRC_B: %x\n",Cores[c].Revb.FB_SRC_B);
fprintf(dump, " - IN_COEF_L: %x\n", Cores[c].Revb.IN_COEF_R);
fprintf(dump, " - IN_COEF_R: %x\n", Cores[c].Revb.IN_COEF_L);
fprintf(dump," - IIR_ALPHA: %x\n",Cores[c].Revb.IIR_ALPHA);
fprintf(dump," - IIR_COEF: %x\n",Cores[c].Revb.IIR_COEF);
fprintf(dump," - IIR_SRC_A0: %x\n",Cores[c].Revb.IIR_SRC_A0);
fprintf(dump," - IIR_SRC_A1: %x\n",Cores[c].Revb.IIR_SRC_A1);
fprintf(dump," - IIR_SRC_B1: %x\n",Cores[c].Revb.IIR_SRC_B0);
fprintf(dump," - IIR_SRC_B0: %x\n",Cores[c].Revb.IIR_SRC_B1);
fprintf(dump," - IIR_DEST_A0: %x\n",Cores[c].Revb.IIR_DEST_A0);
fprintf(dump," - IIR_DEST_A1: %x\n",Cores[c].Revb.IIR_DEST_A1);
fprintf(dump," - IIR_DEST_B0: %x\n",Cores[c].Revb.IIR_DEST_B0);
fprintf(dump," - IIR_DEST_B1: %x\n",Cores[c].Revb.IIR_DEST_B1);
fprintf(dump, " - FB_ALPHA: %x\n", Cores[c].Revb.FB_ALPHA);
fprintf(dump, " - FB_X: %x\n", Cores[c].Revb.FB_X);
fprintf(dump, " - FB_SRC_A: %x\n", Cores[c].Revb.FB_SRC_A);
fprintf(dump, " - FB_SRC_B: %x\n", Cores[c].Revb.FB_SRC_B);
fprintf(dump," - ACC_COEF_A: %x\n",Cores[c].Revb.ACC_COEF_A);
fprintf(dump," - ACC_COEF_B: %x\n",Cores[c].Revb.ACC_COEF_B);
fprintf(dump," - ACC_COEF_C: %x\n",Cores[c].Revb.ACC_COEF_C);
fprintf(dump," - ACC_COEF_D: %x\n",Cores[c].Revb.ACC_COEF_D);
fprintf(dump," - ACC_SRC_A0: %x\n",Cores[c].Revb.ACC_SRC_A0);
fprintf(dump," - ACC_SRC_A1: %x\n",Cores[c].Revb.ACC_SRC_A1);
fprintf(dump," - ACC_SRC_B0: %x\n",Cores[c].Revb.ACC_SRC_B0);
fprintf(dump," - ACC_SRC_B1: %x\n",Cores[c].Revb.ACC_SRC_B1);
fprintf(dump," - ACC_SRC_C0: %x\n",Cores[c].Revb.ACC_SRC_C0);
fprintf(dump," - ACC_SRC_C1: %x\n",Cores[c].Revb.ACC_SRC_C1);
fprintf(dump," - ACC_SRC_D0: %x\n",Cores[c].Revb.ACC_SRC_D0);
fprintf(dump," - ACC_SRC_D1: %x\n",Cores[c].Revb.ACC_SRC_D1);
fprintf(dump, " - IIR_ALPHA: %x\n", Cores[c].Revb.IIR_ALPHA);
fprintf(dump, " - IIR_COEF: %x\n", Cores[c].Revb.IIR_COEF);
fprintf(dump, " - IIR_SRC_A0: %x\n", Cores[c].Revb.IIR_SRC_A0);
fprintf(dump, " - IIR_SRC_A1: %x\n", Cores[c].Revb.IIR_SRC_A1);
fprintf(dump, " - IIR_SRC_B1: %x\n", Cores[c].Revb.IIR_SRC_B0);
fprintf(dump, " - IIR_SRC_B0: %x\n", Cores[c].Revb.IIR_SRC_B1);
fprintf(dump, " - IIR_DEST_A0: %x\n", Cores[c].Revb.IIR_DEST_A0);
fprintf(dump, " - IIR_DEST_A1: %x\n", Cores[c].Revb.IIR_DEST_A1);
fprintf(dump, " - IIR_DEST_B0: %x\n", Cores[c].Revb.IIR_DEST_B0);
fprintf(dump, " - IIR_DEST_B1: %x\n", Cores[c].Revb.IIR_DEST_B1);
fprintf(dump," - MIX_DEST_A0: %x\n",Cores[c].Revb.MIX_DEST_A0);
fprintf(dump," - MIX_DEST_A1: %x\n",Cores[c].Revb.MIX_DEST_A1);
fprintf(dump," - MIX_DEST_B0: %x\n",Cores[c].Revb.MIX_DEST_B0);
fprintf(dump," - MIX_DEST_B1: %x\n",Cores[c].Revb.MIX_DEST_B1);
fprintf(dump,"#### END OF DUMP.\n\n");
}
fclose(dump);
}
fprintf(dump, " - ACC_COEF_A: %x\n", Cores[c].Revb.ACC_COEF_A);
fprintf(dump, " - ACC_COEF_B: %x\n", Cores[c].Revb.ACC_COEF_B);
fprintf(dump, " - ACC_COEF_C: %x\n", Cores[c].Revb.ACC_COEF_C);
fprintf(dump, " - ACC_COEF_D: %x\n", Cores[c].Revb.ACC_COEF_D);
fprintf(dump, " - ACC_SRC_A0: %x\n", Cores[c].Revb.ACC_SRC_A0);
fprintf(dump, " - ACC_SRC_A1: %x\n", Cores[c].Revb.ACC_SRC_A1);
fprintf(dump, " - ACC_SRC_B0: %x\n", Cores[c].Revb.ACC_SRC_B0);
fprintf(dump, " - ACC_SRC_B1: %x\n", Cores[c].Revb.ACC_SRC_B1);
fprintf(dump, " - ACC_SRC_C0: %x\n", Cores[c].Revb.ACC_SRC_C0);
fprintf(dump, " - ACC_SRC_C1: %x\n", Cores[c].Revb.ACC_SRC_C1);
fprintf(dump, " - ACC_SRC_D0: %x\n", Cores[c].Revb.ACC_SRC_D0);
fprintf(dump, " - ACC_SRC_D1: %x\n", Cores[c].Revb.ACC_SRC_D1);
fprintf(dump, " - MIX_DEST_A0: %x\n", Cores[c].Revb.MIX_DEST_A0);
fprintf(dump, " - MIX_DEST_A1: %x\n", Cores[c].Revb.MIX_DEST_A1);
fprintf(dump, " - MIX_DEST_B0: %x\n", Cores[c].Revb.MIX_DEST_B0);
fprintf(dump, " - MIX_DEST_B1: %x\n", Cores[c].Revb.MIX_DEST_B1);
fprintf(dump, "#### END OF DUMP.\n\n");
}
fclose(dump);
}
#endif
#endif
}

View File

@ -26,40 +26,39 @@ extern void ConLog(const char *fmt, ...);
extern void DoFullDump();
extern FILE* OpenBinaryLog( const wxString& logfile );
extern FILE* OpenLog( const wxString& logfile );
extern FILE* OpenDump( const wxString& logfile );
extern FILE *OpenBinaryLog(const wxString &logfile);
extern FILE *OpenLog(const wxString &logfile);
extern FILE *OpenDump(const wxString &logfile);
namespace WaveDump
{
enum CoreSourceType
{
// Core's input stream, usually pulled from ADMA streams.
CoreSrc_Input = 0
enum CoreSourceType {
// Core's input stream, usually pulled from ADMA streams.
CoreSrc_Input = 0,
// Output of the actual 24 input voices which have dry output enabled.
, CoreSrc_DryVoiceMix
// 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
// 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 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
// 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
// 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
};
CoreSrc_Count
};
extern void Open();
extern void Close();
extern void WriteCore( uint coreidx, CoreSourceType src, s16 left, s16 right );
extern void WriteCore( uint coreidx, CoreSourceType src, const StereoOut16& sample );
extern void Open();
extern void Close();
extern void WriteCore(uint coreidx, CoreSourceType src, s16 left, s16 right);
extern void WriteCore(uint coreidx, CoreSourceType src, const StereoOut16 &sample);
}
using WaveDump::CoreSrc_Input;
@ -69,4 +68,4 @@ using WaveDump::CoreSrc_PreReverb;
using WaveDump::CoreSrc_PostReverb;
using WaveDump::CoreSrc_External;
#endif // DEBUG_H_INCLUDED //
#endif // DEBUG_H_INCLUDED //

View File

@ -23,131 +23,132 @@
#include <string.h>
static const u8 sLogTable[256] = {
0x00,0x3C,0x60,0x78,0x8C,0x9C,0xA8,0xB4,0xBE,0xC8,0xD0,0xD8,0xDE,0xE4,0xEA,0xF0,
0xF6,0xFA,0xFE,0x04,0x08,0x0C,0x10,0x14,0x16,0x1A,0x1E,0x20,0x24,0x26,0x2A,0x2C,
0x2E,0x32,0x34,0x36,0x38,0x3A,0x3E,0x40,0x42,0x44,0x46,0x48,0x4A,0x4C,0x4E,0x50,
0x50,0x52,0x54,0x56,0x58,0x5A,0x5A,0x5C,0x5E,0x60,0x60,0x62,0x64,0x66,0x66,0x68,
0x6A,0x6A,0x6C,0x6E,0x6E,0x70,0x70,0x72,0x74,0x74,0x76,0x76,0x78,0x7A,0x7A,0x7C,
0x7C,0x7E,0x7E,0x80,0x80,0x82,0x82,0x84,0x84,0x86,0x86,0x88,0x88,0x8A,0x8A,0x8C,
0x8C,0x8C,0x8E,0x8E,0x90,0x90,0x92,0x92,0x92,0x94,0x94,0x96,0x96,0x96,0x98,0x98,
0x9A,0x9A,0x9A,0x9C,0x9C,0x9C,0x9E,0x9E,0xA0,0xA0,0xA0,0xA2,0xA2,0xA2,0xA4,0xA4,
0xA4,0xA6,0xA6,0xA6,0xA8,0xA8,0xA8,0xAA,0xAA,0xAA,0xAC,0xAC,0xAC,0xAC,0xAE,0xAE,
0xAE,0xB0,0xB0,0xB0,0xB2,0xB2,0xB2,0xB2,0xB4,0xB4,0xB4,0xB6,0xB6,0xB6,0xB6,0xB8,
0xB8,0xB8,0xB8,0xBA,0xBA,0xBA,0xBC,0xBC,0xBC,0xBC,0xBE,0xBE,0xBE,0xBE,0xC0,0xC0,
0xC0,0xC0,0xC2,0xC2,0xC2,0xC2,0xC2,0xC4,0xC4,0xC4,0xC4,0xC6,0xC6,0xC6,0xC6,0xC8,
0xC8,0xC8,0xC8,0xC8,0xCA,0xCA,0xCA,0xCA,0xCC,0xCC,0xCC,0xCC,0xCC,0xCE,0xCE,0xCE,
0xCE,0xCE,0xD0,0xD0,0xD0,0xD0,0xD0,0xD2,0xD2,0xD2,0xD2,0xD2,0xD4,0xD4,0xD4,0xD4,
0xD4,0xD6,0xD6,0xD6,0xD6,0xD6,0xD8,0xD8,0xD8,0xD8,0xD8,0xD8,0xDA,0xDA,0xDA,0xDA,
0xDA,0xDC,0xDC,0xDC,0xDC,0xDC,0xDC,0xDE,0xDE,0xDE,0xDE,0xDE,0xDE,0xE0,0xE0,0xE0,
0x00, 0x3C, 0x60, 0x78, 0x8C, 0x9C, 0xA8, 0xB4, 0xBE, 0xC8, 0xD0, 0xD8, 0xDE, 0xE4, 0xEA, 0xF0,
0xF6, 0xFA, 0xFE, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x16, 0x1A, 0x1E, 0x20, 0x24, 0x26, 0x2A, 0x2C,
0x2E, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3E, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x50,
0x50, 0x52, 0x54, 0x56, 0x58, 0x5A, 0x5A, 0x5C, 0x5E, 0x60, 0x60, 0x62, 0x64, 0x66, 0x66, 0x68,
0x6A, 0x6A, 0x6C, 0x6E, 0x6E, 0x70, 0x70, 0x72, 0x74, 0x74, 0x76, 0x76, 0x78, 0x7A, 0x7A, 0x7C,
0x7C, 0x7E, 0x7E, 0x80, 0x80, 0x82, 0x82, 0x84, 0x84, 0x86, 0x86, 0x88, 0x88, 0x8A, 0x8A, 0x8C,
0x8C, 0x8C, 0x8E, 0x8E, 0x90, 0x90, 0x92, 0x92, 0x92, 0x94, 0x94, 0x96, 0x96, 0x96, 0x98, 0x98,
0x9A, 0x9A, 0x9A, 0x9C, 0x9C, 0x9C, 0x9E, 0x9E, 0xA0, 0xA0, 0xA0, 0xA2, 0xA2, 0xA2, 0xA4, 0xA4,
0xA4, 0xA6, 0xA6, 0xA6, 0xA8, 0xA8, 0xA8, 0xAA, 0xAA, 0xAA, 0xAC, 0xAC, 0xAC, 0xAC, 0xAE, 0xAE,
0xAE, 0xB0, 0xB0, 0xB0, 0xB2, 0xB2, 0xB2, 0xB2, 0xB4, 0xB4, 0xB4, 0xB6, 0xB6, 0xB6, 0xB6, 0xB8,
0xB8, 0xB8, 0xB8, 0xBA, 0xBA, 0xBA, 0xBC, 0xBC, 0xBC, 0xBC, 0xBE, 0xBE, 0xBE, 0xBE, 0xC0, 0xC0,
0xC0, 0xC0, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC4, 0xC4, 0xC4, 0xC4, 0xC6, 0xC6, 0xC6, 0xC6, 0xC8,
0xC8, 0xC8, 0xC8, 0xC8, 0xCA, 0xCA, 0xCA, 0xCA, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0xCE, 0xCE,
0xCE, 0xCE, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD4, 0xD4, 0xD4, 0xD4,
0xD4, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xDA, 0xDA, 0xDA, 0xDA,
0xDA, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xE0, 0xE0, 0xE0,
};
DPLII::DPLII( s32 lowpass_freq, s32 samplerate ) :
LAccum( 0 ),
RAccum( 0 ),
ANum( 0 ),
lpf_l( lowpass_freq, samplerate ),
lpf_r( lowpass_freq, samplerate ),
bufdone( 1 ),
Gfl( 0 ),
Gfr( 0 ),
LMax( 0 ),
RMax( 0 )
DPLII::DPLII(s32 lowpass_freq, s32 samplerate)
: LAccum(0)
, RAccum(0)
, ANum(0)
, lpf_l(lowpass_freq, samplerate)
, lpf_r(lowpass_freq, samplerate)
, bufdone(1)
, Gfl(0)
, Gfr(0)
, LMax(0)
, RMax(0)
{
memset( LBuff, 0, sizeof( LBuff ) );
memset( RBuff, 0, sizeof( RBuff ) );
memset( spdif_data, 0, sizeof( spdif_data ) );
memset(LBuff, 0, sizeof(LBuff));
memset(RBuff, 0, sizeof(RBuff));
memset(spdif_data, 0, sizeof(spdif_data));
}
// Takes a single stereo input sample and translates it into six output samples
// for 5.1 audio support on non-DPL2 hardware.
void DPLII::Convert( s16 *obuffer, s32 ValL, s32 ValR )
void DPLII::Convert(s16 *obuffer, s32 ValL, s32 ValR)
{
ValL >>= 2;
ValR >>= 2;
if(PlayMode&4)
{
spdif_get_samples(spdif_data);
}
else
{
spdif_data[0]=0;
spdif_data[1]=0;
spdif_data[2]=0;
spdif_data[3]=0;
spdif_data[4]=0;
spdif_data[5]=0;
}
ValL >>= 2;
ValR >>= 2;
if (PlayMode & 4) {
spdif_get_samples(spdif_data);
} else {
spdif_data[0] = 0;
spdif_data[1] = 0;
spdif_data[2] = 0;
spdif_data[3] = 0;
spdif_data[4] = 0;
spdif_data[5] = 0;
}
//const u8 shift = SndOutVolumeShift;
//const u8 shift = SndOutVolumeShift;
s32 XL = abs(ValL>>8);
s32 XR = abs(ValR>>8);
s32 XL = abs(ValL >> 8);
s32 XR = abs(ValR >> 8);
if(XL>LMax) LMax = XL;
if(XR>RMax) RMax = XR;
if (XL > LMax)
LMax = XL;
if (XR > RMax)
RMax = XR;
ANum++;
if(ANum>=128)
{
ANum=0;
LAccum = 1+((LAccum * 224 + LMax * 31)>>8);
RAccum = 1+((RAccum * 224 + RMax * 31)>>8);
ANum++;
if (ANum >= 128) {
ANum = 0;
LAccum = 1 + ((LAccum * 224 + LMax * 31) >> 8);
RAccum = 1 + ((RAccum * 224 + RMax * 31) >> 8);
LMax = 0;
RMax = 0;
LMax = 0;
RMax = 0;
s32 Tfl=(RAccum)*255/(LAccum);
s32 Tfr=(LAccum)*255/(RAccum);
s32 Tfl = (RAccum)*255 / (LAccum);
s32 Tfr = (LAccum)*255 / (RAccum);
int gMax = max(Tfl,Tfr);
Tfl=Tfl*255/gMax;
Tfr=Tfr*255/gMax;
int gMax = max(Tfl, Tfr);
Tfl = Tfl * 255 / gMax;
Tfr = Tfr * 255 / gMax;
if(Tfl>255) Tfl=255;
if(Tfr>255) Tfr=255;
if(Tfl<1) Tfl=1;
if(Tfr<1) Tfr=1;
if (Tfl > 255)
Tfl = 255;
if (Tfr > 255)
Tfr = 255;
if (Tfl < 1)
Tfl = 1;
if (Tfr < 1)
Tfr = 1;
Gfl = (Gfl * 200 + Tfl * 56)>>8;
Gfr = (Gfr * 200 + Tfr * 56)>>8;
Gfl = (Gfl * 200 + Tfl * 56) >> 8;
Gfr = (Gfr * 200 + Tfr * 56) >> 8;
}
}
s32 L, R, C, LFE, SL, SR, LL, LR;
s32 L,R,C,LFE,SL,SR,LL,LR;
extern double pow_2_31;
LL = (s32)(lpf_l.sample((ValL >> 4) / pow_2_31) * pow_2_31);
LR = (s32)(lpf_r.sample((ValR >> 4) / pow_2_31) * pow_2_31);
LFE = (LL + LR) >> 4;
extern double pow_2_31;
LL = (s32)(lpf_l.sample((ValL>>4)/pow_2_31)*pow_2_31);
LR = (s32)(lpf_r.sample((ValR>>4)/pow_2_31)*pow_2_31);
LFE = (LL + LR)>>4;
C = (ValL + ValR) >> 1; //16.8
C=(ValL+ValR)>>1; //16.8
ValL -= C; //16.8
ValR -= C; //16.8
ValL-=C;//16.8
ValR-=C;//16.8
L = ValL >> 8; //16.0
R = ValR >> 8; //16.0
C = C >> 8; //16.0
L=ValL>>8; //16.0
R=ValR>>8; //16.0
C=C>>8; //16.0
const s32 Cfl = 1 + sLogTable[Gfl];
const s32 Cfr = 1 + sLogTable[Gfr];
const s32 Cfl = 1 + sLogTable[Gfl];
const s32 Cfr = 1 + sLogTable[Gfr];
const s32 VL = (ValL >> 4) * Cfl; //16.12
const s32 VR = (ValR >> 4) * Cfr;
const s32 VL = (ValL>>4) * Cfl; //16.12
const s32 VR = (ValR>>4) * Cfr;
const s32 SC = (VL - VR) >> 15;
const s32 SC = (VL-VR)>>15;
SL = (((VR / 148 - VL / 209) >> 4) * Cfr) >> 8;
SR = (((VR / 209 - VL / 148) >> 4) * Cfl) >> 8;
SL = (((VR/148 - VL/209)>>4)*Cfr)>>8;
SR = (((VR/209 - VL/148)>>4)*Cfl)>>8;
int AddCX = (C * Config_DSound51.AddCLR) >> 8;
int AddCX = (C * Config_DSound51.AddCLR)>>8;
obuffer[0]=spdif_data[0] + (((L * Config_DSound51.GainL ))>>8) + AddCX;
obuffer[1]=spdif_data[1] + (((R * Config_DSound51.GainR ))>>8) + AddCX;
obuffer[2]=spdif_data[2] + (((C * Config_DSound51.GainC ))>>8); // - AddCX;
obuffer[3]=spdif_data[3] + (((LFE * Config_DSound51.GainLFE))>>8);
obuffer[4]=spdif_data[4] + (((SL * Config_DSound51.GainSL ))>>8);
obuffer[5]=spdif_data[5] + (((SR * Config_DSound51.GainSR ))>>8);
obuffer[0] = spdif_data[0] + (((L * Config_DSound51.GainL)) >> 8) + AddCX;
obuffer[1] = spdif_data[1] + (((R * Config_DSound51.GainR)) >> 8) + AddCX;
obuffer[2] = spdif_data[2] + (((C * Config_DSound51.GainC)) >> 8); // - AddCX;
obuffer[3] = spdif_data[3] + (((LFE * Config_DSound51.GainLFE)) >> 8);
obuffer[4] = spdif_data[4] + (((SL * Config_DSound51.GainSL)) >> 8);
obuffer[5] = spdif_data[5] + (((SR * Config_DSound51.GainSR)) >> 8);
#if 0
if( UseAveraging )

File diff suppressed because it is too large Load Diff

View File

@ -21,154 +21,154 @@
#include "Global.h"
static const u8 sLogTable[256] = {
0x00,0x3C,0x60,0x78,0x8C,0x9C,0xA8,0xB4,0xBE,0xC8,0xD0,0xD8,0xDE,0xE4,0xEA,0xF0,
0xF6,0xFA,0xFE,0x04,0x08,0x0C,0x10,0x14,0x16,0x1A,0x1E,0x20,0x24,0x26,0x2A,0x2C,
0x2E,0x32,0x34,0x36,0x38,0x3A,0x3E,0x40,0x42,0x44,0x46,0x48,0x4A,0x4C,0x4E,0x50,
0x50,0x52,0x54,0x56,0x58,0x5A,0x5A,0x5C,0x5E,0x60,0x60,0x62,0x64,0x66,0x66,0x68,
0x6A,0x6A,0x6C,0x6E,0x6E,0x70,0x70,0x72,0x74,0x74,0x76,0x76,0x78,0x7A,0x7A,0x7C,
0x7C,0x7E,0x7E,0x80,0x80,0x82,0x82,0x84,0x84,0x86,0x86,0x88,0x88,0x8A,0x8A,0x8C,
0x8C,0x8C,0x8E,0x8E,0x90,0x90,0x92,0x92,0x92,0x94,0x94,0x96,0x96,0x96,0x98,0x98,
0x9A,0x9A,0x9A,0x9C,0x9C,0x9C,0x9E,0x9E,0xA0,0xA0,0xA0,0xA2,0xA2,0xA2,0xA4,0xA4,
0xA4,0xA6,0xA6,0xA6,0xA8,0xA8,0xA8,0xAA,0xAA,0xAA,0xAC,0xAC,0xAC,0xAC,0xAE,0xAE,
0xAE,0xB0,0xB0,0xB0,0xB2,0xB2,0xB2,0xB2,0xB4,0xB4,0xB4,0xB6,0xB6,0xB6,0xB6,0xB8,
0xB8,0xB8,0xB8,0xBA,0xBA,0xBA,0xBC,0xBC,0xBC,0xBC,0xBE,0xBE,0xBE,0xBE,0xC0,0xC0,
0xC0,0xC0,0xC2,0xC2,0xC2,0xC2,0xC2,0xC4,0xC4,0xC4,0xC4,0xC6,0xC6,0xC6,0xC6,0xC8,
0xC8,0xC8,0xC8,0xC8,0xCA,0xCA,0xCA,0xCA,0xCC,0xCC,0xCC,0xCC,0xCC,0xCE,0xCE,0xCE,
0xCE,0xCE,0xD0,0xD0,0xD0,0xD0,0xD0,0xD2,0xD2,0xD2,0xD2,0xD2,0xD4,0xD4,0xD4,0xD4,
0xD4,0xD6,0xD6,0xD6,0xD6,0xD6,0xD8,0xD8,0xD8,0xD8,0xD8,0xD8,0xDA,0xDA,0xDA,0xDA,
0xDA,0xDC,0xDC,0xDC,0xDC,0xDC,0xDC,0xDE,0xDE,0xDE,0xDE,0xDE,0xDE,0xE0,0xE0,0xE0,
0x00, 0x3C, 0x60, 0x78, 0x8C, 0x9C, 0xA8, 0xB4, 0xBE, 0xC8, 0xD0, 0xD8, 0xDE, 0xE4, 0xEA, 0xF0,
0xF6, 0xFA, 0xFE, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x16, 0x1A, 0x1E, 0x20, 0x24, 0x26, 0x2A, 0x2C,
0x2E, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3E, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x50,
0x50, 0x52, 0x54, 0x56, 0x58, 0x5A, 0x5A, 0x5C, 0x5E, 0x60, 0x60, 0x62, 0x64, 0x66, 0x66, 0x68,
0x6A, 0x6A, 0x6C, 0x6E, 0x6E, 0x70, 0x70, 0x72, 0x74, 0x74, 0x76, 0x76, 0x78, 0x7A, 0x7A, 0x7C,
0x7C, 0x7E, 0x7E, 0x80, 0x80, 0x82, 0x82, 0x84, 0x84, 0x86, 0x86, 0x88, 0x88, 0x8A, 0x8A, 0x8C,
0x8C, 0x8C, 0x8E, 0x8E, 0x90, 0x90, 0x92, 0x92, 0x92, 0x94, 0x94, 0x96, 0x96, 0x96, 0x98, 0x98,
0x9A, 0x9A, 0x9A, 0x9C, 0x9C, 0x9C, 0x9E, 0x9E, 0xA0, 0xA0, 0xA0, 0xA2, 0xA2, 0xA2, 0xA4, 0xA4,
0xA4, 0xA6, 0xA6, 0xA6, 0xA8, 0xA8, 0xA8, 0xAA, 0xAA, 0xAA, 0xAC, 0xAC, 0xAC, 0xAC, 0xAE, 0xAE,
0xAE, 0xB0, 0xB0, 0xB0, 0xB2, 0xB2, 0xB2, 0xB2, 0xB4, 0xB4, 0xB4, 0xB6, 0xB6, 0xB6, 0xB6, 0xB8,
0xB8, 0xB8, 0xB8, 0xBA, 0xBA, 0xBA, 0xBC, 0xBC, 0xBC, 0xBC, 0xBE, 0xBE, 0xBE, 0xBE, 0xC0, 0xC0,
0xC0, 0xC0, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC4, 0xC4, 0xC4, 0xC4, 0xC6, 0xC6, 0xC6, 0xC6, 0xC8,
0xC8, 0xC8, 0xC8, 0xC8, 0xCA, 0xCA, 0xCA, 0xCA, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0xCE, 0xCE,
0xCE, 0xCE, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD4, 0xD4, 0xD4, 0xD4,
0xD4, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xDA, 0xDA, 0xDA, 0xDA,
0xDA, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xE0, 0xE0, 0xE0,
};
static float Gfl=0,Gfr=0;
static float LMax=0,RMax=0;
static float Gfl = 0, Gfr = 0;
static float LMax = 0, RMax = 0;
static float AccL=0;
static float AccR=0;
static float AccL = 0;
static float AccR = 0;
const float Scale = 4294967296.0f; // tweak this value to change the overall output volume
const float Scale = 4294967296.0f; // tweak this value to change the overall output volume
const float GainL = 0.80f * Scale;
const float GainR = 0.80f * Scale;
const float GainL = 0.80f * Scale;
const float GainR = 0.80f * Scale;
const float GainC = 0.75f * Scale;
const float GainC = 0.75f * Scale;
const float GainSL = 0.90f * Scale;
const float GainSR = 0.90f * Scale;
const float GainLFE= 0.90f * Scale;
const float GainLFE = 0.90f * Scale;
const float AddCLR = 0.20f * Scale; // Stereo expansion
const float AddCLR = 0.20f * Scale; // Stereo expansion
extern void ResetDplIIDecoder()
{
Gfl=0;
Gfr=0;
LMax=0;
RMax=0;
AccL=0;
AccR=0;
Gfl = 0;
Gfr = 0;
LMax = 0;
RMax = 0;
AccL = 0;
AccR = 0;
}
void ProcessDplIISample32( const StereoOut32& src, Stereo51Out32DplII * s)
void ProcessDplIISample32(const StereoOut32 &src, Stereo51Out32DplII *s)
{
float IL = src.Left / (float)(1<<(SndOutVolumeShift+16));
float IR = src.Right / (float)(1<<(SndOutVolumeShift+16));
float IL = src.Left / (float)(1 << (SndOutVolumeShift + 16));
float IR = src.Right / (float)(1 << (SndOutVolumeShift + 16));
// Calculate center channel and LFE
float C = (IL+IR) * 0.5f;
float SUB = C; // no need to lowpass, the speaker amplifier should take care of it
// Calculate center channel and LFE
float C = (IL + IR) * 0.5f;
float SUB = C; // no need to lowpass, the speaker amplifier should take care of it
float L = IL - C; // Effective L/R data
float R = IR - C;
float L = IL - C; // Effective L/R data
float R = IR - C;
// Peak L/R
float PL = std::abs(L);
float PR = std::abs(R);
// Peak L/R
float PL = std::abs(L);
float PR = std::abs(R);
AccL += (PL-AccL)*0.1f;
AccR += (PR-AccR)*0.1f;
// Calculate power balance
float Balance = (AccR-AccL); // -1 .. 1
AccL += (PL - AccL) * 0.1f;
AccR += (PR - AccR) * 0.1f;
// If the power levels are different, then the audio is meant for the front speakers
float Frontness = std::abs(Balance);
float Rearness = 1-Frontness; // And the other way around
// Calculate power balance
float Balance = (AccR - AccL); // -1 .. 1
// Equalize the power levels for L/R
float B = std::min(0.9f,std::max(-0.9f,Balance));
// If the power levels are different, then the audio is meant for the front speakers
float Frontness = std::abs(Balance);
float Rearness = 1 - Frontness; // And the other way around
float VL = L / (1-B); // if B>0, it means R>L, so increase L, else decrease L
float VR = R / (1+B); // vice-versa
// Equalize the power levels for L/R
float B = std::min(0.9f, std::max(-0.9f, Balance));
// 1.73+1.22 = 2.94; 2.94 = 0.34 = 0.9996; Close enough.
// The range for VL/VR is approximately 0..1,
// But in the cases where VL/VR are > 0.5, Rearness is 0 so it should never overflow.
const float RearScale = 0.34f * 2;
float VL = L / (1 - B); // if B>0, it means R>L, so increase L, else decrease L
float VR = R / (1 + B); // vice-versa
float SL = (VR*1.73f - VL*1.22f) * RearScale * Rearness;
float SR = (VR*1.22f - VL*1.73f) * RearScale * Rearness;
// Possible experiment: Play with stereo expension levels on rear
// 1.73+1.22 = 2.94; 2.94 = 0.34 = 0.9996; Close enough.
// The range for VL/VR is approximately 0..1,
// But in the cases where VL/VR are > 0.5, Rearness is 0 so it should never overflow.
const float RearScale = 0.34f * 2;
// Adjust the volume of the front speakers based on what we calculated above
L *= Frontness;
R *= Frontness;
s32 CX = (s32)(C * AddCLR);
float SL = (VR * 1.73f - VL * 1.22f) * RearScale * Rearness;
float SR = (VR * 1.22f - VL * 1.73f) * RearScale * Rearness;
// Possible experiment: Play with stereo expension levels on rear
s->Left = (s32)(L * GainL ) + CX;
s->Right = (s32)(R * GainR ) + CX;
s->Center = (s32)(C * GainC );
s->LFE = (s32)(SUB * GainLFE);
s->LeftBack = (s32)(SL * GainSL );
s->RightBack = (s32)(SR * GainSR );
// Adjust the volume of the front speakers based on what we calculated above
L *= Frontness;
R *= Frontness;
s32 CX = (s32)(C * AddCLR);
s->Left = (s32)(L * GainL) + CX;
s->Right = (s32)(R * GainR) + CX;
s->Center = (s32)(C * GainC);
s->LFE = (s32)(SUB * GainLFE);
s->LeftBack = (s32)(SL * GainSL);
s->RightBack = (s32)(SR * GainSR);
}
void ProcessDplIISample16( const StereoOut32& src, Stereo51Out16DplII * s)
void ProcessDplIISample16(const StereoOut32 &src, Stereo51Out16DplII *s)
{
Stereo51Out32DplII ss;
ProcessDplIISample32(src, &ss);
Stereo51Out32DplII ss;
ProcessDplIISample32(src, &ss);
s->Left = ss.Left >> 16;
s->Right = ss.Right >> 16;
s->Center = ss.Center >> 16;
s->LFE = ss.LFE >> 16;
s->LeftBack = ss.LeftBack >> 16;
s->RightBack = ss.RightBack >> 16;
s->Left = ss.Left >> 16;
s->Right = ss.Right >> 16;
s->Center = ss.Center >> 16;
s->LFE = ss.LFE >> 16;
s->LeftBack = ss.LeftBack >> 16;
s->RightBack = ss.RightBack >> 16;
}
void ProcessDplSample32( const StereoOut32& src, Stereo51Out32Dpl * s)
void ProcessDplSample32(const StereoOut32 &src, Stereo51Out32Dpl *s)
{
float ValL = src.Left / (float)(1<<(SndOutVolumeShift+16));
float ValR = src.Right / (float)(1<<(SndOutVolumeShift+16));
float ValL = src.Left / (float)(1 << (SndOutVolumeShift + 16));
float ValR = src.Right / (float)(1 << (SndOutVolumeShift + 16));
float C = (ValL+ValR)*0.5f; //+15.8
float S = (ValL-ValR)*0.5f;
float C = (ValL + ValR) * 0.5f; //+15.8
float S = (ValL - ValR) * 0.5f;
float L=ValL-C; //+15.8
float R=ValR-C;
float L = ValL - C; //+15.8
float R = ValR - C;
float SUB = C;
s32 CX = (s32)(C * AddCLR); // +15.16
float SUB = C;
s->Left = (s32)(L * GainL ) + CX; // +15.16 = +31, can grow to +32 if (GainL + AddCLR)>255
s->Right = (s32)(R * GainR ) + CX;
s->Center = (s32)(C * GainC ); // +15.16 = +31
s->LFE = (s32)(SUB * GainLFE);
s->LeftBack = (s32)(S * GainSL );
s->RightBack = (s32)(S * GainSR );
s32 CX = (s32)(C * AddCLR); // +15.16
s->Left = (s32)(L * GainL) + CX; // +15.16 = +31, can grow to +32 if (GainL + AddCLR)>255
s->Right = (s32)(R * GainR) + CX;
s->Center = (s32)(C * GainC); // +15.16 = +31
s->LFE = (s32)(SUB * GainLFE);
s->LeftBack = (s32)(S * GainSL);
s->RightBack = (s32)(S * GainSR);
}
void ProcessDplSample16( const StereoOut32& src, Stereo51Out16Dpl * s)
void ProcessDplSample16(const StereoOut32 &src, Stereo51Out16Dpl *s)
{
Stereo51Out32Dpl ss;
ProcessDplSample32(src, &ss);
Stereo51Out32Dpl ss;
ProcessDplSample32(src, &ss);
s->Left = ss.Left >> 16;
s->Right = ss.Right >> 16;
s->Center = ss.Center >> 16;
s->LFE = ss.LFE >> 16;
s->LeftBack = ss.LeftBack >> 16;
s->RightBack = ss.RightBack >> 16;
s->Left = ss.Left >> 16;
s->Right = ss.Right >> 16;
s->Center = ss.Center >> 16;
s->LFE = ss.LFE >> 16;
s->LeftBack = ss.LeftBack >> 16;
s->RightBack = ss.RightBack >> 16;
}

View File

@ -30,7 +30,7 @@ struct V_Core;
namespace soundtouch
{
class SoundTouch;
class SoundTouch;
}
#include <assert.h>
@ -47,8 +47,8 @@ namespace soundtouch
namespace VersionInfo
{
static const u8 Release = 2;
static const u8 Revision = 0; // increase that with each version
static const u8 Release = 2;
static const u8 Revision = 0; // increase that with each version
}
//////////////////////////////////////////////////////////////////////////
@ -58,16 +58,16 @@ namespace VersionInfo
#undef min
#undef max
template< typename T >
static __forceinline void Clampify( T& src, T min, T max )
template <typename T>
static __forceinline void Clampify(T &src, T min, T max)
{
src = std::min( std::max( src, min ), max );
src = std::min(std::max(src, min), max);
}
template< typename T >
static __forceinline T GetClamped( T src, T min, T max )
template <typename T>
static __forceinline T GetClamped(T src, T min, T max)
{
return std::min( std::max( src, min ), max );
return std::min(std::max(src, min), max);
}
#ifdef __WXMAC__
@ -83,13 +83,13 @@ extern void SysMessage(const wchar_t *fmt, ...);
// Abbreviated macros for dev/debug only consoles and msgboxes.
#ifdef PCSX2_DEVBUILD
# define DevMsg MsgBox
#define DevMsg MsgBox
#else
# define DevMsg
#define DevMsg
#endif
#ifdef PCSX2_DEVBUILD
# define SPU2_LOG
#define SPU2_LOG
#endif
// Uncomment to enable debug keys on numpad (0 to 5)

View File

@ -15,9 +15,9 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Dialogs.h"
#include "Dialogs.h"
void AboutBox()
{
SysMessage("Yay: Aboutbox.");
SysMessage("Yay: Aboutbox.");
}

View File

@ -15,7 +15,7 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
// Adapted from ZeroSPU2 code by Zerofrog. Heavily modified by Arcum42.
// Adapted from ZeroSPU2 code by Zerofrog. Heavily modified by Arcum42.
#ifdef __linux__
@ -24,241 +24,229 @@
#include "Global.h"
#include "Alsa.h"
#include "SndOut.h"
// Does not work, except as effectively a null plugin.
class AlsaMod: public SndOutModule
class AlsaMod : public SndOutModule
{
protected:
static const int PacketsPerBuffer = 1; // increase this if ALSA can't keep up with 512-sample packets
static const int MAX_BUFFER_COUNT = 4;
static const int NumBuffers = 4; // TODO: this should be configurable someday -- lower values reduce latency.
unsigned int pspeed;
static const int PacketsPerBuffer = 1; // increase this if ALSA can't keep up with 512-sample packets
static const int MAX_BUFFER_COUNT = 4;
static const int NumBuffers = 4; // TODO: this should be configurable someday -- lower values reduce latency.
unsigned int pspeed;
snd_pcm_t *handle;
snd_pcm_uframes_t buffer_size;
snd_async_handler_t *pcm_callback;
snd_pcm_t *handle;
snd_pcm_uframes_t buffer_size;
snd_async_handler_t *pcm_callback;
uint period_time;
uint buffer_time;
uint period_time;
uint buffer_time;
protected:
// Invoked by the static ExternalCallback method below.
void _InternalCallback()
{
snd_pcm_sframes_t avail;
fprintf(stderr,"* SPU2-X:Iz in your internal callback.\n");
// Invoked by the static ExternalCallback method below.
void _InternalCallback()
{
snd_pcm_sframes_t avail;
fprintf(stderr, "* SPU2-X:Iz in your internal callback.\n");
avail = snd_pcm_avail_update( handle );
while (avail >= (int)period_time )
{
StereoOut16 buff[PacketsPerBuffer * SndOutPacketSize];
StereoOut16* p1 = buff;
avail = snd_pcm_avail_update(handle);
while (avail >= (int)period_time) {
StereoOut16 buff[PacketsPerBuffer * SndOutPacketSize];
StereoOut16 *p1 = buff;
for( int p=0; p<PacketsPerBuffer; p++, p1+=SndOutPacketSize )
SndBuffer::ReadSamples( p1 );
for (int p = 0; p < PacketsPerBuffer; p++, p1 += SndOutPacketSize)
SndBuffer::ReadSamples(p1);
snd_pcm_writei( handle, buff, period_time );
avail = snd_pcm_avail_update(handle);
}
}
snd_pcm_writei(handle, buff, period_time);
avail = snd_pcm_avail_update(handle);
}
}
// Preps and invokes the _InternalCallback above. This provides a cdecl-compliant
// entry point for our C++ified object state. :)
static void ExternalCallback( snd_async_handler_t *pcm_call)
{
fprintf(stderr,"* SPU2-X:Iz in your external callback.\n");
AlsaMod *data = (AlsaMod*)snd_async_handler_get_callback_private( pcm_call );
// Preps and invokes the _InternalCallback above. This provides a cdecl-compliant
// entry point for our C++ified object state. :)
static void ExternalCallback(snd_async_handler_t *pcm_call)
{
fprintf(stderr, "* SPU2-X:Iz in your external callback.\n");
AlsaMod *data = (AlsaMod *)snd_async_handler_get_callback_private(pcm_call);
pxAssume( data != NULL );
//pxAssume( data->handle == snd_async_handler_get_pcm(pcm_call) );
pxAssume(data != NULL);
//pxAssume( data->handle == snd_async_handler_get_pcm(pcm_call) );
// Not sure if we just need an assert, or something like this:
if (data->handle != snd_async_handler_get_pcm(pcm_call))
{
fprintf(stderr,"* SPU2-X: Failed to handle sound.\n");
return;
}
// Not sure if we just need an assert, or something like this:
if (data->handle != snd_async_handler_get_pcm(pcm_call)) {
fprintf(stderr, "* SPU2-X: Failed to handle sound.\n");
return;
}
data->_InternalCallback();
}
data->_InternalCallback();
}
public:
s32 Init()
{
//fprintf(stderr,"* SPU2-X: Initing Alsa\n");
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
snd_pcm_status_t *status;
int pchannels = 2;
snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
s32 Init()
{
//fprintf(stderr,"* SPU2-X: Initing Alsa\n");
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
snd_pcm_status_t *status;
int pchannels = 2;
snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
handle = NULL;
pcm_callback = NULL;
pspeed = SAMPLE_RATE;
handle = NULL;
pcm_callback = NULL;
pspeed = SAMPLE_RATE;
// buffer time and period time are in microseconds...
// (don't simplify the equation below -- it'll just cause integer rounding errors.
period_time = (SndOutPacketSize * 1000) / (SampleRate / 1000);
buffer_time = period_time * NumBuffers;
// buffer time and period time are in microseconds...
// (don't simplify the equation below -- it'll just cause integer rounding errors.
period_time = (SndOutPacketSize*1000) / (SampleRate / 1000);
buffer_time = period_time * NumBuffers;
int err;
int err;
err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC /*| SND_PCM_NONBLOCK*/);
if (err < 0) {
fprintf(stderr, "Audio open error: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC /*| SND_PCM_NONBLOCK*/);
if(err < 0)
{
fprintf(stderr,"Audio open error: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_nonblock(handle, 0);
if (err < 0) {
fprintf(stderr, "Can't set blocking mode: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_nonblock(handle, 0);
if(err < 0)
{
fprintf(stderr,"Can't set blocking mode: %s\n", snd_strerror(err));
return -1;
}
snd_pcm_hw_params_alloca(&hwparams);
snd_pcm_sw_params_alloca(&swparams);
snd_pcm_hw_params_alloca(&hwparams);
snd_pcm_sw_params_alloca(&swparams);
err = snd_pcm_hw_params_any(handle, hwparams);
if (err < 0) {
fprintf(stderr, "Broken configuration for this PCM: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_any(handle, hwparams);
if (err < 0)
{
fprintf(stderr,"Broken configuration for this PCM: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
if (err < 0) {
fprintf(stderr, "Access type not available: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
if (err < 0)
{
fprintf(stderr,"Access type not available: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_format(handle, hwparams, format);
if (err < 0) {
fprintf(stderr, "Sample format not available: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_format(handle, hwparams, format);
if (err < 0)
{
fprintf(stderr,"Sample format not available: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_channels(handle, hwparams, pchannels);
if (err < 0) {
fprintf(stderr, "Channels count not available: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0);
if (err < 0) {
fprintf(stderr, "Rate not available: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_channels(handle, hwparams, pchannels);
if (err < 0)
{
fprintf(stderr,"Channels count not available: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0);
if (err < 0)
{
fprintf(stderr,"Rate not available: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0);
if (err < 0) {
fprintf(stderr, "Buffer time error: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0);
if(err < 0) {
fprintf(stderr,"Buffer time error: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0);
if (err < 0) {
fprintf(stderr, "Period time error: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0);
if (err < 0)
{
fprintf(stderr,"Period time error: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params(handle, hwparams);
if (err < 0) {
fprintf(stderr, "Unable to install hw params: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params(handle, hwparams);
if (err < 0)
{
fprintf(stderr,"Unable to install hw params: %s\n", snd_strerror(err));
return -1;
}
snd_pcm_status_alloca(&status);
err = snd_pcm_status(handle, status);
if (err < 0) {
fprintf(stderr, "Unable to get status: %s\n", snd_strerror(err));
return -1;
}
snd_pcm_status_alloca(&status);
err = snd_pcm_status(handle, status);
if(err < 0)
{
fprintf(stderr,"Unable to get status: %s\n", snd_strerror(err));
return -1;
}
// Bind our asynchronous callback magic:
// Bind our asynchronous callback magic:
if (handle == NULL)
fprintf(stderr, "No handle.");
if (handle == NULL) fprintf(stderr, "No handle.");
//fprintf(stderr,"* SPU2-X:Iz setting your internal callback.\n");
// The external handler never seems to get called after this.
snd_async_add_pcm_handler( &pcm_callback, handle, ExternalCallback, this );
err = snd_pcm_start( handle );
if(err < 0)
{
fprintf(stderr,"Pcm start failed: %s\n", snd_strerror(err));
return -1;
}
// Diagnostic code:
//buffer_size = snd_pcm_status_get_avail(status);
//fprintf(stderr,"All set up.\n");
return 0;
}
//fprintf(stderr,"* SPU2-X:Iz setting your internal callback.\n");
// The external handler never seems to get called after this.
snd_async_add_pcm_handler(&pcm_callback, handle, ExternalCallback, this);
err = snd_pcm_start(handle);
if (err < 0) {
fprintf(stderr, "Pcm start failed: %s\n", snd_strerror(err));
return -1;
}
// Diagnostic code:
//buffer_size = snd_pcm_status_get_avail(status);
void Close()
{
//fprintf(stderr,"* SPU2-X: Closing Alsa\n");
if(handle == NULL) return;
//fprintf(stderr,"All set up.\n");
return 0;
}
snd_pcm_drop(handle);
snd_pcm_close(handle);
handle = NULL;
}
void Close()
{
//fprintf(stderr,"* SPU2-X: Closing Alsa\n");
if (handle == NULL)
return;
virtual void Configure(uptr parent)
{
}
snd_pcm_drop(handle);
snd_pcm_close(handle);
handle = NULL;
}
virtual bool Is51Out() const { return false; }
virtual void Configure(uptr parent)
{
}
s32 Test() const
{
return 0;
}
virtual bool Is51Out() const { return false; }
int GetEmptySampleCount()
{
if(handle == NULL)
{
fprintf(stderr,"Handle is NULL!\n");
return 0;
}
s32 Test() const
{
return 0;
}
// Returns the amount of free buffer space, in samples.
int l = snd_pcm_avail_update(handle);
if( l < 0 ) return 0;
return (l / 1000) * (SampleRate / 1000);
}
int GetEmptySampleCount()
{
if (handle == NULL) {
fprintf(stderr, "Handle is NULL!\n");
return 0;
}
const wchar_t* GetIdent() const
{
return L"Alsa";
}
// Returns the amount of free buffer space, in samples.
int l = snd_pcm_avail_update(handle);
if (l < 0)
return 0;
return (l / 1000) * (SampleRate / 1000);
}
const wchar_t* GetLongName() const
{
return L"Alsa";
}
const wchar_t *GetIdent() const
{
return L"Alsa";
}
void ReadSettings()
{
}
const wchar_t *GetLongName() const
{
return L"Alsa";
}
void SetApiSettings(wxString api)
{
}
void ReadSettings()
{
}
void WriteSettings() const
{
}
void SetApiSettings(wxString api)
{
}
void WriteSettings() const
{
}
} static Alsa;
SndOutModule *AlsaOut = &Alsa;

View File

@ -15,8 +15,8 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LINUX_H__
#define __LINUX_H__
#ifndef __LINUX_H__
#define __LINUX_H__
#include <assert.h>
#include <stdlib.h>
@ -32,11 +32,11 @@
extern int AlsaSetupSound();
extern void AlsaRemoveSound();
extern int AlsaSoundGetBytesBuffered();
extern void AlsaSoundFeedVoiceData(unsigned char* pSound,long lBytes);
extern void AlsaSoundFeedVoiceData(unsigned char *pSound, long lBytes);
extern int SetupSound();
extern void RemoveSound();
extern int SoundGetBytesBuffered();
extern void SoundFeedVoiceData(unsigned char* pSound,long lBytes);
extern void SoundFeedVoiceData(unsigned char *pSound, long lBytes);
#endif // __LINUX_H__
#endif // __LINUX_H__

View File

@ -15,93 +15,94 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Dialogs.h"
#include <wx/fileconf.h>
#include "Dialogs.h"
#include <wx/fileconf.h>
wxFileConfig *spuConfig = NULL;
wxString path(L"~/.pcsx2/inis/spu2-x.ini");
bool pathSet = false;
wxFileConfig *spuConfig = NULL;
wxString path(L"~/.pcsx2/inis/spu2-x.ini");
bool pathSet = false;
void initIni()
{
if (spuConfig == NULL) spuConfig = new wxFileConfig(L"", L"", path, L"", wxCONFIG_USE_LOCAL_FILE);
if (spuConfig == NULL)
spuConfig = new wxFileConfig(L"", L"", path, L"", wxCONFIG_USE_LOCAL_FILE);
}
void setIni(const wchar_t* Section)
{
initIni();
spuConfig->SetPath(wxsFormat(L"/%s", Section));
}
void CfgSetSettingsDir(const char* dir)
void setIni(const wchar_t *Section)
{
FileLog("CfgSetSettingsDir(%s)\n", dir);
path = wxString::FromAscii(dir) + L"/spu2-x.ini";
pathSet = true;
initIni();
spuConfig->SetPath(wxsFormat(L"/%s", Section));
}
void CfgWriteBool(const wchar_t* Section, const wchar_t* Name, bool Value)
void CfgSetSettingsDir(const char *dir)
{
setIni(Section);
spuConfig->Write(Name, Value);
FileLog("CfgSetSettingsDir(%s)\n", dir);
path = wxString::FromAscii(dir) + L"/spu2-x.ini";
pathSet = true;
}
void CfgWriteInt(const wchar_t* Section, const wchar_t* Name, int Value)
void CfgWriteBool(const wchar_t *Section, const wchar_t *Name, bool Value)
{
setIni(Section);
spuConfig->Write(Name, Value);
setIni(Section);
spuConfig->Write(Name, Value);
}
void CfgWriteFloat(const wchar_t* Section, const wchar_t* Name, float Value)
void CfgWriteInt(const wchar_t *Section, const wchar_t *Name, int Value)
{
setIni(Section);
spuConfig->Write(Name, (double)Value);
setIni(Section);
spuConfig->Write(Name, Value);
}
void CfgWriteStr(const wchar_t* Section, const wchar_t* Name, const wxString& Data)
void CfgWriteFloat(const wchar_t *Section, const wchar_t *Name, float Value)
{
setIni(Section);
spuConfig->Write(Name, Data);
setIni(Section);
spuConfig->Write(Name, (double)Value);
}
bool CfgReadBool(const wchar_t *Section,const wchar_t* Name, bool Default)
void CfgWriteStr(const wchar_t *Section, const wchar_t *Name, const wxString &Data)
{
bool ret;
setIni(Section);
spuConfig->Read(Name, &ret, Default);
return ret;
setIni(Section);
spuConfig->Write(Name, Data);
}
int CfgReadInt(const wchar_t* Section, const wchar_t* Name,int Default)
bool CfgReadBool(const wchar_t *Section, const wchar_t *Name, bool Default)
{
int ret;
bool ret;
setIni(Section);
spuConfig->Read(Name, &ret, Default);
setIni(Section);
spuConfig->Read(Name, &ret, Default);
return ret;
return ret;
}
float CfgReadFloat(const wchar_t* Section, const wchar_t* Name, float Default)
int CfgReadInt(const wchar_t *Section, const wchar_t *Name, int Default)
{
double ret;
int ret;
setIni(Section);
spuConfig->Read(Name, &ret, (double)Default);
setIni(Section);
spuConfig->Read(Name, &ret, Default);
return (float)ret;
return ret;
}
void CfgReadStr(const wchar_t* Section, const wchar_t* Name, wchar_t* Data, int DataSize, const wchar_t* Default)
float CfgReadFloat(const wchar_t *Section, const wchar_t *Name, float Default)
{
setIni(Section);
wcscpy(Data, spuConfig->Read(Name, Default).wc_str());
double ret;
setIni(Section);
spuConfig->Read(Name, &ret, (double)Default);
return (float)ret;
}
void CfgReadStr(const wchar_t* Section, const wchar_t* Name, wxString& Data, const wchar_t* Default)
void CfgReadStr(const wchar_t *Section, const wchar_t *Name, wchar_t *Data, int DataSize, const wchar_t *Default)
{
setIni(Section);
Data = spuConfig->Read(Name, Default);
setIni(Section);
wcscpy(Data, spuConfig->Read(Name, Default).wc_str());
}
void CfgReadStr(const wchar_t *Section, const wchar_t *Name, wxString &Data, const wchar_t *Default)
{
setIni(Section);
Data = spuConfig->Read(Name, Default);
}

View File

@ -32,7 +32,7 @@ static const int LATENCY_MAX = 750;
static const int LATENCY_MIN = 15;
int AutoDMAPlayRate[2] = {0,0};
int AutoDMAPlayRate[2] = {0, 0};
// Default settings.
@ -47,9 +47,9 @@ int Interpolation = 4;
*/
bool EffectsDisabled = false;
float FinalVolume; // global
float FinalVolume; // global
bool AdvancedVolumeControl;
float VolumeAdjustFLdb; // decibels settings, cos audiophiles love that
float VolumeAdjustFLdb; // decibels settings, cos audiophiles love that
float VolumeAdjustCdb;
float VolumeAdjustFRdb;
float VolumeAdjustBLdb;
@ -57,7 +57,7 @@ float VolumeAdjustBRdb;
float VolumeAdjustSLdb;
float VolumeAdjustSRdb;
float VolumeAdjustLFEdb;
float VolumeAdjustFL; // linear coefs calcualted from decibels,
float VolumeAdjustFL; // linear coefs calcualted from decibels,
float VolumeAdjustC;
float VolumeAdjustFR;
float VolumeAdjustBL;
@ -69,12 +69,12 @@ unsigned int delayCycles;
bool postprocess_filter_enabled = true;
bool postprocess_filter_dealias = false;
bool _visual_debug_enabled = false; // windows only feature
bool _visual_debug_enabled = false; // windows only feature
// OUTPUT
u32 OutputModule = 0;
int SndOutLatencyMS = 300;
int SynchMode = 0; // Time Stretch, Async or Disabled
int SynchMode = 0; // Time Stretch, Async or Disabled
static u32 OutputAPI = 0;
static u32 SdlOutputAPI = 0;
@ -84,135 +84,138 @@ int dplLevel = 0;
void ReadSettings()
{
// For some reason this can be called before we know what ini file we're writing to.
// Lets not try to read it if that happens.
if (!pathSet)
{
FileLog("Read called without the path set.\n");
return;
}
Interpolation = CfgReadInt( L"MIXING",L"Interpolation", 4 );
EffectsDisabled = CfgReadBool( L"MIXING", L"Disable_Effects", false );
postprocess_filter_dealias = CfgReadBool( L"MIXING", L"DealiasFilter", false );
FinalVolume = ((float)CfgReadInt( L"MIXING", L"FinalVolume", 100 )) / 100;
if ( FinalVolume > 1.0f) FinalVolume = 1.0f;
// For some reason this can be called before we know what ini file we're writing to.
// Lets not try to read it if that happens.
if (!pathSet) {
FileLog("Read called without the path set.\n");
return;
}
AdvancedVolumeControl = CfgReadBool(L"MIXING", L"AdvancedVolumeControl", false);
VolumeAdjustCdb = CfgReadFloat(L"MIXING", L"VolumeAdjustC(dB)", 0);
VolumeAdjustFLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustFL(dB)", 0);
VolumeAdjustFRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustFR(dB)", 0);
VolumeAdjustBLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustBL(dB)", 0);
VolumeAdjustBRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustBR(dB)", 0);
VolumeAdjustSLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustSL(dB)", 0);
VolumeAdjustSRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustSR(dB)", 0);
VolumeAdjustLFEdb = CfgReadFloat(L"MIXING", L"VolumeAdjustLFE(dB)", 0);
VolumeAdjustC = powf(10, VolumeAdjustCdb / 10);
VolumeAdjustFL = powf(10, VolumeAdjustFLdb / 10);
VolumeAdjustFR = powf(10, VolumeAdjustFRdb / 10);
VolumeAdjustBL = powf(10, VolumeAdjustBLdb / 10);
VolumeAdjustBR = powf(10, VolumeAdjustBRdb / 10);
VolumeAdjustSL = powf(10, VolumeAdjustSLdb / 10);
VolumeAdjustSR = powf(10, VolumeAdjustSRdb / 10);
VolumeAdjustLFE = powf(10, VolumeAdjustLFEdb / 10);
delayCycles = CfgReadInt(L"DEBUG", L"DelayCycles", 4);
Interpolation = CfgReadInt(L"MIXING", L"Interpolation", 4);
EffectsDisabled = CfgReadBool(L"MIXING", L"Disable_Effects", false);
postprocess_filter_dealias = CfgReadBool(L"MIXING", L"DealiasFilter", false);
FinalVolume = ((float)CfgReadInt(L"MIXING", L"FinalVolume", 100)) / 100;
if (FinalVolume > 1.0f)
FinalVolume = 1.0f;
AdvancedVolumeControl = CfgReadBool(L"MIXING", L"AdvancedVolumeControl", false);
VolumeAdjustCdb = CfgReadFloat(L"MIXING", L"VolumeAdjustC(dB)", 0);
VolumeAdjustFLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustFL(dB)", 0);
VolumeAdjustFRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustFR(dB)", 0);
VolumeAdjustBLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustBL(dB)", 0);
VolumeAdjustBRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustBR(dB)", 0);
VolumeAdjustSLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustSL(dB)", 0);
VolumeAdjustSRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustSR(dB)", 0);
VolumeAdjustLFEdb = CfgReadFloat(L"MIXING", L"VolumeAdjustLFE(dB)", 0);
VolumeAdjustC = powf(10, VolumeAdjustCdb / 10);
VolumeAdjustFL = powf(10, VolumeAdjustFLdb / 10);
VolumeAdjustFR = powf(10, VolumeAdjustFRdb / 10);
VolumeAdjustBL = powf(10, VolumeAdjustBLdb / 10);
VolumeAdjustBR = powf(10, VolumeAdjustBRdb / 10);
VolumeAdjustSL = powf(10, VolumeAdjustSLdb / 10);
VolumeAdjustSR = powf(10, VolumeAdjustSRdb / 10);
VolumeAdjustLFE = powf(10, VolumeAdjustLFEdb / 10);
delayCycles = CfgReadInt(L"DEBUG", L"DelayCycles", 4);
wxString temp;
CfgReadStr( L"OUTPUT", L"Output_Module", temp, PortaudioOut->GetIdent() );
OutputModule = FindOutputModuleById( temp.c_str() );// find the driver index of this module
wxString temp;
CfgReadStr(L"OUTPUT", L"Output_Module", temp, PortaudioOut->GetIdent());
OutputModule = FindOutputModuleById(temp.c_str()); // find the driver index of this module
// find current API
// find current API
#ifdef __linux__
CfgReadStr( L"PORTAUDIO", L"HostApi", temp, L"ALSA" );
OutputAPI = -1;
if (temp == L"ALSA") OutputAPI = 0;
if (temp == L"OSS") OutputAPI = 1;
if (temp == L"JACK") OutputAPI = 2;
CfgReadStr(L"PORTAUDIO", L"HostApi", temp, L"ALSA");
OutputAPI = -1;
if (temp == L"ALSA")
OutputAPI = 0;
if (temp == L"OSS")
OutputAPI = 1;
if (temp == L"JACK")
OutputAPI = 2;
#else
CfgReadStr( L"PORTAUDIO", L"HostApi", temp, L"OSS" );
OutputAPI = -1;
CfgReadStr(L"PORTAUDIO", L"HostApi", temp, L"OSS");
OutputAPI = -1;
if (temp == L"OSS") OutputAPI = 0;
if (temp == L"OSS")
OutputAPI = 0;
#endif
#ifdef __linux__
CfgReadStr( L"SDL", L"HostApi", temp, L"pulseaudio" );
SdlOutputAPI = -1;
CfgReadStr(L"SDL", L"HostApi", temp, L"pulseaudio");
SdlOutputAPI = -1;
#if SDL_MAJOR_VERSION >= 2
// YES It sucks ...
for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
if (!temp.Cmp(wxString(SDL_GetAudioDriver(i), wxConvUTF8)))
SdlOutputAPI = i;
}
// YES It sucks ...
for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
if (!temp.Cmp(wxString(SDL_GetAudioDriver(i), wxConvUTF8)))
SdlOutputAPI = i;
}
#endif
#endif
SndOutLatencyMS = CfgReadInt(L"OUTPUT",L"Latency", 300);
SynchMode = CfgReadInt( L"OUTPUT", L"Synch_Mode", 0);
SndOutLatencyMS = CfgReadInt(L"OUTPUT", L"Latency", 300);
SynchMode = CfgReadInt(L"OUTPUT", L"Synch_Mode", 0);
PortaudioOut->ReadSettings();
PortaudioOut->ReadSettings();
#ifdef __linux__
SDLOut->ReadSettings();
SDLOut->ReadSettings();
#endif
SoundtouchCfg::ReadSettings();
DebugConfig::ReadSettings();
SoundtouchCfg::ReadSettings();
DebugConfig::ReadSettings();
// Sanity Checks
// -------------
// Sanity Checks
// -------------
Clampify( SndOutLatencyMS, LATENCY_MIN, LATENCY_MAX );
Clampify(SndOutLatencyMS, LATENCY_MIN, LATENCY_MAX);
WriteSettings();
spuConfig->Flush();
WriteSettings();
spuConfig->Flush();
}
/*****************************************************************************/
void WriteSettings()
{
if (!pathSet)
{
FileLog("Write called without the path set.\n");
return;
}
if (!pathSet) {
FileLog("Write called without the path set.\n");
return;
}
CfgWriteInt(L"MIXING",L"Interpolation",Interpolation);
CfgWriteBool(L"MIXING",L"Disable_Effects",EffectsDisabled);
CfgWriteBool(L"MIXING",L"DealiasFilter",postprocess_filter_dealias);
CfgWriteInt(L"MIXING",L"FinalVolume",(int)(FinalVolume * 100 +0.5f));
CfgWriteInt(L"MIXING", L"Interpolation", Interpolation);
CfgWriteBool(L"MIXING", L"Disable_Effects", EffectsDisabled);
CfgWriteBool(L"MIXING", L"DealiasFilter", postprocess_filter_dealias);
CfgWriteInt(L"MIXING", L"FinalVolume", (int)(FinalVolume * 100 + 0.5f));
CfgWriteBool(L"MIXING", L"AdvancedVolumeControl", AdvancedVolumeControl);
CfgWriteFloat(L"MIXING", L"VolumeAdjustC(dB)", VolumeAdjustCdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustFL(dB)", VolumeAdjustFLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustFR(dB)", VolumeAdjustFRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustBL(dB)", VolumeAdjustBLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustBR(dB)", VolumeAdjustBRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustSL(dB)", VolumeAdjustSLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustSR(dB)", VolumeAdjustSRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustLFE(dB)", VolumeAdjustLFEdb);
CfgWriteBool(L"MIXING", L"AdvancedVolumeControl", AdvancedVolumeControl);
CfgWriteFloat(L"MIXING", L"VolumeAdjustC(dB)", VolumeAdjustCdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustFL(dB)", VolumeAdjustFLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustFR(dB)", VolumeAdjustFRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustBL(dB)", VolumeAdjustBLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustBR(dB)", VolumeAdjustBRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustSL(dB)", VolumeAdjustSLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustSR(dB)", VolumeAdjustSRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustLFE(dB)", VolumeAdjustLFEdb);
CfgWriteStr(L"OUTPUT",L"Output_Module", mods[OutputModule]->GetIdent() );
CfgWriteInt(L"OUTPUT",L"Latency", SndOutLatencyMS);
CfgWriteInt(L"OUTPUT",L"Synch_Mode", SynchMode);
CfgWriteInt(L"DEBUG", L"DelayCycles", delayCycles);
CfgWriteStr(L"OUTPUT", L"Output_Module", mods[OutputModule]->GetIdent());
CfgWriteInt(L"OUTPUT", L"Latency", SndOutLatencyMS);
CfgWriteInt(L"OUTPUT", L"Synch_Mode", SynchMode);
CfgWriteInt(L"DEBUG", L"DelayCycles", delayCycles);
PortaudioOut->WriteSettings();
PortaudioOut->WriteSettings();
#ifdef __linux__
SDLOut->WriteSettings();
SDLOut->WriteSettings();
#endif
SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings();
SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings();
}
void advanced_dialog()
{
SoundtouchCfg::DisplayDialog();
SoundtouchCfg::DisplayDialog();
}
void debug_dialog()
{
DebugConfig::DisplayDialog();
DebugConfig::DisplayDialog();
}
#if defined(__unix__)
@ -241,16 +244,16 @@ void DisplayDialog()
GtkWidget *advanced_button;
/* Create the widgets */
dialog = gtk_dialog_new_with_buttons (
"SPU2-X Config",
NULL, /* parent window*/
(GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
"OK", GTK_RESPONSE_ACCEPT,
"Cancel", GTK_RESPONSE_REJECT,
NULL);
dialog = gtk_dialog_new_with_buttons(
"SPU2-X Config",
NULL, /* parent window*/
(GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
"OK", GTK_RESPONSE_ACCEPT,
"Cancel", GTK_RESPONSE_REJECT,
NULL);
int_label = gtk_label_new ("Interpolation:");
int_box = gtk_combo_box_text_new ();
int_label = gtk_label_new("Interpolation:");
int_box = gtk_combo_box_text_new();
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(int_box), "0 - Nearest (fastest/bad quality)");
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(int_box), "1 - Linear (simple/okay sound)");
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(int_box), "2 - Cubic (artificial highs)");
@ -262,10 +265,10 @@ void DisplayDialog()
dealias_filter = gtk_check_button_new_with_label("Use the de-alias filter (overemphasizes the highs)");
debug_check = gtk_check_button_new_with_label("Enable Debug Options");
debug_button = gtk_button_new_with_label("Debug...");
debug_button = gtk_button_new_with_label("Debug...");
mod_label = gtk_label_new ("Module:");
mod_box = gtk_combo_box_text_new ();
mod_label = gtk_label_new("Module:");
mod_box = gtk_combo_box_text_new();
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(mod_box), "0 - No Sound (emulate SPU2 only)");
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(mod_box), "1 - PortAudio (cross-platform)");
#ifdef __linux__
@ -274,10 +277,10 @@ void DisplayDialog()
//gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(mod_box), "3 - Alsa (probably doesn't work)");
gtk_combo_box_set_active(GTK_COMBO_BOX(mod_box), OutputModule);
api_label = gtk_label_new ("PortAudio API:");
api_box = gtk_combo_box_text_new ();
api_label = gtk_label_new("PortAudio API:");
api_box = gtk_combo_box_text_new();
#ifdef __linux__
// In order to keep it the menu light, I only put linux major api
// In order to keep it the menu light, I only put linux major api
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(api_box), "0 - ALSA (recommended)");
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(api_box), "1 - OSS (legacy)");
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(api_box), "2 - JACK");
@ -287,8 +290,8 @@ void DisplayDialog()
gtk_combo_box_set_active(GTK_COMBO_BOX(api_box), OutputAPI);
#if SDL_MAJOR_VERSION >= 2
sdl_api_label = gtk_label_new ("SDL API:");
sdl_api_box = gtk_combo_box_text_new ();
sdl_api_label = gtk_label_new("SDL API:");
sdl_api_box = gtk_combo_box_text_new();
// YES It sucks ...
for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sdl_api_box), SDL_GetAudioDriver(i));
@ -296,7 +299,7 @@ void DisplayDialog()
gtk_combo_box_set_active(GTK_COMBO_BOX(sdl_api_box), SdlOutputAPI);
#endif
latency_label = gtk_label_new ("Latency:");
latency_label = gtk_label_new("Latency:");
#if GTK_MAJOR_VERSION < 3
latency_slide = gtk_hscale_new_with_range(LATENCY_MIN, LATENCY_MAX, 5);
#else
@ -304,123 +307,131 @@ void DisplayDialog()
#endif
gtk_range_set_value(GTK_RANGE(latency_slide), SndOutLatencyMS);
sync_label = gtk_label_new ("Synchronization Mode:");
sync_box = gtk_combo_box_text_new ();
sync_label = gtk_label_new("Synchronization Mode:");
sync_box = gtk_combo_box_text_new();
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sync_box), "TimeStretch (Recommended)");
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sync_box), "Async Mix (Breaks some games!)");
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sync_box), "None (Audio can skip.)");
gtk_combo_box_set_active(GTK_COMBO_BOX(sync_box), SynchMode);
advanced_button = gtk_button_new_with_label("Advanced...");
advanced_button = gtk_button_new_with_label("Advanced...");
main_box = gtk_hbox_new(false, 5);
main_frame = gtk_frame_new ("SPU2-X Config");
gtk_container_add (GTK_CONTAINER(main_frame), main_box);
main_frame = gtk_frame_new("SPU2-X Config");
gtk_container_add(GTK_CONTAINER(main_frame), main_box);
mixing_box = gtk_vbox_new(false, 5);
mixing_frame = gtk_frame_new ("Mixing Settings:");
gtk_container_add (GTK_CONTAINER(mixing_frame), mixing_box);
mixing_frame = gtk_frame_new("Mixing Settings:");
gtk_container_add(GTK_CONTAINER(mixing_frame), mixing_box);
output_box = gtk_vbox_new(false, 5);
output_frame = gtk_frame_new ("Output Settings:");
gtk_container_add (GTK_CONTAINER(output_frame), output_box);
output_frame = gtk_frame_new("Output Settings:");
gtk_container_add(GTK_CONTAINER(output_frame), output_box);
gtk_container_add(GTK_CONTAINER(mixing_box), int_label);
gtk_container_add(GTK_CONTAINER(mixing_box), int_box);
gtk_container_add(GTK_CONTAINER(mixing_box), effects_check);
gtk_container_add(GTK_CONTAINER(mixing_box), dealias_filter);
gtk_container_add(GTK_CONTAINER(mixing_box), debug_check);
gtk_container_add(GTK_CONTAINER(mixing_box), debug_button);
gtk_container_add(GTK_CONTAINER(mixing_box), int_label);
gtk_container_add(GTK_CONTAINER(mixing_box), int_box);
gtk_container_add(GTK_CONTAINER(mixing_box), effects_check);
gtk_container_add(GTK_CONTAINER(mixing_box), dealias_filter);
gtk_container_add(GTK_CONTAINER(mixing_box), debug_check);
gtk_container_add(GTK_CONTAINER(mixing_box), debug_button);
gtk_container_add(GTK_CONTAINER(output_box), mod_label);
gtk_container_add(GTK_CONTAINER(output_box), mod_box);
gtk_container_add(GTK_CONTAINER(output_box), api_label);
gtk_container_add(GTK_CONTAINER(output_box), api_box);
gtk_container_add(GTK_CONTAINER(output_box), mod_label);
gtk_container_add(GTK_CONTAINER(output_box), mod_box);
gtk_container_add(GTK_CONTAINER(output_box), api_label);
gtk_container_add(GTK_CONTAINER(output_box), api_box);
#if SDL_MAJOR_VERSION >= 2
gtk_container_add(GTK_CONTAINER(output_box), sdl_api_label);
gtk_container_add(GTK_CONTAINER(output_box), sdl_api_box);
gtk_container_add(GTK_CONTAINER(output_box), sdl_api_label);
gtk_container_add(GTK_CONTAINER(output_box), sdl_api_box);
#endif
gtk_container_add(GTK_CONTAINER(output_box), sync_label);
gtk_container_add(GTK_CONTAINER(output_box), sync_box);
gtk_container_add(GTK_CONTAINER(output_box), latency_label);
gtk_container_add(GTK_CONTAINER(output_box), latency_slide);
gtk_container_add(GTK_CONTAINER(output_box), advanced_button);
gtk_container_add(GTK_CONTAINER(output_box), sync_label);
gtk_container_add(GTK_CONTAINER(output_box), sync_box);
gtk_container_add(GTK_CONTAINER(output_box), latency_label);
gtk_container_add(GTK_CONTAINER(output_box), latency_slide);
gtk_container_add(GTK_CONTAINER(output_box), advanced_button);
gtk_container_add(GTK_CONTAINER(main_box), mixing_frame);
gtk_container_add(GTK_CONTAINER(main_box), output_frame);
gtk_container_add(GTK_CONTAINER(main_box), mixing_frame);
gtk_container_add(GTK_CONTAINER(main_box), output_frame);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(effects_check), EffectsDisabled);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dealias_filter), postprocess_filter_dealias);
//FinalVolume;
//FinalVolume;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(debug_check), DebugEnabled);
gtk_container_add (GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), main_frame);
gtk_widget_show_all (dialog);
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), main_frame);
gtk_widget_show_all(dialog);
g_signal_connect_swapped(advanced_button, "clicked", G_CALLBACK(advanced_dialog), advanced_button);
g_signal_connect_swapped(debug_button, "clicked", G_CALLBACK(debug_dialog), debug_button);
return_value = gtk_dialog_run (GTK_DIALOG (dialog));
return_value = gtk_dialog_run(GTK_DIALOG(dialog));
if (return_value == GTK_RESPONSE_ACCEPT)
{
DebugEnabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(debug_check));
postprocess_filter_dealias = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dealias_filter));
if (gtk_combo_box_get_active(GTK_COMBO_BOX(int_box)) != -1)
Interpolation = gtk_combo_box_get_active(GTK_COMBO_BOX(int_box));
if (return_value == GTK_RESPONSE_ACCEPT) {
DebugEnabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(debug_check));
postprocess_filter_dealias = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dealias_filter));
if (gtk_combo_box_get_active(GTK_COMBO_BOX(int_box)) != -1)
Interpolation = gtk_combo_box_get_active(GTK_COMBO_BOX(int_box));
EffectsDisabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(effects_check));
//FinalVolume;
EffectsDisabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(effects_check));
//FinalVolume;
if (gtk_combo_box_get_active(GTK_COMBO_BOX(mod_box)) != -1)
OutputModule = gtk_combo_box_get_active(GTK_COMBO_BOX(mod_box));
if (gtk_combo_box_get_active(GTK_COMBO_BOX(mod_box)) != -1)
OutputModule = gtk_combo_box_get_active(GTK_COMBO_BOX(mod_box));
if (gtk_combo_box_get_active(GTK_COMBO_BOX(api_box)) != -1) {
OutputAPI = gtk_combo_box_get_active(GTK_COMBO_BOX(api_box));
if (gtk_combo_box_get_active(GTK_COMBO_BOX(api_box)) != -1) {
OutputAPI = gtk_combo_box_get_active(GTK_COMBO_BOX(api_box));
#ifdef __linux__
switch(OutputAPI) {
case 0: PortaudioOut->SetApiSettings(L"ALSA"); break;
case 1: PortaudioOut->SetApiSettings(L"OSS"); break;
case 2: PortaudioOut->SetApiSettings(L"JACK"); break;
default: PortaudioOut->SetApiSettings(L"Unknown");
}
switch (OutputAPI) {
case 0:
PortaudioOut->SetApiSettings(L"ALSA");
break;
case 1:
PortaudioOut->SetApiSettings(L"OSS");
break;
case 2:
PortaudioOut->SetApiSettings(L"JACK");
break;
default:
PortaudioOut->SetApiSettings(L"Unknown");
}
#else
switch(OutputAPI) {
case 0: PortaudioOut->SetApiSettings(L"OSS"); break;
default: PortaudioOut->SetApiSettings(L"Unknown");
}
switch (OutputAPI) {
case 0:
PortaudioOut->SetApiSettings(L"OSS");
break;
default:
PortaudioOut->SetApiSettings(L"Unknown");
}
#endif
}
}
#if SDL_MAJOR_VERSION >= 2
if (gtk_combo_box_get_active(GTK_COMBO_BOX(sdl_api_box)) != -1) {
SdlOutputAPI = gtk_combo_box_get_active(GTK_COMBO_BOX(sdl_api_box));
// YES It sucks ...
SDLOut->SetApiSettings(wxString(SDL_GetAudioDriver(SdlOutputAPI), wxConvUTF8));
}
if (gtk_combo_box_get_active(GTK_COMBO_BOX(sdl_api_box)) != -1) {
SdlOutputAPI = gtk_combo_box_get_active(GTK_COMBO_BOX(sdl_api_box));
// YES It sucks ...
SDLOut->SetApiSettings(wxString(SDL_GetAudioDriver(SdlOutputAPI), wxConvUTF8));
}
#endif
SndOutLatencyMS = gtk_range_get_value(GTK_RANGE(latency_slide));
if (gtk_combo_box_get_active(GTK_COMBO_BOX(sync_box)) != -1)
SynchMode = gtk_combo_box_get_active(GTK_COMBO_BOX(sync_box));
SndOutLatencyMS = gtk_range_get_value(GTK_RANGE(latency_slide));
if (gtk_combo_box_get_active(GTK_COMBO_BOX(sync_box)) != -1)
SynchMode = gtk_combo_box_get_active(GTK_COMBO_BOX(sync_box));
}
gtk_widget_destroy (dialog);
gtk_widget_destroy(dialog);
}
#else
void DisplayDialog()
{
}
#endif
void configure()
{
initIni();
ReadSettings();
DisplayDialog();
WriteSettings();
delete spuConfig;
spuConfig = NULL;
initIni();
ReadSettings();
DisplayDialog();
WriteSettings();
delete spuConfig;
spuConfig = NULL;
}

View File

@ -82,16 +82,16 @@ extern u32 OutputModule;
extern int SndOutLatencyMS;
extern wchar_t dspPlugin[];
extern int dspPluginModule;
extern int dspPluginModule;
extern bool dspPluginEnabled;
extern bool dspPluginEnabled;
extern int SynchMode;
namespace SoundtouchCfg
{
void ReadSettings();
void WriteSettings();
void DisplayDialog();
void ReadSettings();
void WriteSettings();
void DisplayDialog();
};
void ReadSettings();
@ -101,4 +101,4 @@ void AboutBox();
extern wxFileConfig *spuConfig;
extern bool pathSet;
extern void initIni();
#endif // CONFIG_H_INCLUDED
#endif // CONFIG_H_INCLUDED

View File

@ -20,22 +20,22 @@
#include "Config.h"
#include "Utilities/Path.h"
bool DebugEnabled=false;
bool _MsgToConsole=false;
bool _MsgKeyOnOff=false;
bool _MsgVoiceOff=false;
bool _MsgDMA=false;
bool _MsgAutoDMA=false;
bool _MsgOverruns=false;
bool _MsgCache=false;
bool DebugEnabled = false;
bool _MsgToConsole = false;
bool _MsgKeyOnOff = false;
bool _MsgVoiceOff = false;
bool _MsgDMA = false;
bool _MsgAutoDMA = false;
bool _MsgOverruns = false;
bool _MsgCache = false;
bool _AccessLog=false;
bool _DMALog=false;
bool _WaveLog=false;
bool _AccessLog = false;
bool _DMALog = false;
bool _WaveLog = false;
bool _CoresDump=false;
bool _MemDump=false;
bool _RegDump=false;
bool _CoresDump = false;
bool _MemDump = false;
bool _RegDump = false;
// this is set true if PCSX2 invokes the SetLogDir callback, which tells SPU2-X to use that over
// the configured crap in the ini file.
@ -53,105 +53,105 @@ wxString CoresDumpFileName;
wxString MemDumpFileName;
wxString RegDumpFileName;
void CfgSetLogDir( const char* dir )
void CfgSetLogDir(const char *dir)
{
LogsFolder = (dir==NULL) ? wxString(L"logs") : fromUTF8(dir);
DumpsFolder = (dir==NULL) ? wxString(L"logs") : fromUTF8(dir);
LogLocationSetByPcsx2 = (dir!=NULL);
LogsFolder = (dir == NULL) ? wxString(L"logs") : fromUTF8(dir);
DumpsFolder = (dir == NULL) ? wxString(L"logs") : fromUTF8(dir);
LogLocationSetByPcsx2 = (dir != NULL);
}
FILE* OpenBinaryLog( const wxString& logfile )
FILE *OpenBinaryLog(const wxString &logfile)
{
return wxFopen( Path::Combine(LogsFolder, logfile), L"wb" );
return wxFopen(Path::Combine(LogsFolder, logfile), L"wb");
}
FILE* OpenLog( const wxString& logfile )
FILE *OpenLog(const wxString &logfile)
{
return wxFopen( Path::Combine(LogsFolder, logfile), L"w" );
return wxFopen(Path::Combine(LogsFolder, logfile), L"w");
}
FILE* OpenDump( const wxString& logfile )
FILE *OpenDump(const wxString &logfile)
{
return wxFopen( Path::Combine(DumpsFolder, logfile), L"w" );
return wxFopen(Path::Combine(DumpsFolder, logfile), L"w");
}
namespace DebugConfig {
static const wchar_t* Section = L"DEBUG";
namespace DebugConfig
{
static const wchar_t *Section = L"DEBUG";
static void set_default_filenames()
{
AccessLogFileName = L"SPU2Log.txt";
WaveLogFileName = L"SPU2log.wav";
DMA4LogFileName = L"SPU2dma4.dat";
DMA7LogFileName = L"SPU2dma7.dat";
AccessLogFileName = L"SPU2Log.txt";
WaveLogFileName = L"SPU2log.wav";
DMA4LogFileName = L"SPU2dma4.dat";
DMA7LogFileName = L"SPU2dma7.dat";
CoresDumpFileName = L"SPU2Cores.txt";
MemDumpFileName = L"SPU2mem.dat";
RegDumpFileName = L"SPU2regs.dat";
CoresDumpFileName = L"SPU2Cores.txt";
MemDumpFileName = L"SPU2mem.dat";
RegDumpFileName = L"SPU2regs.dat";
}
void ReadSettings()
{
DebugEnabled = CfgReadBool(Section, L"Global_Enable",0);
_MsgToConsole= CfgReadBool(Section, L"Show_Messages",0);
_MsgKeyOnOff = CfgReadBool(Section, L"Show_Messages_Key_On_Off",0);
_MsgVoiceOff = CfgReadBool(Section, L"Show_Messages_Voice_Off",0);
_MsgDMA = CfgReadBool(Section, L"Show_Messages_DMA_Transfer",0);
_MsgAutoDMA = CfgReadBool(Section, L"Show_Messages_AutoDMA",0);
_MsgOverruns = CfgReadBool(Section, L"Show_Messages_Overruns",0);
_MsgCache = CfgReadBool(Section, L"Show_Messages_CacheStats",0);
DebugEnabled = CfgReadBool(Section, L"Global_Enable", 0);
_MsgToConsole = CfgReadBool(Section, L"Show_Messages", 0);
_MsgKeyOnOff = CfgReadBool(Section, L"Show_Messages_Key_On_Off", 0);
_MsgVoiceOff = CfgReadBool(Section, L"Show_Messages_Voice_Off", 0);
_MsgDMA = CfgReadBool(Section, L"Show_Messages_DMA_Transfer", 0);
_MsgAutoDMA = CfgReadBool(Section, L"Show_Messages_AutoDMA", 0);
_MsgOverruns = CfgReadBool(Section, L"Show_Messages_Overruns", 0);
_MsgCache = CfgReadBool(Section, L"Show_Messages_CacheStats", 0);
_AccessLog = CfgReadBool(Section, L"Log_Register_Access",0);
_DMALog = CfgReadBool(Section, L"Log_DMA_Transfers",0);
_WaveLog = CfgReadBool(Section, L"Log_WAVE_Output",0);
_AccessLog = CfgReadBool(Section, L"Log_Register_Access", 0);
_DMALog = CfgReadBool(Section, L"Log_DMA_Transfers", 0);
_WaveLog = CfgReadBool(Section, L"Log_WAVE_Output", 0);
_CoresDump = CfgReadBool(Section, L"Dump_Info",0);
_MemDump = CfgReadBool(Section, L"Dump_Memory",0);
_RegDump = CfgReadBool(Section, L"Dump_Regs",0);
_CoresDump = CfgReadBool(Section, L"Dump_Info", 0);
_MemDump = CfgReadBool(Section, L"Dump_Memory", 0);
_RegDump = CfgReadBool(Section, L"Dump_Regs", 0);
set_default_filenames();
set_default_filenames();
CfgReadStr(Section,L"Access_Log_Filename",AccessLogFileName, L"logs/SPU2Log.txt");
CfgReadStr(Section,L"WaveLog_Filename", WaveLogFileName, L"logs/SPU2log.wav");
CfgReadStr(Section,L"DMA4Log_Filename", DMA4LogFileName, L"logs/SPU2dma4.dat");
CfgReadStr(Section,L"DMA7Log_Filename", DMA7LogFileName, L"logs/SPU2dma7.dat");
CfgReadStr(Section, L"Access_Log_Filename", AccessLogFileName, L"logs/SPU2Log.txt");
CfgReadStr(Section, L"WaveLog_Filename", WaveLogFileName, L"logs/SPU2log.wav");
CfgReadStr(Section, L"DMA4Log_Filename", DMA4LogFileName, L"logs/SPU2dma4.dat");
CfgReadStr(Section, L"DMA7Log_Filename", DMA7LogFileName, L"logs/SPU2dma7.dat");
CfgReadStr(Section,L"Info_Dump_Filename",CoresDumpFileName, L"logs/SPU2Cores.txt");
CfgReadStr(Section,L"Mem_Dump_Filename", MemDumpFileName, L"logs/SPU2mem.dat");
CfgReadStr(Section,L"Reg_Dump_Filename", RegDumpFileName, L"logs/SPU2regs.dat");
CfgReadStr(Section, L"Info_Dump_Filename", CoresDumpFileName, L"logs/SPU2Cores.txt");
CfgReadStr(Section, L"Mem_Dump_Filename", MemDumpFileName, L"logs/SPU2mem.dat");
CfgReadStr(Section, L"Reg_Dump_Filename", RegDumpFileName, L"logs/SPU2regs.dat");
}
void WriteSettings()
{
CfgWriteBool(Section,L"Global_Enable",DebugEnabled);
CfgWriteBool(Section, L"Global_Enable", DebugEnabled);
CfgWriteBool(Section,L"Show_Messages", _MsgToConsole);
CfgWriteBool(Section,L"Show_Messages_Key_On_Off", _MsgKeyOnOff);
CfgWriteBool(Section,L"Show_Messages_Voice_Off", _MsgVoiceOff);
CfgWriteBool(Section,L"Show_Messages_DMA_Transfer",_MsgDMA);
CfgWriteBool(Section,L"Show_Messages_AutoDMA", _MsgAutoDMA);
CfgWriteBool(Section,L"Show_Messages_Overruns", _MsgOverruns);
CfgWriteBool(Section,L"Show_Messages_CacheStats", _MsgCache);
CfgWriteBool(Section, L"Show_Messages", _MsgToConsole);
CfgWriteBool(Section, L"Show_Messages_Key_On_Off", _MsgKeyOnOff);
CfgWriteBool(Section, L"Show_Messages_Voice_Off", _MsgVoiceOff);
CfgWriteBool(Section, L"Show_Messages_DMA_Transfer", _MsgDMA);
CfgWriteBool(Section, L"Show_Messages_AutoDMA", _MsgAutoDMA);
CfgWriteBool(Section, L"Show_Messages_Overruns", _MsgOverruns);
CfgWriteBool(Section, L"Show_Messages_CacheStats", _MsgCache);
CfgWriteBool(Section,L"Log_Register_Access",_AccessLog);
CfgWriteBool(Section,L"Log_DMA_Transfers", _DMALog);
CfgWriteBool(Section,L"Log_WAVE_Output", _WaveLog);
CfgWriteBool(Section, L"Log_Register_Access", _AccessLog);
CfgWriteBool(Section, L"Log_DMA_Transfers", _DMALog);
CfgWriteBool(Section, L"Log_WAVE_Output", _WaveLog);
CfgWriteBool(Section,L"Dump_Info", _CoresDump);
CfgWriteBool(Section,L"Dump_Memory",_MemDump);
CfgWriteBool(Section,L"Dump_Regs", _RegDump);
CfgWriteBool(Section, L"Dump_Info", _CoresDump);
CfgWriteBool(Section, L"Dump_Memory", _MemDump);
CfgWriteBool(Section, L"Dump_Regs", _RegDump);
set_default_filenames();
CfgWriteStr(Section,L"Access_Log_Filename",AccessLogFileName);
CfgWriteStr(Section,L"WaveLog_Filename", WaveLogFileName);
CfgWriteStr(Section,L"DMA4Log_Filename", DMA4LogFileName);
CfgWriteStr(Section,L"DMA7Log_Filename", DMA7LogFileName);
CfgWriteStr(Section,L"Info_Dump_Filename",CoresDumpFileName);
CfgWriteStr(Section,L"Mem_Dump_Filename", MemDumpFileName);
CfgWriteStr(Section,L"Reg_Dump_Filename", RegDumpFileName);
set_default_filenames();
CfgWriteStr(Section, L"Access_Log_Filename", AccessLogFileName);
CfgWriteStr(Section, L"WaveLog_Filename", WaveLogFileName);
CfgWriteStr(Section, L"DMA4Log_Filename", DMA4LogFileName);
CfgWriteStr(Section, L"DMA7Log_Filename", DMA7LogFileName);
CfgWriteStr(Section, L"Info_Dump_Filename", CoresDumpFileName);
CfgWriteStr(Section, L"Mem_Dump_Filename", MemDumpFileName);
CfgWriteStr(Section, L"Reg_Dump_Filename", RegDumpFileName);
}
#ifdef __unix__
@ -169,26 +169,26 @@ void DisplayDialog()
GtkWidget *log_access_check, *log_dma_check, *log_wave_check;
GtkWidget *dump_core_check, *dump_mem_check, *dump_reg_check;
ReadSettings();
ReadSettings();
// Create the widgets
dialog = gtk_dialog_new_with_buttons (
"Spu2-X Config",
NULL, // parent window
(GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
"OK", GTK_RESPONSE_ACCEPT,
"Cancel", GTK_RESPONSE_REJECT,
NULL);
dialog = gtk_dialog_new_with_buttons(
"Spu2-X Config",
NULL, // parent window
(GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
"OK", GTK_RESPONSE_ACCEPT,
"Cancel", GTK_RESPONSE_REJECT,
NULL);
main_box = gtk_hbox_new(false, 5);
main_frame = gtk_frame_new ("Spu2-X Config");
gtk_container_add (GTK_CONTAINER(main_frame), main_box);
main_frame = gtk_frame_new("Spu2-X Config");
gtk_container_add(GTK_CONTAINER(main_frame), main_box);
// Message Section
msg_box = gtk_vbox_new(false, 5);
msg_box = gtk_vbox_new(false, 5);
msg_console_check = gtk_check_button_new_with_label("Show In Console");
msg_console_check = gtk_check_button_new_with_label("Show In Console");
msg_key_check = gtk_check_button_new_with_label("KeyOn/Off Events");
msg_voice_check = gtk_check_button_new_with_label("Voice Stop Events");
msg_dma_check = gtk_check_button_new_with_label("DMA Operations");
@ -196,13 +196,13 @@ void DisplayDialog()
msg_overrun_check = gtk_check_button_new_with_label("Buffer Over/Underruns");
msg_cache_check = gtk_check_button_new_with_label("ADPCM Cache Statistics");
gtk_container_add(GTK_CONTAINER(msg_box), msg_console_check);
gtk_container_add(GTK_CONTAINER(msg_box), msg_key_check);
gtk_container_add(GTK_CONTAINER(msg_box), msg_voice_check);
gtk_container_add(GTK_CONTAINER(msg_box), msg_dma_check);
gtk_container_add(GTK_CONTAINER(msg_box), msg_autodma_check);
gtk_container_add(GTK_CONTAINER(msg_box), msg_overrun_check);
gtk_container_add(GTK_CONTAINER(msg_box), msg_cache_check);
gtk_container_add(GTK_CONTAINER(msg_box), msg_console_check);
gtk_container_add(GTK_CONTAINER(msg_box), msg_key_check);
gtk_container_add(GTK_CONTAINER(msg_box), msg_voice_check);
gtk_container_add(GTK_CONTAINER(msg_box), msg_dma_check);
gtk_container_add(GTK_CONTAINER(msg_box), msg_autodma_check);
gtk_container_add(GTK_CONTAINER(msg_box), msg_overrun_check);
gtk_container_add(GTK_CONTAINER(msg_box), msg_cache_check);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(msg_console_check), _MsgToConsole);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(msg_key_check), _MsgKeyOnOff);
@ -212,26 +212,26 @@ void DisplayDialog()
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(msg_overrun_check), _MsgOverruns);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(msg_cache_check), _MsgCache);
msg_frame = gtk_frame_new ("Message/Log Options");
gtk_container_add (GTK_CONTAINER(msg_frame), msg_box);
msg_frame = gtk_frame_new("Message/Log Options");
gtk_container_add(GTK_CONTAINER(msg_frame), msg_box);
// Log Section
log_box = gtk_vbox_new(false, 5);
log_box = gtk_vbox_new(false, 5);
log_access_check = gtk_check_button_new_with_label("Log Register/DMA Actions");
log_dma_check = gtk_check_button_new_with_label("Log DMA Writes");
log_wave_check = gtk_check_button_new_with_label("Log Audio Output");
gtk_container_add(GTK_CONTAINER(log_box), log_access_check);
gtk_container_add(GTK_CONTAINER(log_box), log_dma_check);
gtk_container_add(GTK_CONTAINER(log_box), log_wave_check);
gtk_container_add(GTK_CONTAINER(log_box), log_access_check);
gtk_container_add(GTK_CONTAINER(log_box), log_dma_check);
gtk_container_add(GTK_CONTAINER(log_box), log_wave_check);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(log_access_check), _AccessLog);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(log_dma_check), _DMALog);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(log_wave_check), _WaveLog);
log_frame = gtk_frame_new ("Log Options");
gtk_container_add (GTK_CONTAINER(log_frame), log_box);
log_frame = gtk_frame_new("Log Options");
gtk_container_add(GTK_CONTAINER(log_frame), log_box);
// Dump Section
dump_box = gtk_vbox_new(false, 5);
@ -240,56 +240,54 @@ void DisplayDialog()
dump_mem_check = gtk_check_button_new_with_label("Dump Memory Contents");
dump_reg_check = gtk_check_button_new_with_label("Dump Register Data");
gtk_container_add(GTK_CONTAINER(dump_box), dump_core_check);
gtk_container_add(GTK_CONTAINER(dump_box), dump_mem_check);
gtk_container_add(GTK_CONTAINER(dump_box), dump_reg_check);
gtk_container_add(GTK_CONTAINER(dump_box), dump_core_check);
gtk_container_add(GTK_CONTAINER(dump_box), dump_mem_check);
gtk_container_add(GTK_CONTAINER(dump_box), dump_reg_check);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dump_core_check), _CoresDump);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dump_mem_check), _MemDump);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dump_reg_check), _RegDump);
dump_frame = gtk_frame_new ("Dumps (on close)");
gtk_container_add (GTK_CONTAINER(dump_frame), dump_box);
dump_frame = gtk_frame_new("Dumps (on close)");
gtk_container_add(GTK_CONTAINER(dump_frame), dump_box);
// Add everything
gtk_container_add (GTK_CONTAINER(main_box), msg_frame);
gtk_container_add (GTK_CONTAINER(main_box), log_frame);
gtk_container_add (GTK_CONTAINER(main_box), dump_frame);
gtk_container_add(GTK_CONTAINER(main_box), msg_frame);
gtk_container_add(GTK_CONTAINER(main_box), log_frame);
gtk_container_add(GTK_CONTAINER(main_box), dump_frame);
// Add all our widgets, and show everything we've added to the dialog.
gtk_container_add (GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), main_frame);
gtk_widget_show_all (dialog);
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), main_frame);
gtk_widget_show_all(dialog);
return_value = gtk_dialog_run (GTK_DIALOG (dialog));
return_value = gtk_dialog_run(GTK_DIALOG(dialog));
if (return_value == GTK_RESPONSE_ACCEPT)
{
_MsgToConsole = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_console_check));
_MsgKeyOnOff = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_key_check));
_MsgVoiceOff = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_voice_check));
_MsgDMA = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_dma_check));
_MsgAutoDMA = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_autodma_check));
_MsgOverruns = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_overrun_check));
_MsgCache = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_cache_check));
if (return_value == GTK_RESPONSE_ACCEPT) {
_MsgToConsole = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_console_check));
_MsgKeyOnOff = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_key_check));
_MsgVoiceOff = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_voice_check));
_MsgDMA = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_dma_check));
_MsgAutoDMA = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_autodma_check));
_MsgOverruns = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_overrun_check));
_MsgCache = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msg_cache_check));
_AccessLog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(log_access_check));
_DMALog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(log_dma_check));
_WaveLog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(log_wave_check));
_AccessLog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(log_access_check));
_DMALog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(log_dma_check));
_WaveLog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(log_wave_check));
_CoresDump = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dump_core_check));
_MemDump = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dump_mem_check));
_RegDump = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dump_reg_check));
_CoresDump = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dump_core_check));
_MemDump = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dump_mem_check));
_RegDump = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dump_reg_check));
}
gtk_widget_destroy (dialog);
gtk_widget_destroy(dialog);
WriteSettings();
}
#else
void DisplayDialog()
{
}
#endif
}

View File

@ -26,150 +26,147 @@
namespace SoundtouchCfg
{
// Timestretch Slider Bounds, Min/Max
static const int SequenceLen_Min = 20;
static const int SequenceLen_Max = 100;
// Timestretch Slider Bounds, Min/Max
static const int SequenceLen_Min = 20;
static const int SequenceLen_Max = 100;
static const int SeekWindow_Min = 10;
static const int SeekWindow_Max = 30;
static const int SeekWindow_Min = 10;
static const int SeekWindow_Max = 30;
static const int Overlap_Min = 5;
static const int Overlap_Max = 15;
static const int Overlap_Min = 5;
static const int Overlap_Max = 15;
static int SequenceLenMS = 30;
static int SeekWindowMS = 20;
static int OverlapMS = 10;
static int SequenceLenMS = 30;
static int SeekWindowMS = 20;
static int OverlapMS = 10;
static void ClampValues()
{
Clampify( SequenceLenMS, SequenceLen_Min, SequenceLen_Max );
Clampify( SeekWindowMS, SeekWindow_Min, SeekWindow_Max );
Clampify( OverlapMS, Overlap_Min, Overlap_Max );
}
static void ClampValues()
{
Clampify(SequenceLenMS, SequenceLen_Min, SequenceLen_Max);
Clampify(SeekWindowMS, SeekWindow_Min, SeekWindow_Max);
Clampify(OverlapMS, Overlap_Min, Overlap_Max);
}
void ApplySettings( soundtouch::SoundTouch& sndtouch )
{
sndtouch.setSetting( SETTING_SEQUENCE_MS, SequenceLenMS );
sndtouch.setSetting( SETTING_SEEKWINDOW_MS, SeekWindowMS );
sndtouch.setSetting( SETTING_OVERLAP_MS, OverlapMS );
}
void ApplySettings(soundtouch::SoundTouch &sndtouch)
{
sndtouch.setSetting(SETTING_SEQUENCE_MS, SequenceLenMS);
sndtouch.setSetting(SETTING_SEEKWINDOW_MS, SeekWindowMS);
sndtouch.setSetting(SETTING_OVERLAP_MS, OverlapMS);
}
void ReadSettings()
{
SequenceLenMS = CfgReadInt( L"SOUNDTOUCH", L"SequenceLengthMS", 30 );
SeekWindowMS = CfgReadInt( L"SOUNDTOUCH", L"SeekWindowMS", 20 );
OverlapMS = CfgReadInt( L"SOUNDTOUCH", L"OverlapMS", 10 );
void ReadSettings()
{
SequenceLenMS = CfgReadInt(L"SOUNDTOUCH", L"SequenceLengthMS", 30);
SeekWindowMS = CfgReadInt(L"SOUNDTOUCH", L"SeekWindowMS", 20);
OverlapMS = CfgReadInt(L"SOUNDTOUCH", L"OverlapMS", 10);
ClampValues();
WriteSettings();
}
ClampValues();
WriteSettings();
}
void WriteSettings()
{
CfgWriteInt( L"SOUNDTOUCH", L"SequenceLengthMS", SequenceLenMS );
CfgWriteInt( L"SOUNDTOUCH", L"SeekWindowMS", SeekWindowMS );
CfgWriteInt( L"SOUNDTOUCH", L"OverlapMS", OverlapMS );
}
void WriteSettings()
{
CfgWriteInt(L"SOUNDTOUCH", L"SequenceLengthMS", SequenceLenMS);
CfgWriteInt(L"SOUNDTOUCH", L"SeekWindowMS", SeekWindowMS);
CfgWriteInt(L"SOUNDTOUCH", L"OverlapMS", OverlapMS);
}
#ifdef __unix__
static GtkWidget *seq_label, *seek_label, *over_label;
static GtkWidget *seq_slide, *seek_slide, *over_slide;
static GtkWidget *seq_label, *seek_label, *over_label;
static GtkWidget *seq_slide, *seek_slide, *over_slide;
void restore_defaults()
{
gtk_range_set_value(GTK_RANGE(seq_slide), 30);
gtk_range_set_value(GTK_RANGE(seek_slide), 20);
gtk_range_set_value(GTK_RANGE(over_slide), 10);
}
void restore_defaults()
{
gtk_range_set_value(GTK_RANGE(seq_slide), 30);
gtk_range_set_value(GTK_RANGE(seek_slide), 20);
gtk_range_set_value(GTK_RANGE(over_slide), 10);
}
void DisplayDialog()
{
int return_value;
GtkWidget *dialog, *main_label, *main_frame, *main_box;
GtkWidget *default_button;
void DisplayDialog()
{
int return_value;
GtkWidget *dialog, *main_label, *main_frame, *main_box;
GtkWidget *default_button;
ReadSettings();
ReadSettings();
/* Create the widgets */
dialog = gtk_dialog_new_with_buttons (
"Advanced Settings",
NULL, /* parent window*/
(GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
"OK", GTK_RESPONSE_ACCEPT,
"Cancel", GTK_RESPONSE_REJECT,
NULL);
/* Create the widgets */
dialog = gtk_dialog_new_with_buttons(
"Advanced Settings",
NULL, /* parent window*/
(GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
"OK", GTK_RESPONSE_ACCEPT,
"Cancel", GTK_RESPONSE_REJECT,
NULL);
main_label = gtk_label_new ("These are advanced configuration options fine tuning time stretching behavior. Larger values are better for slowdown, while smaller values are better for speedup (more then 60 fps.). All options are in microseconds.");
gtk_label_set_line_wrap (GTK_LABEL(main_label), true);
main_label = gtk_label_new("These are advanced configuration options fine tuning time stretching behavior. Larger values are better for slowdown, while smaller values are better for speedup (more then 60 fps.). All options are in microseconds.");
gtk_label_set_line_wrap(GTK_LABEL(main_label), true);
default_button = gtk_button_new_with_label("Reset to Defaults");
default_button = gtk_button_new_with_label("Reset to Defaults");
seq_label = gtk_label_new("Sequence Length");
seq_label = gtk_label_new("Sequence Length");
#if GTK_MAJOR_VERSION < 3
seq_slide = gtk_hscale_new_with_range(SequenceLen_Min, SequenceLen_Max, 2);
seq_slide = gtk_hscale_new_with_range(SequenceLen_Min, SequenceLen_Max, 2);
#else
seq_slide = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, SequenceLen_Min, SequenceLen_Max, 2);
seq_slide = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, SequenceLen_Min, SequenceLen_Max, 2);
#endif
gtk_range_set_value(GTK_RANGE(seq_slide), SequenceLenMS);
gtk_range_set_value(GTK_RANGE(seq_slide), SequenceLenMS);
seek_label = gtk_label_new("Seek Window Size");
seek_label = gtk_label_new("Seek Window Size");
#if GTK_MAJOR_VERSION < 3
seek_slide = gtk_hscale_new_with_range(SeekWindow_Min, SeekWindow_Max, 1);
seek_slide = gtk_hscale_new_with_range(SeekWindow_Min, SeekWindow_Max, 1);
#else
seek_slide = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, SeekWindow_Min, SeekWindow_Max, 1);
seek_slide = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, SeekWindow_Min, SeekWindow_Max, 1);
#endif
gtk_range_set_value(GTK_RANGE(seek_slide), SeekWindowMS);
gtk_range_set_value(GTK_RANGE(seek_slide), SeekWindowMS);
over_label = gtk_label_new("Overlap");
over_label = gtk_label_new("Overlap");
#if GTK_MAJOR_VERSION < 3
over_slide = gtk_hscale_new_with_range(Overlap_Min, Overlap_Max, 1);
over_slide = gtk_hscale_new_with_range(Overlap_Min, Overlap_Max, 1);
#else
over_slide = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, Overlap_Min, Overlap_Max, 1);
over_slide = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, Overlap_Min, Overlap_Max, 1);
#endif
gtk_range_set_value(GTK_RANGE(over_slide), OverlapMS);
gtk_range_set_value(GTK_RANGE(over_slide), OverlapMS);
main_box = gtk_vbox_new(false, 5);
main_frame = gtk_frame_new ("Spu2-X Config");
main_box = gtk_vbox_new(false, 5);
main_frame = gtk_frame_new("Spu2-X Config");
gtk_container_add(GTK_CONTAINER (main_box), default_button);
gtk_container_add(GTK_CONTAINER (main_box), seq_label);
gtk_container_add(GTK_CONTAINER (main_box), seq_slide);
gtk_container_add(GTK_CONTAINER (main_box), seek_label);
gtk_container_add(GTK_CONTAINER (main_box), seek_slide);
gtk_container_add(GTK_CONTAINER (main_box), over_label);
gtk_container_add(GTK_CONTAINER (main_box), over_slide);
gtk_container_add(GTK_CONTAINER(main_frame), main_box);
gtk_container_add(GTK_CONTAINER(main_box), default_button);
gtk_container_add(GTK_CONTAINER(main_box), seq_label);
gtk_container_add(GTK_CONTAINER(main_box), seq_slide);
gtk_container_add(GTK_CONTAINER(main_box), seek_label);
gtk_container_add(GTK_CONTAINER(main_box), seek_slide);
gtk_container_add(GTK_CONTAINER(main_box), over_label);
gtk_container_add(GTK_CONTAINER(main_box), over_slide);
gtk_container_add(GTK_CONTAINER(main_frame), main_box);
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), main_label);
gtk_container_add (GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), main_frame);
gtk_widget_show_all (dialog);
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), main_label);
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), main_frame);
gtk_widget_show_all(dialog);
g_signal_connect_swapped(default_button, "clicked", G_CALLBACK(restore_defaults), default_button);
g_signal_connect_swapped(default_button, "clicked", G_CALLBACK(restore_defaults), default_button);
return_value = gtk_dialog_run (GTK_DIALOG (dialog));
return_value = gtk_dialog_run(GTK_DIALOG(dialog));
if (return_value == GTK_RESPONSE_ACCEPT)
{
SequenceLenMS = gtk_range_get_value(GTK_RANGE(seq_slide));;
SeekWindowMS = gtk_range_get_value(GTK_RANGE(seek_slide));;
OverlapMS = gtk_range_get_value(GTK_RANGE(over_slide));;
}
gtk_widget_destroy (dialog);
WriteSettings();
}
#else
void DisplayDialog()
{
if (return_value == GTK_RESPONSE_ACCEPT) {
SequenceLenMS = gtk_range_get_value(GTK_RANGE(seq_slide));
SeekWindowMS = gtk_range_get_value(GTK_RANGE(seek_slide));
OverlapMS = gtk_range_get_value(GTK_RANGE(over_slide));
}
void restore_defaults()
{
}
gtk_widget_destroy(dialog);
WriteSettings();
}
#else
void DisplayDialog()
{
}
void restore_defaults()
{
}
#endif
}

View File

@ -15,7 +15,7 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
// To be continued...
// To be continued...
#include "Dialogs.h"
#include <cstring>
@ -32,34 +32,35 @@ void SysMessage(const char *fmt, ...)
vsprintf(msg, fmt, list);
va_end(list);
if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0;
if (msg[strlen(msg) - 1] == '\n')
msg[strlen(msg) - 1] = 0;
GtkWidget *dialog;
dialog = gtk_message_dialog_new (NULL,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"%s", msg);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
dialog = gtk_message_dialog_new(NULL,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"%s", msg);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
void SysMessage(const wchar_t *fmt, ...)
{
va_list list;
va_start(list,fmt);
wxString msg;
msg.PrintfV( fmt, list );
va_end(list);
va_list list;
va_start(list, fmt);
wxString msg;
msg.PrintfV(fmt, list);
va_end(list);
GtkWidget *dialog;
dialog = gtk_message_dialog_new (NULL,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"%s", msg.ToUTF8().data());
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
dialog = gtk_message_dialog_new(NULL,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"%s", msg.ToUTF8().data());
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
#endif
@ -67,8 +68,7 @@ void DspUpdate()
{
}
s32 DspLoadLibrary(wchar_t* fileName, int modnum)
s32 DspLoadLibrary(wchar_t *fileName, int modnum)
{
return 0;
return 0;
}

View File

@ -23,23 +23,23 @@
namespace DebugConfig
{
extern void ReadSettings();
extern void WriteSettings();
extern void DisplayDialog();
extern void ReadSettings();
extern void WriteSettings();
extern void DisplayDialog();
}
extern void CfgSetSettingsDir(const char* dir);
extern void CfgSetLogDir(const char* dir);
extern void CfgSetSettingsDir(const char *dir);
extern void CfgSetLogDir(const char *dir);
extern void CfgWriteBool(const wchar_t* Section, const wchar_t* Name, bool Value);
extern void CfgWriteInt(const wchar_t* Section, const wchar_t* Name, int Value);
extern void CfgWriteFloat(const wchar_t* Section, const wchar_t* Name, float Value);
extern void CfgWriteStr(const wchar_t* Section, const wchar_t* Name, const wxString& Data);
extern void CfgWriteBool(const wchar_t *Section, const wchar_t *Name, bool Value);
extern void CfgWriteInt(const wchar_t *Section, const wchar_t *Name, int Value);
extern void CfgWriteFloat(const wchar_t *Section, const wchar_t *Name, float Value);
extern void CfgWriteStr(const wchar_t *Section, const wchar_t *Name, const wxString &Data);
extern bool CfgReadBool(const wchar_t *Section,const wchar_t* Name, bool Default);
extern void CfgReadStr(const wchar_t* Section, const wchar_t* Name, wxString& Data, const wchar_t* Default);
extern bool CfgReadBool(const wchar_t *Section, const wchar_t *Name, bool Default);
extern void CfgReadStr(const wchar_t *Section, const wchar_t *Name, wxString &Data, const wchar_t *Default);
//extern void CfgReadStr(const wchar_t* Section, const wchar_t* Name, wchar_t* Data, int DataSize, const wchar_t* Default);
extern int CfgReadInt(const wchar_t* Section, const wchar_t* Name,int Default) ;
extern float CfgReadFloat(const wchar_t* Section, const wchar_t* Name, float Default);
extern int CfgReadInt(const wchar_t *Section, const wchar_t *Name, int Default);
extern float CfgReadFloat(const wchar_t *Section, const wchar_t *Name, float Default);
#endif

View File

@ -20,75 +20,75 @@
#include <math.h>
#include <float.h>
template< typename FloatType > __forceinline
LowPassFilter<FloatType>::LowPassFilter( FloatType freq, FloatType srate )
template <typename FloatType>
__forceinline LowPassFilter<FloatType>::LowPassFilter(FloatType freq, FloatType srate)
{
typedef FloatType FT;
typedef FloatType FT;
FloatType omega = (FT)2.0 * freq / srate;
static const FloatType g = (FT)1.0;
FloatType omega = (FT)2.0 * freq / srate;
static const FloatType g = (FT)1.0;
// calculating coefficients:
// calculating coefficients:
FloatType k,p,q,a;
FloatType a0,a1,a2,a3,a4;
FloatType k, p, q, a;
FloatType a0, a1, a2, a3, a4;
k = ((FT)4.0*g-(FT)3.0)/(g+(FT)1.0);
p = (FT)1.0-(FT)0.25*k;
p *= p;
k = ((FT)4.0 * g - (FT)3.0) / (g + (FT)1.0);
p = (FT)1.0 - (FT)0.25 * k;
p *= p;
// LP:
a = (FT)1.0/(tan((FT)0.5*omega)*((FT)1.0+p));
p = (FT)1.0+a;
q = (FT)1.0-a;
// LP:
a = (FT)1.0 / (tan((FT)0.5 * omega) * ((FT)1.0 + p));
p = (FT)1.0 + a;
q = (FT)1.0 - a;
a0 = (FT)1.0/(k+p*p*p*p);
a1 = (FT)4.0*(k+p*p*p*q);
a2 = (FT)6.0*(k+p*p*q*q);
a3 = (FT)4.0*(k+p*q*q*q);
a4 = (k+q*q*q*q);
p = a0*(k+(FT)1.0);
a0 = (FT)1.0 / (k + p * p * p * p);
a1 = (FT)4.0 * (k + p * p * p * q);
a2 = (FT)6.0 * (k + p * p * q * q);
a3 = (FT)4.0 * (k + p * q * q * q);
a4 = (k + q * q * q * q);
p = a0 * (k + (FT)1.0);
coef[0] = p;
coef[1] = (FT)4.0*p;
coef[2] = (FT)6.0*p;
coef[3] = (FT)4.0*p;
coef[4] = p;
coef[5] = -a1*a0;
coef[6] = -a2*a0;
coef[7] = -a3*a0;
coef[8] = -a4*a0;
coef[0] = p;
coef[1] = (FT)4.0 * p;
coef[2] = (FT)6.0 * p;
coef[3] = (FT)4.0 * p;
coef[4] = p;
coef[5] = -a1 * a0;
coef[6] = -a2 * a0;
coef[7] = -a3 * a0;
coef[8] = -a4 * a0;
}
// Processes a single sample into the LPF.
template< typename FloatType > __forceinline
FloatType LowPassFilter<FloatType>::sample( FloatType inval )
template <typename FloatType>
__forceinline FloatType LowPassFilter<FloatType>::sample(FloatType inval)
{
const FloatType out = (coef[0]*inval) + d[0];
d[0] = (coef[1]*inval) + (coef[5]*out) + d[1];
d[1] = (coef[2]*inval) + (coef[6]*out) + d[2];
d[2] = (coef[3]*inval) + (coef[7]*out) + d[3];
d[3] = (coef[4]*inval) + (coef[8]*out);
const FloatType out = (coef[0] * inval) + d[0];
d[0] = (coef[1] * inval) + (coef[5] * out) + d[1];
d[1] = (coef[2] * inval) + (coef[6] * out) + d[2];
d[2] = (coef[3] * inval) + (coef[7] * out) + d[3];
d[3] = (coef[4] * inval) + (coef[8] * out);
return out;
return out;
}
LowPassFilter32::LowPassFilter32( float freq, float srate ) :
impl_lpf( freq, srate )
LowPassFilter32::LowPassFilter32(float freq, float srate)
: impl_lpf(freq, srate)
{
}
LowPassFilter64::LowPassFilter64( double freq, double srate ) :
impl_lpf( freq, srate )
LowPassFilter64::LowPassFilter64(double freq, double srate)
: impl_lpf(freq, srate)
{
}
float LowPassFilter32::sample( float inval )
float LowPassFilter32::sample(float inval)
{
return impl_lpf.sample( inval );
return impl_lpf.sample(inval);
}
double LowPassFilter64::sample( double inval )
double LowPassFilter64::sample(double inval)
{
return impl_lpf.sample( inval );
return impl_lpf.sample(inval);
}

View File

@ -17,28 +17,28 @@
#pragma once
template< typename FloatType >
template <typename FloatType>
struct LowPassFilter
{
FloatType coef[9];
FloatType d[4];
FloatType coef[9];
FloatType d[4];
LowPassFilter( FloatType freq, FloatType srate );
FloatType sample( FloatType inval );
LowPassFilter(FloatType freq, FloatType srate);
FloatType sample(FloatType inval);
};
struct LowPassFilter32
{
LowPassFilter<float> impl_lpf;
LowPassFilter<float> impl_lpf;
LowPassFilter32( float freq, float srate );
float sample( float inval );
LowPassFilter32(float freq, float srate);
float sample(float inval);
};
struct LowPassFilter64
{
LowPassFilter<double> impl_lpf;
LowPassFilter<double> impl_lpf;
LowPassFilter64( double freq, double srate );
double sample( double inval );
LowPassFilter64(double freq, double srate);
double sample(double inval);
};

File diff suppressed because it is too large Load Diff

View File

@ -24,115 +24,112 @@ extern float VolumeAdjustFR;
struct StereoOut32
{
static StereoOut32 Empty;
static StereoOut32 Empty;
s32 Left;
s32 Right;
s32 Left;
s32 Right;
StereoOut32() :
Left( 0 ),
Right( 0 )
{
}
StereoOut32()
: Left(0)
, Right(0)
{
}
StereoOut32( s32 left, s32 right ) :
Left( left ),
Right( right )
{
}
StereoOut32(s32 left, s32 right)
: Left(left)
, Right(right)
{
}
StereoOut32( const StereoOut16& src );
explicit StereoOut32( const StereoOutFloat& src );
StereoOut32(const StereoOut16 &src);
explicit StereoOut32(const StereoOutFloat &src);
StereoOut16 DownSample() const;
StereoOut16 DownSample() const;
StereoOut32 operator*( const int& factor ) const
{
return StereoOut32(
Left * factor,
Right * factor
);
}
StereoOut32 operator*(const int &factor) const
{
return StereoOut32(
Left * factor,
Right * factor);
}
StereoOut32& operator*=( const int& factor )
{
Left *= factor;
Right *= factor;
return *this;
}
StereoOut32 &operator*=(const int &factor)
{
Left *= factor;
Right *= factor;
return *this;
}
StereoOut32 operator+( const StereoOut32& right ) const
{
return StereoOut32(
Left + right.Left,
Right + right.Right
);
}
StereoOut32 operator+(const StereoOut32 &right) const
{
return StereoOut32(
Left + right.Left,
Right + right.Right);
}
StereoOut32 operator/( int src ) const
{
return StereoOut32( Left / src, Right / src );
}
StereoOut32 operator/(int src) const
{
return StereoOut32(Left / src, Right / src);
}
void ResampleFrom( const StereoOut32& src )
{
this->Left = src.Left << 2;
this->Right = src.Right << 2;
}
void ResampleFrom(const StereoOut32 &src)
{
this->Left = src.Left << 2;
this->Right = src.Right << 2;
}
void AdjustFrom(const StereoOut32& src)
{
ResampleFrom(src);
void AdjustFrom(const StereoOut32 &src)
{
ResampleFrom(src);
Left = (s32) (Left * VolumeAdjustFL);
Right = (s32) (Right * VolumeAdjustFR);
}
Left = (s32)(Left * VolumeAdjustFL);
Right = (s32)(Right * VolumeAdjustFR);
}
};
struct FrequencyResponseFilter
{
static FrequencyResponseFilter Empty;
static FrequencyResponseFilter Empty;
StereoOut32 History_One_In;
StereoOut32 History_One_Out;
StereoOut32 History_Two_In;
StereoOut32 History_Two_Out;
StereoOut32 History_One_In;
StereoOut32 History_One_Out;
StereoOut32 History_Two_In;
StereoOut32 History_Two_Out;
s32 lx1;
s32 lx2;
s32 ly1;
s32 ly2;
s32 lx1;
s32 lx2;
s32 ly1;
s32 ly2;
float la0, la1, la2, lb1, lb2;
float ha0, ha1, ha2, hb1, hb2;
float la0, la1, la2, lb1, lb2;
float ha0, ha1, ha2, hb1, hb2;
FrequencyResponseFilter() :
History_One_In( 0, 0 ),
History_One_Out( 0, 0 ),
History_Two_In( 0, 0 ),
History_Two_Out( 0, 0 ),
lx1 ( 0 ),
lx2 ( 0 ),
ly1 ( 0 ),
ly2 ( 0 ),
la0 ( 1.00320890889339290000f ),
la1 ( -1.97516434134506300000f ),
la2 ( 0.97243484967313087000f ),
lb1 ( -1.97525280404731810000f ),
lb2 ( 0.97555529586426892000f ),
FrequencyResponseFilter()
: History_One_In(0, 0)
, History_One_Out(0, 0)
, History_Two_In(0, 0)
, History_Two_Out(0, 0)
, lx1(0)
, lx2(0)
, ly1(0)
, ly2(0)
ha0 ( 1.52690772687271160000f ),
ha1 ( -1.62653918974914990000f ), //-1.72 = "common equilizer curve" --____--
ha2 ( 0.57997976029249387000f ),
hb1 ( -0.80955590379048203000f ),
hb2 ( 0.28990420120653748000f )
{
}
, la0(1.00320890889339290000f)
, la1(-1.97516434134506300000f)
, la2(0.97243484967313087000f)
, lb1(-1.97525280404731810000f)
, lb2(0.97555529586426892000f)
, ha0(1.52690772687271160000f)
, ha1(-1.62653918974914990000f) //-1.72 = "common equilizer curve" --____--
, ha2(0.57997976029249387000f)
, hb1(-0.80955590379048203000f)
, hb2(0.28990420120653748000f)
{
}
};
extern void Mix();
extern s32 clamp_mix( s32 x, u8 bitshift=0 );
extern void Mix();
extern s32 clamp_mix(s32 x, u8 bitshift = 0);
extern StereoOut32 clamp_mix( const StereoOut32& sample, u8 bitshift=0 );
extern StereoOut32 clamp_mix(const StereoOut32 &sample, u8 bitshift = 0);

File diff suppressed because it is too large Load Diff

View File

@ -28,42 +28,62 @@
#ifdef _MSC_VER
#define EXPORT_C_(type) extern "C" type CALLBACK
#else
#define EXPORT_C_(type) extern "C" __attribute__((stdcall,externally_visible,visibility("default"))) type
#define EXPORT_C_(type) extern "C" __attribute__((stdcall, externally_visible, visibility("default"))) type
#endif
// We have our own versions that have the DLLExport attribute configured:
EXPORT_C_(s32) SPU2init();
EXPORT_C_(void) SPU2reset();
EXPORT_C_(s32) SPU2open(void *pDsp);
EXPORT_C_(void) SPU2close();
EXPORT_C_(void) SPU2shutdown();
EXPORT_C_(void) SPU2write(u32 mem, u16 value);
EXPORT_C_(u16) SPU2read(u32 mem);
EXPORT_C_(s32)
SPU2init();
EXPORT_C_(void)
SPU2reset();
EXPORT_C_(s32)
SPU2open(void *pDsp);
EXPORT_C_(void)
SPU2close();
EXPORT_C_(void)
SPU2shutdown();
EXPORT_C_(void)
SPU2write(u32 mem, u16 value);
EXPORT_C_(u16)
SPU2read(u32 mem);
#ifdef ENABLE_NEW_IOPDMA_SPU2
EXPORT_C_(s32) SPU2dmaRead(s32 channel, u32* data, u32 bytesLeft, u32* bytesProcessed);
EXPORT_C_(s32) SPU2dmaWrite(s32 channel, u32* data, u32 bytesLeft, u32* bytesProcessed);
EXPORT_C_(void) SPU2dmaInterrupt(s32 channel);
EXPORT_C_(s32)
SPU2dmaRead(s32 channel, u32 *data, u32 bytesLeft, u32 *bytesProcessed);
EXPORT_C_(s32)
SPU2dmaWrite(s32 channel, u32 *data, u32 bytesLeft, u32 *bytesProcessed);
EXPORT_C_(void)
SPU2dmaInterrupt(s32 channel);
// dma irq callbacks not needed anymore, they are handled by the dmac
EXPORT_C_(void) SPU2irqCallback(void (*SPU2callback)());
EXPORT_C_(void)
SPU2irqCallback(void (*SPU2callback)());
#else
// These defines are useless and gcc-4.6 complain about redefinition
// so we remove them on linux
#ifndef __POSIX__
EXPORT_C_(void) SPU2readDMA4Mem(u16 *pMem, u32 size);
EXPORT_C_(void) SPU2writeDMA4Mem(u16 *pMem, u32 size);
EXPORT_C_(void) SPU2interruptDMA4();
EXPORT_C_(void) SPU2readDMA7Mem(u16* pMem, u32 size);
EXPORT_C_(void) SPU2writeDMA7Mem(u16 *pMem, u32 size);
EXPORT_C_(void) SPU2interruptDMA7();
EXPORT_C_(void)
SPU2readDMA4Mem(u16 *pMem, u32 size);
EXPORT_C_(void)
SPU2writeDMA4Mem(u16 *pMem, u32 size);
EXPORT_C_(void)
SPU2interruptDMA4();
EXPORT_C_(void)
SPU2readDMA7Mem(u16 *pMem, u32 size);
EXPORT_C_(void)
SPU2writeDMA7Mem(u16 *pMem, u32 size);
EXPORT_C_(void)
SPU2interruptDMA7();
// all addresses passed by dma will be pointers to the array starting at baseaddr
// This function is necessary to successfully save and reload the spu2 state
EXPORT_C_(u32) SPU2ReadMemAddr(int core);
EXPORT_C_(void) SPU2WriteMemAddr(int core,u32 value);
EXPORT_C_(void) SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)());
EXPORT_C_(u32)
SPU2ReadMemAddr(int core);
EXPORT_C_(void)
SPU2WriteMemAddr(int core, u32 value);
EXPORT_C_(void)
SPU2irqCallback(void (*SPU2callback)(), void (*DMA4callback)(), void (*DMA7callback)());
#endif
#endif
@ -71,25 +91,32 @@ EXPORT_C_(void) SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),vo
// if start is 1, starts recording spu2 data, else stops
// returns a non zero value if successful
// for now, pData is not used
EXPORT_C_(int) SPU2setupRecording(int start, void* pData);
EXPORT_C_(int)
SPU2setupRecording(int start, void *pData);
EXPORT_C_(void) SPU2setClockPtr(u32* ptr);
EXPORT_C_(void)
SPU2setClockPtr(u32 *ptr);
EXPORT_C_(void) SPU2async(u32 cycles);
EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data);
EXPORT_C_(void) SPU2configure();
EXPORT_C_(void) SPU2about();
EXPORT_C_(s32) SPU2test();
EXPORT_C_(void)
SPU2async(u32 cycles);
EXPORT_C_(s32)
SPU2freeze(int mode, freezeData *data);
EXPORT_C_(void)
SPU2configure();
EXPORT_C_(void)
SPU2about();
EXPORT_C_(s32)
SPU2test();
#include "Spu2replay.h"
extern u8 callirq;
extern void (* _irqcallback)();
extern void (*_irqcallback)();
#ifndef ENABLE_NEW_IOPDMA_SPU2
extern void (* dma4callback)();
extern void (* dma7callback)();
extern void (*dma4callback)();
extern void (*dma7callback)();
extern s16 *input_data;
extern u32 input_data_ptr;
@ -99,11 +126,11 @@ extern double srate_pv;
extern int recording;
extern u32 lClocks;
extern u32* cyclePtr;
extern u32 *cyclePtr;
extern void SPU2writeLog( const char* action, u32 rmem, u16 value );
extern void SPU2writeLog(const char *action, u32 rmem, u16 value);
extern void TimeUpdate(u32 cClocks);
extern void SPU2_FastWrite( u32 rmem, u16 value );
extern void SPU2_FastWrite(u32 rmem, u16 value);
extern void LowPassFilterInit();

View File

@ -18,7 +18,7 @@
#include "Global.h"
#include "Dma.h"
#include "PS2E-spu2.h" // required for ENABLE_NEW_IOPDMA_SPU2 define
#include "PS2E-spu2.h" // required for ENABLE_NEW_IOPDMA_SPU2 define
// Core 0 Input is "SPDIF mode" - Source audio is AC3 compressed.
@ -31,148 +31,147 @@
//
StereoOut32 V_Core::ReadInput_HiFi()
{
if (psxmode)ConLog("ReadInput_HiFi!!!!!\n");
InputPosRead &= ~1;
//
//#ifdef PCM24_S1_INTERLEAVE
// StereoOut32 retval(
// *((s32*)(ADMATempBuffer+(InputPosRead<<1))),
// *((s32*)(ADMATempBuffer+(InputPosRead<<1)+2))
// );
//#else
// StereoOut32 retval(
// (s32&)(ADMATempBuffer[InputPosRead]),
// (s32&)(ADMATempBuffer[InputPosRead+0x200])
// );
//#endif
if (psxmode)
ConLog("ReadInput_HiFi!!!!!\n");
InputPosRead &= ~1;
//
//#ifdef PCM24_S1_INTERLEAVE
// StereoOut32 retval(
// *((s32*)(ADMATempBuffer+(InputPosRead<<1))),
// *((s32*)(ADMATempBuffer+(InputPosRead<<1)+2))
// );
//#else
// StereoOut32 retval(
// (s32&)(ADMATempBuffer[InputPosRead]),
// (s32&)(ADMATempBuffer[InputPosRead+0x200])
// );
//#endif
StereoOut32 retval(
(s32&)(*GetMemPtr(0x2000 + (Index<<10) + InputPosRead)),
(s32&)(*GetMemPtr(0x2200 + (Index<<10) + InputPosRead))
);
StereoOut32 retval(
(s32 &)(*GetMemPtr(0x2000 + (Index << 10) + InputPosRead)),
(s32 &)(*GetMemPtr(0x2200 + (Index << 10) + InputPosRead)));
if( Index == 1 )
{
// CDDA Mode:
// give 30 bit data (SndOut downsamples the rest of the way)
// HACKFIX: 28 bits seems better according to rama. I should take some time and do some
// bitcounting on this one. --air
retval.Left >>= 4;
retval.Right >>= 4;
}
if (Index == 1) {
// CDDA Mode:
// give 30 bit data (SndOut downsamples the rest of the way)
// HACKFIX: 28 bits seems better according to rama. I should take some time and do some
// bitcounting on this one. --air
retval.Left >>= 4;
retval.Right >>= 4;
}
InputPosRead += 2;
InputPosRead += 2;
// Why does CDDA mode check for InputPos == 0x100? In the old code, SPDIF mode did not but CDDA did.
// One of these seems wrong, they should be the same. Since standard ADMA checks too I'm assuming that as default. -- air
// Why does CDDA mode check for InputPos == 0x100? In the old code, SPDIF mode did not but CDDA did.
// One of these seems wrong, they should be the same. Since standard ADMA checks too I'm assuming that as default. -- air
if( (InputPosRead==0x100) || (InputPosRead>=0x200) )
{
if ((InputPosRead == 0x100) || (InputPosRead >= 0x200)) {
#ifdef ENABLE_NEW_IOPDMA_SPU2
// WARNING: Assumes this to be in the same thread as the dmas
AutoDmaFree += 0x200;
// WARNING: Assumes this to be in the same thread as the dmas
AutoDmaFree += 0x200;
#else
AdmaInProgress = 0;
if(InputDataLeft >= 0x200)
{
AdmaInProgress = 0;
if (InputDataLeft >= 0x200) {
#ifdef PCM24_S1_INTERLEAVE
AutoDMAReadBuffer(1);
AutoDMAReadBuffer(1);
#else
AutoDMAReadBuffer(0);
AutoDMAReadBuffer(0);
#endif
AdmaInProgress = 1;
AdmaInProgress = 1;
TSA = (Index<<10) + InputPosRead;
TSA = (Index << 10) + InputPosRead;
if (InputDataLeft < 0x200)
{
FileLog("[%10d] %s AutoDMA%c block end.\n", (Index==1) ? "CDDA" : "SPDIF", Cycles, GetDmaIndexChar());
if (InputDataLeft < 0x200) {
FileLog("[%10d] %s AutoDMA%c block end.\n", (Index == 1) ? "CDDA" : "SPDIF", Cycles, GetDmaIndexChar());
if( IsDevBuild )
{
if(InputDataLeft > 0)
{
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
}
InputDataLeft = 0;
// Hack, kinda. We call the interrupt early here, since PCSX2 doesn't like them delayed.
//DMAICounter = 1;
if(Index == 0) { if(dma4callback) dma4callback(); }
else { if(dma7callback) dma7callback(); }
}
}
if (IsDevBuild) {
if (InputDataLeft > 0) {
if (MsgAutoDMA())
ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
}
InputDataLeft = 0;
// Hack, kinda. We call the interrupt early here, since PCSX2 doesn't like them delayed.
//DMAICounter = 1;
if (Index == 0) {
if (dma4callback)
dma4callback();
} else {
if (dma7callback)
dma7callback();
}
}
}
#endif
InputPosRead &= 0x1ff;
}
return retval;
InputPosRead &= 0x1ff;
}
return retval;
}
StereoOut32 V_Core::ReadInput()
{
StereoOut32 retval;
StereoOut32 retval;
if( (Index!=1) || ((PlayMode&2)==0) )
{
for (int i=0; i<2; i++)
if (Cores[i].IRQEnable && 0x2000 + (Index << 10) + InputPosRead == (Cores[i].IRQA & 0xfffffdff))
SetIrqCall(i);
if ((Index != 1) || ((PlayMode & 2) == 0)) {
for (int i = 0; i < 2; i++)
if (Cores[i].IRQEnable && 0x2000 + (Index << 10) + InputPosRead == (Cores[i].IRQA & 0xfffffdff))
SetIrqCall(i);
//retval = StereoOut32(
// (s32)ADMATempBuffer[InputPosRead],
// (s32)ADMATempBuffer[InputPosRead+0x200]
//);
retval = StereoOut32(
(s32)(*GetMemPtr(0x2000 + (Index<<10) + InputPosRead)),
(s32)(*GetMemPtr(0x2200 + (Index<<10) + InputPosRead))
);
}
//retval = StereoOut32(
// (s32)ADMATempBuffer[InputPosRead],
// (s32)ADMATempBuffer[InputPosRead+0x200]
//);
retval = StereoOut32(
(s32)(*GetMemPtr(0x2000 + (Index << 10) + InputPosRead)),
(s32)(*GetMemPtr(0x2200 + (Index << 10) + InputPosRead)));
}
#ifdef PCSX2_DEVBUILD
DebugCores[Index].admaWaveformL[InputPosRead%0x100]=retval.Left;
DebugCores[Index].admaWaveformR[InputPosRead%0x100]=retval.Right;
DebugCores[Index].admaWaveformL[InputPosRead % 0x100] = retval.Left;
DebugCores[Index].admaWaveformR[InputPosRead % 0x100] = retval.Right;
#endif
InputPosRead++;
InputPosRead++;
if (AutoDMACtrl & (Index + 1) && (InputPosRead == 0x100 || InputPosRead == 0x200))
{
if (AutoDMACtrl & (Index + 1) && (InputPosRead == 0x100 || InputPosRead == 0x200)) {
#ifdef ENABLE_NEW_IOPDMA_SPU2
// WARNING: Assumes this to be in the same thread as the dmas
AutoDmaFree += 0x200;
// WARNING: Assumes this to be in the same thread as the dmas
AutoDmaFree += 0x200;
#else
AdmaInProgress = 0;
if(InputDataLeft >= 0x200)
{
//u8 k=InputDataLeft>=InputDataProgress;
AdmaInProgress = 0;
if (InputDataLeft >= 0x200) {
//u8 k=InputDataLeft>=InputDataProgress;
AutoDMAReadBuffer(0);
AutoDMAReadBuffer(0);
AdmaInProgress = 1;
TSA = (Index<<10) + InputPosRead;
AdmaInProgress = 1;
TSA = (Index << 10) + InputPosRead;
if (InputDataLeft < 0x200)
{
AutoDMACtrl |= ~3;
if (InputDataLeft < 0x200) {
AutoDMACtrl |= ~3;
if( IsDevBuild )
{
FileLog("[%10d] AutoDMA%c block end.\n",Cycles, GetDmaIndexChar());
if(InputDataLeft>0)
{
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
}
if (IsDevBuild) {
FileLog("[%10d] AutoDMA%c block end.\n", Cycles, GetDmaIndexChar());
if (InputDataLeft > 0) {
if (MsgAutoDMA())
ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
}
InputDataLeft = 0;
// Hack, kinda. We call the interrupt early here, since PCSX2 doesn't like them delayed.
//DMAICounter = 1;
if(Index == 0) { if(dma4callback) dma4callback(); }
else { if(dma7callback) dma7callback(); }
}
}
InputDataLeft = 0;
// Hack, kinda. We call the interrupt early here, since PCSX2 doesn't like them delayed.
//DMAICounter = 1;
if (Index == 0) {
if (dma4callback)
dma4callback();
} else {
if (dma7callback)
dma7callback();
}
}
}
#endif
}
InputPosRead &= 0x1ff;
return retval;
}
InputPosRead &= 0x1ff;
return retval;
}

View File

@ -17,238 +17,280 @@
#include "Global.h"
const char *ParamNames[8]={"VOLL","VOLR","PITCH","ADSR1","ADSR2","ENVX","VOLXL","VOLXR"};
const char *AddressNames[6]={"SSAH","SSAL","LSAH","LSAL","NAXH","NAXL"};
const char *ParamNames[8] = {"VOLL", "VOLR", "PITCH", "ADSR1", "ADSR2", "ENVX", "VOLXL", "VOLXR"};
const char *AddressNames[6] = {"SSAH", "SSAL", "LSAH", "LSAL", "NAXH", "NAXL"};
__forceinline void _RegLog_( const char* action, int level, const char *RName, u32 mem, u32 core, u16 value )
__forceinline void _RegLog_(const char *action, int level, const char *RName, u32 mem, u32 core, u16 value)
{
if( level > 1 )
FileLog("[%10d] SPU2 %s mem %08x (core %d, register %s) value %04x\n",
Cycles, action, mem, core, RName, value);
if (level > 1)
FileLog("[%10d] SPU2 %s mem %08x (core %d, register %s) value %04x\n",
Cycles, action, mem, core, RName, value);
}
#define RegLog( lev, rname, mem, core, val ) _RegLog_( action, lev, rname, mem, core, val )
#define RegLog(lev, rname, mem, core, val) _RegLog_(action, lev, rname, mem, core, val)
void SPU2writeLog( const char* action, u32 rmem, u16 value )
void SPU2writeLog(const char *action, u32 rmem, u16 value)
{
if( !IsDevBuild ) return;
if (!IsDevBuild)
return;
//u32 vx=0, vc=0;
u32 core=0, omem, mem;
omem=mem=rmem & 0x7FF; //FFFF;
if (mem & 0x400) { omem^=0x400; core=1; }
//u32 vx=0, vc=0;
u32 core = 0, omem, mem;
omem = mem = rmem & 0x7FF; //FFFF;
if (mem & 0x400) {
omem ^= 0x400;
core = 1;
}
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 < 0x02E0)) // Voice Addressing Params (VA)
{
const u32 voice = ((omem-0x01C0) / 12);
const u32 address = ((omem-0x01C0) % 12)>>1;
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 < 0x02E0)) // 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 );
}
else if ((mem >= 0x0760) && (mem < 0x07b0))
{
omem=mem; core=0;
if (mem >= 0x0788) {omem-=0x28; core=1;}
switch(omem)
{
case REG_P_EVOLL: RegLog(2,"EVOLL",rmem,core,value); break;
case REG_P_EVOLR: RegLog(2,"EVOLR",rmem,core,value); break;
case REG_P_AVOLL: if (core) { RegLog(2,"AVOLL",rmem,core,value); } break;
case REG_P_AVOLR: if (core) { RegLog(2,"AVOLR",rmem,core,value); } break;
case REG_P_BVOLL: RegLog(2,"BVOLL",rmem,core,value); break;
case REG_P_BVOLR: RegLog(2,"BVOLR",rmem,core,value); break;
case REG_P_MVOLXL: RegLog(2,"MVOLXL",rmem,core,value); break;
case REG_P_MVOLXR: RegLog(2,"MVOLXR",rmem,core,value); break;
case R_IIR_ALPHA: RegLog(2,"IIR_ALPHA",rmem,core,value); break;
case R_ACC_COEF_A: RegLog(2,"ACC_COEF_A",rmem,core,value); break;
case R_ACC_COEF_B: RegLog(2,"ACC_COEF_B",rmem,core,value); break;
case R_ACC_COEF_C: RegLog(2,"ACC_COEF_C",rmem,core,value); break;
case R_ACC_COEF_D: RegLog(2,"ACC_COEF_D",rmem,core,value); break;
case R_IIR_COEF: RegLog(2,"IIR_COEF",rmem,core,value); break;
case R_FB_ALPHA: RegLog(2,"FB_ALPHA",rmem,core,value); break;
case R_FB_X: RegLog(2,"FB_X",rmem,core,value); break;
case R_IN_COEF_L: RegLog(2,"IN_COEF_L",rmem,core,value); break;
case R_IN_COEF_R: RegLog(2,"IN_COEF_R",rmem,core,value); break;
char dest[192];
sprintf(dest, "Voice %d %s", voice, AddressNames[address]);
RegLog(2, dest, rmem, core, value);
} else if ((mem >= 0x0760) && (mem < 0x07b0)) {
omem = mem;
core = 0;
if (mem >= 0x0788) {
omem -= 0x28;
core = 1;
}
switch (omem) {
case REG_P_EVOLL:
RegLog(2, "EVOLL", rmem, core, value);
break;
case REG_P_EVOLR:
RegLog(2, "EVOLR", rmem, core, value);
break;
case REG_P_AVOLL:
if (core) {
RegLog(2, "AVOLL", rmem, core, value);
}
break;
case REG_P_AVOLR:
if (core) {
RegLog(2, "AVOLR", rmem, core, value);
}
break;
case REG_P_BVOLL:
RegLog(2, "BVOLL", rmem, core, value);
break;
case REG_P_BVOLR:
RegLog(2, "BVOLR", rmem, core, value);
break;
case REG_P_MVOLXL:
RegLog(2, "MVOLXL", rmem, core, value);
break;
case REG_P_MVOLXR:
RegLog(2, "MVOLXR", rmem, core, value);
break;
case R_IIR_ALPHA:
RegLog(2, "IIR_ALPHA", rmem, core, value);
break;
case R_ACC_COEF_A:
RegLog(2, "ACC_COEF_A", rmem, core, value);
break;
case R_ACC_COEF_B:
RegLog(2, "ACC_COEF_B", rmem, core, value);
break;
case R_ACC_COEF_C:
RegLog(2, "ACC_COEF_C", rmem, core, value);
break;
case R_ACC_COEF_D:
RegLog(2, "ACC_COEF_D", rmem, core, value);
break;
case R_IIR_COEF:
RegLog(2, "IIR_COEF", rmem, core, value);
break;
case R_FB_ALPHA:
RegLog(2, "FB_ALPHA", rmem, core, value);
break;
case R_FB_X:
RegLog(2, "FB_X", rmem, core, value);
break;
case R_IN_COEF_L:
RegLog(2, "IN_COEF_L", rmem, core, value);
break;
case R_IN_COEF_R:
RegLog(2, "IN_COEF_R", rmem, core, value);
break;
}
} else if ((mem >= 0x07C0) && (mem < 0x07CE)) {
switch (mem) {
case SPDIF_OUT:
RegLog(2, "SPDIF_OUT", rmem, -1, value);
break;
case SPDIF_IRQINFO:
RegLog(2, "SPDIF_IRQINFO", rmem, -1, value);
break;
case 0x7c4:
if (Spdif.Unknown1 != value)
ConLog("* SPU2-X: SPDIF Unknown Register 1 set to %04x\n", value);
RegLog(2, "SPDIF_UNKNOWN1", rmem, -1, value);
break;
case SPDIF_MODE:
if (Spdif.Mode != value)
ConLog("* SPU2-X: SPDIF Mode set to %04x\n", value);
RegLog(2, "SPDIF_MODE", rmem, -1, value);
break;
case SPDIF_MEDIA:
if (Spdif.Media != value)
ConLog("* SPU2-X: SPDIF Media set to %04x\n", value);
RegLog(2, "SPDIF_MEDIA", rmem, -1, value);
break;
case 0x7ca:
if (Spdif.Unknown2 != value)
ConLog("* SPU2-X: SPDIF Unknown Register 2 set to %04x\n", value);
RegLog(2, "SPDIF_UNKNOWN2", rmem, -1, value);
break;
case SPDIF_PROTECT:
if (Spdif.Protection != value)
ConLog("* SPU2-X: SPDIF Copy set to %04x\n", value);
RegLog(2, "SPDIF_PROTECT", rmem, -1, value);
break;
}
UpdateSpdifMode();
} else {
switch (omem) {
case REG_C_ATTR:
RegLog(4, "ATTR", rmem, core, value);
break;
case REG_S_PMON:
RegLog(1, "PMON0", rmem, core, value);
break;
case (REG_S_PMON + 2):
RegLog(1, "PMON1", rmem, core, value);
break;
case REG_S_NON:
RegLog(1, "NON0", rmem, core, value);
break;
case (REG_S_NON + 2):
RegLog(1, "NON1", rmem, core, value);
break;
case REG_S_VMIXL:
RegLog(1, "VMIXL0", rmem, core, value);
case (REG_S_VMIXL + 2):
RegLog(1, "VMIXL1", rmem, core, value);
break;
case REG_S_VMIXEL:
RegLog(1, "VMIXEL0", rmem, core, value);
break;
case (REG_S_VMIXEL + 2):
RegLog(1, "VMIXEL1", rmem, core, value);
break;
case REG_S_VMIXR:
RegLog(1, "VMIXR0", rmem, core, value);
break;
case (REG_S_VMIXR + 2):
RegLog(1, "VMIXR1", rmem, core, value);
break;
case REG_S_VMIXER:
RegLog(1, "VMIXER0", rmem, core, value);
break;
case (REG_S_VMIXER + 2):
RegLog(1, "VMIXER1", rmem, core, value);
break;
case REG_P_MMIX:
RegLog(1, "MMIX", rmem, core, value);
break;
case REG_A_IRQA:
RegLog(2, "IRQAH", rmem, core, value);
break;
case (REG_A_IRQA + 2):
RegLog(2, "IRQAL", rmem, core, value);
break;
case (REG_S_KON + 2):
RegLog(1, "KON1", rmem, core, value);
break;
case REG_S_KON:
RegLog(1, "KON0", rmem, core, value);
break;
case (REG_S_KOFF + 2):
RegLog(1, "KOFF1", rmem, core, value);
break;
case REG_S_KOFF:
RegLog(1, "KOFF0", rmem, core, value);
break;
case REG_A_TSA:
RegLog(2, "TSAH", rmem, core, value);
break;
case (REG_A_TSA + 2):
RegLog(2, "TSAL", rmem, core, value);
break;
case REG_S_ENDX:
//ConLog("* SPU2-X: Core %d ENDX cleared!\n",core);
RegLog(2, "ENDX0", rmem, core, value);
break;
case (REG_S_ENDX + 2):
//ConLog("* SPU2-X: Core %d ENDX cleared!\n",core);
RegLog(2, "ENDX1", rmem, core, value);
break;
case REG_P_MVOLL:
RegLog(1, "MVOLL", rmem, core, value);
break;
case REG_P_MVOLR:
RegLog(1, "MVOLR", rmem, core, value);
break;
case REG_S_ADMAS:
RegLog(3, "ADMAS", rmem, core, value);
//ConLog("* SPU2-X: Core %d AutoDMAControl set to %d\n",core,value);
break;
case REG_P_STATX:
RegLog(3, "STATX", rmem, core, value);
break;
case REG_A_ESA:
RegLog(2, "ESAH", rmem, core, value);
break;
case (REG_A_ESA + 2):
RegLog(2, "ESAL", rmem, core, value);
break;
case REG_A_EEA:
RegLog(2, "EEAH", rmem, core, value);
break;
}
}
else if ((mem>=0x07C0) && (mem<0x07CE))
{
switch(mem)
{
case SPDIF_OUT:
RegLog(2,"SPDIF_OUT",rmem,-1,value);
break;
case SPDIF_IRQINFO:
RegLog(2,"SPDIF_IRQINFO",rmem,-1,value);
break;
case 0x7c4:
if(Spdif.Unknown1 != value) ConLog("* SPU2-X: SPDIF Unknown Register 1 set to %04x\n",value);
RegLog(2,"SPDIF_UNKNOWN1",rmem,-1,value);
break;
case SPDIF_MODE:
if(Spdif.Mode != value) ConLog("* SPU2-X: SPDIF Mode set to %04x\n",value);
RegLog(2,"SPDIF_MODE",rmem,-1,value);
break;
case SPDIF_MEDIA:
if(Spdif.Media != value) ConLog("* SPU2-X: SPDIF Media set to %04x\n",value);
RegLog(2,"SPDIF_MEDIA",rmem,-1,value);
break;
case 0x7ca:
if(Spdif.Unknown2 != value) ConLog("* SPU2-X: SPDIF Unknown Register 2 set to %04x\n",value);
RegLog(2,"SPDIF_UNKNOWN2",rmem,-1,value);
break;
case SPDIF_PROTECT:
if(Spdif.Protection != value) ConLog("* SPU2-X: SPDIF Copy set to %04x\n",value);
RegLog(2,"SPDIF_PROTECT",rmem,-1,value);
break;
}
UpdateSpdifMode();
}
else
{
switch(omem)
{
case REG_C_ATTR:
RegLog(4,"ATTR",rmem,core,value);
break;
case REG_S_PMON:
RegLog(1,"PMON0",rmem,core,value);
break;
case (REG_S_PMON + 2):
RegLog(1,"PMON1",rmem,core,value);
break;
case REG_S_NON:
RegLog(1,"NON0",rmem,core,value);
break;
case (REG_S_NON + 2):
RegLog(1,"NON1",rmem,core,value);
break;
case REG_S_VMIXL:
RegLog(1,"VMIXL0",rmem,core,value);
case (REG_S_VMIXL + 2):
RegLog(1,"VMIXL1",rmem,core,value);
break;
case REG_S_VMIXEL:
RegLog(1,"VMIXEL0",rmem,core,value);
break;
case (REG_S_VMIXEL + 2):
RegLog(1,"VMIXEL1",rmem,core,value);
break;
case REG_S_VMIXR:
RegLog(1,"VMIXR0",rmem,core,value);
break;
case (REG_S_VMIXR + 2):
RegLog(1,"VMIXR1",rmem,core,value);
break;
case REG_S_VMIXER:
RegLog(1,"VMIXER0",rmem,core,value);
break;
case (REG_S_VMIXER + 2):
RegLog(1,"VMIXER1",rmem,core,value);
break;
case REG_P_MMIX:
RegLog(1,"MMIX",rmem,core,value);
break;
case REG_A_IRQA:
RegLog(2,"IRQAH",rmem,core,value);
break;
case (REG_A_IRQA + 2):
RegLog(2,"IRQAL",rmem,core,value);
break;
case (REG_S_KON + 2):
RegLog(1,"KON1",rmem,core,value);
break;
case REG_S_KON:
RegLog(1,"KON0",rmem,core,value);
break;
case (REG_S_KOFF + 2):
RegLog(1,"KOFF1",rmem,core,value);
break;
case REG_S_KOFF:
RegLog(1,"KOFF0",rmem,core,value);
break;
case REG_A_TSA:
RegLog(2,"TSAH",rmem,core,value);
break;
case (REG_A_TSA + 2):
RegLog(2,"TSAL",rmem,core,value);
break;
case REG_S_ENDX:
//ConLog("* SPU2-X: Core %d ENDX cleared!\n",core);
RegLog(2,"ENDX0",rmem,core,value);
break;
case (REG_S_ENDX + 2):
//ConLog("* SPU2-X: Core %d ENDX cleared!\n",core);
RegLog(2,"ENDX1",rmem,core,value);
break;
case REG_P_MVOLL:
RegLog(1,"MVOLL",rmem,core,value);
break;
case REG_P_MVOLR:
RegLog(1,"MVOLR",rmem,core,value);
break;
case REG_S_ADMAS:
RegLog(3,"ADMAS",rmem,core,value);
//ConLog("* SPU2-X: Core %d AutoDMAControl set to %d\n",core,value);
break;
case REG_P_STATX:
RegLog(3,"STATX",rmem,core,value);
break;
case REG_A_ESA:
RegLog(2,"ESAH",rmem,core,value);
break;
case (REG_A_ESA + 2):
RegLog(2,"ESAL",rmem,core,value);
break;
case REG_A_EEA:
RegLog(2,"EEAH",rmem,core,value);
break;
#define LOG_REVB_REG(n, t) \
case R_##n: \
RegLog(2, t "H", mem, core, value); \
break; \
case (R_##n + 2): \
RegLog(2, t "L", mem, core, value); \
break;
#define LOG_REVB_REG(n,t) \
case R_##n: \
RegLog(2,t "H",mem,core,value); \
break; \
case (R_##n + 2): \
RegLog(2,t "L",mem,core,value); \
break;
LOG_REVB_REG(FB_SRC_A, "FB_SRC_A")
LOG_REVB_REG(FB_SRC_B, "FB_SRC_B")
LOG_REVB_REG(IIR_SRC_A0, "IIR_SRC_A0")
LOG_REVB_REG(IIR_SRC_A1, "IIR_SRC_A1")
LOG_REVB_REG(IIR_SRC_B1, "IIR_SRC_B1")
LOG_REVB_REG(IIR_SRC_B0, "IIR_SRC_B0")
LOG_REVB_REG(IIR_DEST_A0, "IIR_DEST_A0")
LOG_REVB_REG(IIR_DEST_A1, "IIR_DEST_A1")
LOG_REVB_REG(IIR_DEST_B0, "IIR_DEST_B0")
LOG_REVB_REG(IIR_DEST_B1, "IIR_DEST_B1")
LOG_REVB_REG(ACC_SRC_A0, "ACC_SRC_A0")
LOG_REVB_REG(ACC_SRC_A1, "ACC_SRC_A1")
LOG_REVB_REG(ACC_SRC_B0, "ACC_SRC_B0")
LOG_REVB_REG(ACC_SRC_B1, "ACC_SRC_B1")
LOG_REVB_REG(ACC_SRC_C0, "ACC_SRC_C0")
LOG_REVB_REG(ACC_SRC_C1, "ACC_SRC_C1")
LOG_REVB_REG(ACC_SRC_D0, "ACC_SRC_D0")
LOG_REVB_REG(ACC_SRC_D1, "ACC_SRC_D1")
LOG_REVB_REG(MIX_DEST_A0, "MIX_DEST_A0")
LOG_REVB_REG(MIX_DEST_A1, "MIX_DEST_A1")
LOG_REVB_REG(MIX_DEST_B0, "MIX_DEST_B0")
LOG_REVB_REG(MIX_DEST_B1, "MIX_DEST_B1")
LOG_REVB_REG(FB_SRC_A,"FB_SRC_A")
LOG_REVB_REG(FB_SRC_B,"FB_SRC_B")
LOG_REVB_REG(IIR_SRC_A0,"IIR_SRC_A0")
LOG_REVB_REG(IIR_SRC_A1,"IIR_SRC_A1")
LOG_REVB_REG(IIR_SRC_B1,"IIR_SRC_B1")
LOG_REVB_REG(IIR_SRC_B0,"IIR_SRC_B0")
LOG_REVB_REG(IIR_DEST_A0,"IIR_DEST_A0")
LOG_REVB_REG(IIR_DEST_A1,"IIR_DEST_A1")
LOG_REVB_REG(IIR_DEST_B0,"IIR_DEST_B0")
LOG_REVB_REG(IIR_DEST_B1,"IIR_DEST_B1")
LOG_REVB_REG(ACC_SRC_A0,"ACC_SRC_A0")
LOG_REVB_REG(ACC_SRC_A1,"ACC_SRC_A1")
LOG_REVB_REG(ACC_SRC_B0,"ACC_SRC_B0")
LOG_REVB_REG(ACC_SRC_B1,"ACC_SRC_B1")
LOG_REVB_REG(ACC_SRC_C0,"ACC_SRC_C0")
LOG_REVB_REG(ACC_SRC_C1,"ACC_SRC_C1")
LOG_REVB_REG(ACC_SRC_D0,"ACC_SRC_D0")
LOG_REVB_REG(ACC_SRC_D1,"ACC_SRC_D1")
LOG_REVB_REG(MIX_DEST_A0,"MIX_DEST_A0")
LOG_REVB_REG(MIX_DEST_A1,"MIX_DEST_A1")
LOG_REVB_REG(MIX_DEST_B0,"MIX_DEST_B0")
LOG_REVB_REG(MIX_DEST_B1,"MIX_DEST_B1")
default:
RegLog(2,"UNKNOWN",rmem,core,value); spu2Ru16(mem) = value;
}
}
default:
RegLog(2, "UNKNOWN", rmem, core, value);
spu2Ru16(mem) = value;
}
}
}

View File

@ -17,287 +17,287 @@
#include "Global.h"
#define PCORE(c,p) \
U16P(Cores[c].p)
#define PCORE(c, p) \
U16P(Cores[c].p)
#define PVCP(c,v,p) \
PCORE(c,Voices[v].p)
#define PVCP(c, v, p) \
PCORE(c, Voices[v].p)
#define PVC(c,v) \
PVCP(c,v,Volume.Left.Reg_VOL), \
PVCP(c,v,Volume.Right.Reg_VOL), \
PVCP(c,v,Pitch), \
PVCP(c,v,ADSR.regADSR1), \
PVCP(c,v,ADSR.regADSR2), \
PVCP(c,v,ADSR.Value)+1, \
PVCP(c,v,Volume.Left.Value)+1, \
PVCP(c,v,Volume.Right.Value)+1
#define PVC(c, v) \
PVCP(c, v, Volume.Left.Reg_VOL) \
, \
PVCP(c, v, Volume.Right.Reg_VOL), \
PVCP(c, v, Pitch), \
PVCP(c, v, ADSR.regADSR1), \
PVCP(c, v, ADSR.regADSR2), \
PVCP(c, v, ADSR.Value) + 1, \
PVCP(c, v, Volume.Left.Value) + 1, \
PVCP(c, v, Volume.Right.Value) + 1
#define PVCA(c,v) \
PVCP(c,v,StartA)+1, \
PVCP(c,v,StartA), \
PVCP(c,v,LoopStartA)+1, \
PVCP(c,v,LoopStartA), \
PVCP(c,v,NextA)+1, \
PVCP(c,v,NextA)
#define PVCA(c, v) \
PVCP(c, v, StartA) + 1, \
PVCP(c, v, StartA), \
PVCP(c, v, LoopStartA) + 1, \
PVCP(c, v, LoopStartA), \
PVCP(c, v, NextA) + 1, \
PVCP(c, v, NextA)
#define PRAW(a) \
((u16*)NULL)
((u16 *)NULL)
#define PREVB_REG(c,n) \
PCORE(c,Revb.n)+1, \
PCORE(c,Revb.n)
#define PREVB_REG(c, n) \
PCORE(c, Revb.n) + 1, \
PCORE(c, Revb.n)
u16* regtable[0x401];
u16 *regtable[0x401];
u16 const* const regtable_original[0x401] =
{
// Voice Params: 8 params, 24 voices = 0x180 bytes
PVC(0, 0),PVC(0, 1),PVC(0, 2),PVC(0, 3),PVC(0, 4),PVC(0, 5),
PVC(0, 6),PVC(0, 7),PVC(0, 8),PVC(0, 9),PVC(0,10),PVC(0,11),
PVC(0,12),PVC(0,13),PVC(0,14),PVC(0,15),PVC(0,16),PVC(0,17),
PVC(0,18),PVC(0,19),PVC(0,20),PVC(0,21),PVC(0,22),PVC(0,23),
u16 const *const regtable_original[0x401] =
{
// Voice Params: 8 params, 24 voices = 0x180 bytes
PVC(0, 0), PVC(0, 1), PVC(0, 2), PVC(0, 3), PVC(0, 4), PVC(0, 5),
PVC(0, 6), PVC(0, 7), PVC(0, 8), PVC(0, 9), PVC(0, 10), PVC(0, 11),
PVC(0, 12), PVC(0, 13), PVC(0, 14), PVC(0, 15), PVC(0, 16), PVC(0, 17),
PVC(0, 18), PVC(0, 19), PVC(0, 20), PVC(0, 21), PVC(0, 22), PVC(0, 23),
PCORE(0,Regs.PMON),
PCORE(0,Regs.PMON)+1,
PCORE(0,Regs.NON),
PCORE(0,Regs.NON)+1,
PCORE(0,Regs.VMIXL),
PCORE(0,Regs.VMIXL)+1,
PCORE(0,Regs.VMIXEL),
PCORE(0,Regs.VMIXEL)+1,
PCORE(0,Regs.VMIXR),
PCORE(0,Regs.VMIXR)+1,
PCORE(0,Regs.VMIXER),
PCORE(0,Regs.VMIXER)+1,
PCORE(0, Regs.PMON),
PCORE(0, Regs.PMON) + 1,
PCORE(0, Regs.NON),
PCORE(0, Regs.NON) + 1,
PCORE(0, Regs.VMIXL),
PCORE(0, Regs.VMIXL) + 1,
PCORE(0, Regs.VMIXEL),
PCORE(0, Regs.VMIXEL) + 1,
PCORE(0, Regs.VMIXR),
PCORE(0, Regs.VMIXR) + 1,
PCORE(0, Regs.VMIXER),
PCORE(0, Regs.VMIXER) + 1,
PCORE(0,Regs.MMIX),
PCORE(0,Regs.ATTR),
PCORE(0, Regs.MMIX),
PCORE(0, Regs.ATTR),
PCORE(0,IRQA)+1,
PCORE(0,IRQA),
PCORE(0, IRQA) + 1,
PCORE(0, IRQA),
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
PCORE(0,TSA)+1,
PCORE(0,TSA),
PCORE(0, TSA) + 1,
PCORE(0, TSA),
PRAW(REG__1AC), PRAW(REG__1AE),
PRAW(REG__1AC), PRAW(REG__1AE),
PCORE(0,AutoDMACtrl),
PCORE(0, AutoDMACtrl),
PRAW(0x1b2), PRAW(0x1b4), PRAW(0x1b6), PRAW(0x1b8), PRAW(0x1ba), PRAW(0x1bc), PRAW(0x1be), // unknown
PRAW(0x1b2), PRAW(0x1b4), PRAW(0x1b6), PRAW(0x1b8), PRAW(0x1ba), PRAW(0x1bc), PRAW(0x1be), // unknown
// Voice Addresses
PVCA(0, 0),PVCA(0, 1),PVCA(0, 2),PVCA(0, 3),PVCA(0, 4),PVCA(0, 5),
PVCA(0, 6),PVCA(0, 7),PVCA(0, 8),PVCA(0, 9),PVCA(0,10),PVCA(0,11),
PVCA(0,12),PVCA(0,13),PVCA(0,14),PVCA(0,15),PVCA(0,16),PVCA(0,17),
PVCA(0,18),PVCA(0,19),PVCA(0,20),PVCA(0,21),PVCA(0,22),PVCA(0,23),
// Voice Addresses
PVCA(0, 0), PVCA(0, 1), PVCA(0, 2), PVCA(0, 3), PVCA(0, 4), PVCA(0, 5),
PVCA(0, 6), PVCA(0, 7), PVCA(0, 8), PVCA(0, 9), PVCA(0, 10), PVCA(0, 11),
PVCA(0, 12), PVCA(0, 13), PVCA(0, 14), PVCA(0, 15), PVCA(0, 16), PVCA(0, 17),
PVCA(0, 18), PVCA(0, 19), PVCA(0, 20), PVCA(0, 21), PVCA(0, 22), PVCA(0, 23),
PCORE(0,ExtEffectsStartA)+1,
PCORE(0,ExtEffectsStartA),
PCORE(0, ExtEffectsStartA) + 1,
PCORE(0, ExtEffectsStartA),
PREVB_REG(0,FB_SRC_A),
PREVB_REG(0,FB_SRC_B),
PREVB_REG(0,IIR_DEST_A0),
PREVB_REG(0,IIR_DEST_A1),
PREVB_REG(0,ACC_SRC_A0),
PREVB_REG(0,ACC_SRC_A1),
PREVB_REG(0,ACC_SRC_B0),
PREVB_REG(0,ACC_SRC_B1),
PREVB_REG(0,IIR_SRC_A0),
PREVB_REG(0,IIR_SRC_A1),
PREVB_REG(0,IIR_DEST_B0),
PREVB_REG(0,IIR_DEST_B1),
PREVB_REG(0,ACC_SRC_C0),
PREVB_REG(0,ACC_SRC_C1),
PREVB_REG(0,ACC_SRC_D0),
PREVB_REG(0,ACC_SRC_D1),
PREVB_REG(0,IIR_SRC_B0),
PREVB_REG(0,IIR_SRC_B1),
PREVB_REG(0,MIX_DEST_A0),
PREVB_REG(0,MIX_DEST_A1),
PREVB_REG(0,MIX_DEST_B0),
PREVB_REG(0,MIX_DEST_B1),
PREVB_REG(0, FB_SRC_A),
PREVB_REG(0, FB_SRC_B),
PREVB_REG(0, IIR_DEST_A0),
PREVB_REG(0, IIR_DEST_A1),
PREVB_REG(0, ACC_SRC_A0),
PREVB_REG(0, ACC_SRC_A1),
PREVB_REG(0, ACC_SRC_B0),
PREVB_REG(0, ACC_SRC_B1),
PREVB_REG(0, IIR_SRC_A0),
PREVB_REG(0, IIR_SRC_A1),
PREVB_REG(0, IIR_DEST_B0),
PREVB_REG(0, IIR_DEST_B1),
PREVB_REG(0, ACC_SRC_C0),
PREVB_REG(0, ACC_SRC_C1),
PREVB_REG(0, ACC_SRC_D0),
PREVB_REG(0, ACC_SRC_D1),
PREVB_REG(0, IIR_SRC_B0),
PREVB_REG(0, IIR_SRC_B1),
PREVB_REG(0, MIX_DEST_A0),
PREVB_REG(0, MIX_DEST_A1),
PREVB_REG(0, MIX_DEST_B0),
PREVB_REG(0, MIX_DEST_B1),
PCORE(0,ExtEffectsEndA)+1,
PCORE(0,ExtEffectsEndA),
PCORE(0, ExtEffectsEndA) + 1,
PCORE(0, ExtEffectsEndA),
PCORE(0,Regs.ENDX),
PCORE(0,Regs.ENDX)+1,
PCORE(0,Regs.STATX),
PCORE(0, Regs.ENDX),
PCORE(0, Regs.ENDX) + 1,
PCORE(0, Regs.STATX),
//0x346 here
PRAW(0x346),
PRAW(0x348),PRAW(0x34A),PRAW(0x34C),PRAW(0x34E),
PRAW(0x350),PRAW(0x352),PRAW(0x354),PRAW(0x356),
PRAW(0x358),PRAW(0x35A),PRAW(0x35C),PRAW(0x35E),
PRAW(0x360),PRAW(0x362),PRAW(0x364),PRAW(0x366),
PRAW(0x368),PRAW(0x36A),PRAW(0x36C),PRAW(0x36E),
PRAW(0x370),PRAW(0x372),PRAW(0x374),PRAW(0x376),
PRAW(0x378),PRAW(0x37A),PRAW(0x37C),PRAW(0x37E),
PRAW(0x380),PRAW(0x382),PRAW(0x384),PRAW(0x386),
PRAW(0x388),PRAW(0x38A),PRAW(0x38C),PRAW(0x38E),
PRAW(0x390),PRAW(0x392),PRAW(0x394),PRAW(0x396),
PRAW(0x398),PRAW(0x39A),PRAW(0x39C),PRAW(0x39E),
PRAW(0x3A0),PRAW(0x3A2),PRAW(0x3A4),PRAW(0x3A6),
PRAW(0x3A8),PRAW(0x3AA),PRAW(0x3AC),PRAW(0x3AE),
PRAW(0x3B0),PRAW(0x3B2),PRAW(0x3B4),PRAW(0x3B6),
PRAW(0x3B8),PRAW(0x3BA),PRAW(0x3BC),PRAW(0x3BE),
PRAW(0x3C0),PRAW(0x3C2),PRAW(0x3C4),PRAW(0x3C6),
PRAW(0x3C8),PRAW(0x3CA),PRAW(0x3CC),PRAW(0x3CE),
PRAW(0x3D0),PRAW(0x3D2),PRAW(0x3D4),PRAW(0x3D6),
PRAW(0x3D8),PRAW(0x3DA),PRAW(0x3DC),PRAW(0x3DE),
PRAW(0x3E0),PRAW(0x3E2),PRAW(0x3E4),PRAW(0x3E6),
PRAW(0x3E8),PRAW(0x3EA),PRAW(0x3EC),PRAW(0x3EE),
PRAW(0x3F0),PRAW(0x3F2),PRAW(0x3F4),PRAW(0x3F6),
PRAW(0x3F8),PRAW(0x3FA),PRAW(0x3FC),PRAW(0x3FE),
//0x346 here
PRAW(0x346),
PRAW(0x348), PRAW(0x34A), PRAW(0x34C), PRAW(0x34E),
PRAW(0x350), PRAW(0x352), PRAW(0x354), PRAW(0x356),
PRAW(0x358), PRAW(0x35A), PRAW(0x35C), PRAW(0x35E),
PRAW(0x360), PRAW(0x362), PRAW(0x364), PRAW(0x366),
PRAW(0x368), PRAW(0x36A), PRAW(0x36C), PRAW(0x36E),
PRAW(0x370), PRAW(0x372), PRAW(0x374), PRAW(0x376),
PRAW(0x378), PRAW(0x37A), PRAW(0x37C), PRAW(0x37E),
PRAW(0x380), PRAW(0x382), PRAW(0x384), PRAW(0x386),
PRAW(0x388), PRAW(0x38A), PRAW(0x38C), PRAW(0x38E),
PRAW(0x390), PRAW(0x392), PRAW(0x394), PRAW(0x396),
PRAW(0x398), PRAW(0x39A), PRAW(0x39C), PRAW(0x39E),
PRAW(0x3A0), PRAW(0x3A2), PRAW(0x3A4), PRAW(0x3A6),
PRAW(0x3A8), PRAW(0x3AA), PRAW(0x3AC), PRAW(0x3AE),
PRAW(0x3B0), PRAW(0x3B2), PRAW(0x3B4), PRAW(0x3B6),
PRAW(0x3B8), PRAW(0x3BA), PRAW(0x3BC), PRAW(0x3BE),
PRAW(0x3C0), PRAW(0x3C2), PRAW(0x3C4), PRAW(0x3C6),
PRAW(0x3C8), PRAW(0x3CA), PRAW(0x3CC), PRAW(0x3CE),
PRAW(0x3D0), PRAW(0x3D2), PRAW(0x3D4), PRAW(0x3D6),
PRAW(0x3D8), PRAW(0x3DA), PRAW(0x3DC), PRAW(0x3DE),
PRAW(0x3E0), PRAW(0x3E2), PRAW(0x3E4), PRAW(0x3E6),
PRAW(0x3E8), PRAW(0x3EA), PRAW(0x3EC), PRAW(0x3EE),
PRAW(0x3F0), PRAW(0x3F2), PRAW(0x3F4), PRAW(0x3F6),
PRAW(0x3F8), PRAW(0x3FA), PRAW(0x3FC), PRAW(0x3FE),
//AND... we reached 0x400!
// Voice Params: 8 params, 24 voices = 0x180 bytes
PVC(1, 0),PVC(1, 1),PVC(1, 2),PVC(1, 3),PVC(1, 4),PVC(1, 5),
PVC(1, 6),PVC(1, 7),PVC(1, 8),PVC(1, 9),PVC(1,10),PVC(1,11),
PVC(1,12),PVC(1,13),PVC(1,14),PVC(1,15),PVC(1,16),PVC(1,17),
PVC(1,18),PVC(1,19),PVC(1,20),PVC(1,21),PVC(1,22),PVC(1,23),
//AND... we reached 0x400!
// Voice Params: 8 params, 24 voices = 0x180 bytes
PVC(1, 0), PVC(1, 1), PVC(1, 2), PVC(1, 3), PVC(1, 4), PVC(1, 5),
PVC(1, 6), PVC(1, 7), PVC(1, 8), PVC(1, 9), PVC(1, 10), PVC(1, 11),
PVC(1, 12), PVC(1, 13), PVC(1, 14), PVC(1, 15), PVC(1, 16), PVC(1, 17),
PVC(1, 18), PVC(1, 19), PVC(1, 20), PVC(1, 21), PVC(1, 22), PVC(1, 23),
PCORE(1,Regs.PMON),
PCORE(1,Regs.PMON)+1,
PCORE(1,Regs.NON),
PCORE(1,Regs.NON)+1,
PCORE(1,Regs.VMIXL),
PCORE(1,Regs.VMIXL)+1,
PCORE(1,Regs.VMIXEL),
PCORE(1,Regs.VMIXEL)+1,
PCORE(1,Regs.VMIXR),
PCORE(1,Regs.VMIXR)+1,
PCORE(1,Regs.VMIXER),
PCORE(1,Regs.VMIXER)+1,
PCORE(1,Regs.MMIX),
PCORE(1, Regs.PMON),
PCORE(1, Regs.PMON) + 1,
PCORE(1, Regs.NON),
PCORE(1, Regs.NON) + 1,
PCORE(1, Regs.VMIXL),
PCORE(1, Regs.VMIXL) + 1,
PCORE(1, Regs.VMIXEL),
PCORE(1, Regs.VMIXEL) + 1,
PCORE(1, Regs.VMIXR),
PCORE(1, Regs.VMIXR) + 1,
PCORE(1, Regs.VMIXER),
PCORE(1, Regs.VMIXER) + 1,
PCORE(1, Regs.MMIX),
PCORE(1,Regs.ATTR),
PCORE(1, Regs.ATTR),
PCORE(1,IRQA)+1,
PCORE(1,IRQA),
PCORE(1, IRQA) + 1,
PCORE(1, IRQA),
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
PCORE(1,TSA)+1,
PCORE(1,TSA),
PCORE(1, TSA) + 1,
PCORE(1, TSA),
PRAW(0x5ac), PRAW(0x5ae),
PRAW(0x5ac), PRAW(0x5ae),
PCORE(1,AutoDMACtrl),
PCORE(1, AutoDMACtrl),
PRAW(0x5b2), PRAW(0x5b4), PRAW(0x5b6), PRAW(0x5b8), PRAW(0x5ba), PRAW(0x5bc), PRAW(0x5be), // unknown
PRAW(0x5b2), PRAW(0x5b4), PRAW(0x5b6), PRAW(0x5b8), PRAW(0x5ba), PRAW(0x5bc), PRAW(0x5be), // unknown
// Voice Addresses
PVCA(1, 0),PVCA(1, 1),PVCA(1, 2),PVCA(1, 3),PVCA(1, 4),PVCA(1, 5),
PVCA(1, 6),PVCA(1, 7),PVCA(1, 8),PVCA(1, 9),PVCA(1,10),PVCA(1,11),
PVCA(1,12),PVCA(1,13),PVCA(1,14),PVCA(1,15),PVCA(1,16),PVCA(1,17),
PVCA(1,18),PVCA(1,19),PVCA(1,20),PVCA(1,21),PVCA(1,22),PVCA(1,23),
// Voice Addresses
PVCA(1, 0), PVCA(1, 1), PVCA(1, 2), PVCA(1, 3), PVCA(1, 4), PVCA(1, 5),
PVCA(1, 6), PVCA(1, 7), PVCA(1, 8), PVCA(1, 9), PVCA(1, 10), PVCA(1, 11),
PVCA(1, 12), PVCA(1, 13), PVCA(1, 14), PVCA(1, 15), PVCA(1, 16), PVCA(1, 17),
PVCA(1, 18), PVCA(1, 19), PVCA(1, 20), PVCA(1, 21), PVCA(1, 22), PVCA(1, 23),
PCORE(1,ExtEffectsStartA)+1,
PCORE(1,ExtEffectsStartA),
PCORE(1, ExtEffectsStartA) + 1,
PCORE(1, ExtEffectsStartA),
PREVB_REG(1,FB_SRC_A),
PREVB_REG(1,FB_SRC_B),
PREVB_REG(1,IIR_DEST_A0),
PREVB_REG(1,IIR_DEST_A1),
PREVB_REG(1,ACC_SRC_A0),
PREVB_REG(1,ACC_SRC_A1),
PREVB_REG(1,ACC_SRC_B0),
PREVB_REG(1,ACC_SRC_B1),
PREVB_REG(1,IIR_SRC_A0),
PREVB_REG(1,IIR_SRC_A1),
PREVB_REG(1,IIR_DEST_B0),
PREVB_REG(1,IIR_DEST_B1),
PREVB_REG(1,ACC_SRC_C0),
PREVB_REG(1,ACC_SRC_C1),
PREVB_REG(1,ACC_SRC_D0),
PREVB_REG(1,ACC_SRC_D1),
PREVB_REG(1,IIR_SRC_B0),
PREVB_REG(1,IIR_SRC_B1),
PREVB_REG(1,MIX_DEST_A0),
PREVB_REG(1,MIX_DEST_A1),
PREVB_REG(1,MIX_DEST_B0),
PREVB_REG(1,MIX_DEST_B1),
PREVB_REG(1, FB_SRC_A),
PREVB_REG(1, FB_SRC_B),
PREVB_REG(1, IIR_DEST_A0),
PREVB_REG(1, IIR_DEST_A1),
PREVB_REG(1, ACC_SRC_A0),
PREVB_REG(1, ACC_SRC_A1),
PREVB_REG(1, ACC_SRC_B0),
PREVB_REG(1, ACC_SRC_B1),
PREVB_REG(1, IIR_SRC_A0),
PREVB_REG(1, IIR_SRC_A1),
PREVB_REG(1, IIR_DEST_B0),
PREVB_REG(1, IIR_DEST_B1),
PREVB_REG(1, ACC_SRC_C0),
PREVB_REG(1, ACC_SRC_C1),
PREVB_REG(1, ACC_SRC_D0),
PREVB_REG(1, ACC_SRC_D1),
PREVB_REG(1, IIR_SRC_B0),
PREVB_REG(1, IIR_SRC_B1),
PREVB_REG(1, MIX_DEST_A0),
PREVB_REG(1, MIX_DEST_A1),
PREVB_REG(1, MIX_DEST_B0),
PREVB_REG(1, MIX_DEST_B1),
PCORE(1,ExtEffectsEndA)+1,
PCORE(1,ExtEffectsEndA),
PCORE(1, ExtEffectsEndA) + 1,
PCORE(1, ExtEffectsEndA),
PCORE(1,Regs.ENDX),
PCORE(1,Regs.ENDX)+1,
PCORE(1,Regs.STATX),
PCORE(1, Regs.ENDX),
PCORE(1, Regs.ENDX) + 1,
PCORE(1, Regs.STATX),
PRAW(0x746),
PRAW(0x748),PRAW(0x74A),PRAW(0x74C),PRAW(0x74E),
PRAW(0x750),PRAW(0x752),PRAW(0x754),PRAW(0x756),
PRAW(0x758),PRAW(0x75A),PRAW(0x75C),PRAW(0x75E),
PRAW(0x746),
PRAW(0x748), PRAW(0x74A), PRAW(0x74C), PRAW(0x74E),
PRAW(0x750), PRAW(0x752), PRAW(0x754), PRAW(0x756),
PRAW(0x758), PRAW(0x75A), PRAW(0x75C), PRAW(0x75E),
//0x760: weird area
PCORE(0,MasterVol.Left.Reg_VOL),
PCORE(0,MasterVol.Right.Reg_VOL),
PCORE(0,FxVol.Left)+1,
PCORE(0,FxVol.Right)+1,
PCORE(0,ExtVol.Left)+1,
PCORE(0,ExtVol.Right)+1,
PCORE(0,InpVol.Left)+1,
PCORE(0,InpVol.Right)+1,
PCORE(0,MasterVol.Left.Value)+1,
PCORE(0,MasterVol.Right.Value)+1,
PCORE(0,Revb.IIR_ALPHA),
PCORE(0,Revb.ACC_COEF_A),
PCORE(0,Revb.ACC_COEF_B),
PCORE(0,Revb.ACC_COEF_C),
PCORE(0,Revb.ACC_COEF_D),
PCORE(0,Revb.IIR_COEF),
PCORE(0,Revb.FB_ALPHA),
PCORE(0,Revb.FB_X),
PCORE(0,Revb.IN_COEF_L),
PCORE(0,Revb.IN_COEF_R),
//0x760: weird area
PCORE(0, MasterVol.Left.Reg_VOL),
PCORE(0, MasterVol.Right.Reg_VOL),
PCORE(0, FxVol.Left) + 1,
PCORE(0, FxVol.Right) + 1,
PCORE(0, ExtVol.Left) + 1,
PCORE(0, ExtVol.Right) + 1,
PCORE(0, InpVol.Left) + 1,
PCORE(0, InpVol.Right) + 1,
PCORE(0, MasterVol.Left.Value) + 1,
PCORE(0, MasterVol.Right.Value) + 1,
PCORE(0, Revb.IIR_ALPHA),
PCORE(0, Revb.ACC_COEF_A),
PCORE(0, Revb.ACC_COEF_B),
PCORE(0, Revb.ACC_COEF_C),
PCORE(0, Revb.ACC_COEF_D),
PCORE(0, Revb.IIR_COEF),
PCORE(0, Revb.FB_ALPHA),
PCORE(0, Revb.FB_X),
PCORE(0, Revb.IN_COEF_L),
PCORE(0, Revb.IN_COEF_R),
PCORE(1,MasterVol.Left.Reg_VOL),
PCORE(1,MasterVol.Right.Reg_VOL),
PCORE(1,FxVol.Left)+1,
PCORE(1,FxVol.Right)+1,
PCORE(1,ExtVol.Left)+1,
PCORE(1,ExtVol.Right)+1,
PCORE(1,InpVol.Left)+1,
PCORE(1,InpVol.Right)+1,
PCORE(1,MasterVol.Left.Value)+1,
PCORE(1,MasterVol.Right.Value)+1,
PCORE(1,Revb.IIR_ALPHA),
PCORE(1,Revb.ACC_COEF_A),
PCORE(1,Revb.ACC_COEF_B),
PCORE(1,Revb.ACC_COEF_C),
PCORE(1,Revb.ACC_COEF_D),
PCORE(1,Revb.IIR_COEF),
PCORE(1,Revb.FB_ALPHA),
PCORE(1,Revb.FB_X),
PCORE(1,Revb.IN_COEF_L),
PCORE(1,Revb.IN_COEF_R),
PCORE(1, MasterVol.Left.Reg_VOL),
PCORE(1, MasterVol.Right.Reg_VOL),
PCORE(1, FxVol.Left) + 1,
PCORE(1, FxVol.Right) + 1,
PCORE(1, ExtVol.Left) + 1,
PCORE(1, ExtVol.Right) + 1,
PCORE(1, InpVol.Left) + 1,
PCORE(1, InpVol.Right) + 1,
PCORE(1, MasterVol.Left.Value) + 1,
PCORE(1, MasterVol.Right.Value) + 1,
PCORE(1, Revb.IIR_ALPHA),
PCORE(1, Revb.ACC_COEF_A),
PCORE(1, Revb.ACC_COEF_B),
PCORE(1, Revb.ACC_COEF_C),
PCORE(1, Revb.ACC_COEF_D),
PCORE(1, Revb.IIR_COEF),
PCORE(1, Revb.FB_ALPHA),
PCORE(1, Revb.FB_X),
PCORE(1, Revb.IN_COEF_L),
PCORE(1, Revb.IN_COEF_R),
PRAW(0x7B0),PRAW(0x7B2),PRAW(0x7B4),PRAW(0x7B6),
PRAW(0x7B8),PRAW(0x7BA),PRAW(0x7BC),PRAW(0x7BE),
PRAW(0x7B0), PRAW(0x7B2), PRAW(0x7B4), PRAW(0x7B6),
PRAW(0x7B8), PRAW(0x7BA), PRAW(0x7BC), PRAW(0x7BE),
// SPDIF interface
U16P(Spdif.Out),
U16P(Spdif.Info),
U16P(Spdif.Unknown1),
U16P(Spdif.Mode),
U16P(Spdif.Media),
U16P(Spdif.Unknown2),
U16P(Spdif.Protection),
// SPDIF interface
U16P(Spdif.Out),
U16P(Spdif.Info),
U16P(Spdif.Unknown1),
U16P(Spdif.Mode),
U16P(Spdif.Media),
U16P(Spdif.Unknown2),
U16P(Spdif.Protection),
PRAW(0x7CE),
PRAW(0x7D0),PRAW(0x7D2),PRAW(0x7D4),PRAW(0x7D6),
PRAW(0x7D8),PRAW(0x7DA),PRAW(0x7DC),PRAW(0x7DE),
PRAW(0x7E0),PRAW(0x7E2),PRAW(0x7E4),PRAW(0x7E6),
PRAW(0x7E8),PRAW(0x7EA),PRAW(0x7EC),PRAW(0x7EE),
PRAW(0x7F0),PRAW(0x7F2),PRAW(0x7F4),PRAW(0x7F6),
PRAW(0x7F8),PRAW(0x7FA),PRAW(0x7FC),PRAW(0x7FE),
PRAW(0x7CE),
PRAW(0x7D0), PRAW(0x7D2), PRAW(0x7D4), PRAW(0x7D6),
PRAW(0x7D8), PRAW(0x7DA), PRAW(0x7DC), PRAW(0x7DE),
PRAW(0x7E0), PRAW(0x7E2), PRAW(0x7E4), PRAW(0x7E6),
PRAW(0x7E8), PRAW(0x7EA), PRAW(0x7EC), PRAW(0x7EE),
PRAW(0x7F0), PRAW(0x7F2), PRAW(0x7F4), PRAW(0x7F6),
PRAW(0x7F8), PRAW(0x7FA), PRAW(0x7FC), PRAW(0x7FE),
NULL
};
NULL};

View File

@ -24,38 +24,37 @@
//static LowPassFilter64 lowpass_left( 11000, SampleRate );
//static LowPassFilter64 lowpass_right( 11000, SampleRate );
__forceinline s32 V_Core::RevbGetIndexer( s32 offset )
__forceinline s32 V_Core::RevbGetIndexer(s32 offset)
{
u32 pos = ReverbX + offset;
u32 pos = ReverbX + offset;
// Fast and simple single step wrapping, made possible by the preparation of the
// effects buffer addresses.
// Fast and simple single step wrapping, made possible by the preparation of the
// effects buffer addresses.
if( pos > EffectsEndA )
{
pos -= EffectsEndA+1;
pos += EffectsStartA;
}
if (pos > EffectsEndA) {
pos -= EffectsEndA + 1;
pos += EffectsStartA;
}
assert(pos >= EffectsStartA && pos <= EffectsEndA);
return pos;
assert(pos >= EffectsStartA && pos <= EffectsEndA);
return pos;
}
void V_Core::Reverb_AdvanceBuffer()
{
if( RevBuffers.NeedsUpdated )
UpdateEffectsBufferSize();
if (RevBuffers.NeedsUpdated)
UpdateEffectsBufferSize();
if( (Cycles & 1) && (EffectsBufferSize > 0) )
{
ReverbX += 1;
if( ReverbX >= (u32)EffectsBufferSize ) ReverbX = 0;
}
if ((Cycles & 1) && (EffectsBufferSize > 0)) {
ReverbX += 1;
if (ReverbX >= (u32)EffectsBufferSize)
ReverbX = 0;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
StereoOut32 V_Core::DoReverb( const StereoOut32& Input )
StereoOut32 V_Core::DoReverb(const StereoOut32 &Input)
{
#if 0
static const s32 downcoeffs[8] =
@ -64,222 +63,208 @@ StereoOut32 V_Core::DoReverb( const StereoOut32& Input )
15243, 10895, 5344, 1283
};
#else
// 2/3 of the above
static const s32 downcoeffs[8] =
{
855, 3562, 7263, 10163,
10163, 7263, 3562, 855
};
// 2/3 of the above
static const s32 downcoeffs[8] =
{
855, 3562, 7263, 10163,
10163, 7263, 3562, 855};
#endif
downbuf[dbpos] = Input;
dbpos = (dbpos+1) & 7;
downbuf[dbpos] = Input;
dbpos = (dbpos + 1) & 7;
// Reverb processing occurs at 24khz, so we skip processing every other sample,
// and use the previous calculation for this core instead.
// Reverb processing occurs at 24khz, so we skip processing every other sample,
// and use the previous calculation for this core instead.
if( (Cycles&1) == 0 )
{
// Important: Factor silence into the upsampler here, otherwise the reverb engine
// develops a nasty feedback loop.
if ((Cycles & 1) == 0) {
// Important: Factor silence into the upsampler here, otherwise the reverb engine
// develops a nasty feedback loop.
upbuf[ubpos] = StereoOut32::Empty;
}
else
{
if( EffectsBufferSize <= 0 )
{
ubpos = (ubpos+1) & 7;
return StereoOut32::Empty;
}
upbuf[ubpos] = StereoOut32::Empty;
} else {
if (EffectsBufferSize <= 0) {
ubpos = (ubpos + 1) & 7;
return StereoOut32::Empty;
}
// Advance the current reverb buffer pointer, and cache the read/write addresses we'll be
// needing for this session of reverb.
// Advance the current reverb buffer pointer, and cache the read/write addresses we'll be
// needing for this session of reverb.
const u32 src_a0 = RevbGetIndexer( RevBuffers.IIR_SRC_A0 );
const u32 src_a1 = RevbGetIndexer( RevBuffers.IIR_SRC_A1 );
const u32 src_b0 = RevbGetIndexer( RevBuffers.IIR_SRC_B0 );
const u32 src_b1 = RevbGetIndexer( RevBuffers.IIR_SRC_B1 );
const u32 src_a0 = RevbGetIndexer(RevBuffers.IIR_SRC_A0);
const u32 src_a1 = RevbGetIndexer(RevBuffers.IIR_SRC_A1);
const u32 src_b0 = RevbGetIndexer(RevBuffers.IIR_SRC_B0);
const u32 src_b1 = RevbGetIndexer(RevBuffers.IIR_SRC_B1);
const u32 dest_a0 = RevbGetIndexer( RevBuffers.IIR_DEST_A0 );
const u32 dest_a1 = RevbGetIndexer( RevBuffers.IIR_DEST_A1 );
const u32 dest_b0 = RevbGetIndexer( RevBuffers.IIR_DEST_B0 );
const u32 dest_b1 = RevbGetIndexer( RevBuffers.IIR_DEST_B1 );
const u32 dest_a0 = RevbGetIndexer(RevBuffers.IIR_DEST_A0);
const u32 dest_a1 = RevbGetIndexer(RevBuffers.IIR_DEST_A1);
const u32 dest_b0 = RevbGetIndexer(RevBuffers.IIR_DEST_B0);
const u32 dest_b1 = RevbGetIndexer(RevBuffers.IIR_DEST_B1);
const u32 dest2_a0 = RevbGetIndexer( RevBuffers.IIR_DEST_A0 + 1 );
const u32 dest2_a1 = RevbGetIndexer( RevBuffers.IIR_DEST_A1 + 1 );
const u32 dest2_b0 = RevbGetIndexer( RevBuffers.IIR_DEST_B0 + 1 );
const u32 dest2_b1 = RevbGetIndexer( RevBuffers.IIR_DEST_B1 + 1 );
const u32 dest2_a0 = RevbGetIndexer(RevBuffers.IIR_DEST_A0 + 1);
const u32 dest2_a1 = RevbGetIndexer(RevBuffers.IIR_DEST_A1 + 1);
const u32 dest2_b0 = RevbGetIndexer(RevBuffers.IIR_DEST_B0 + 1);
const u32 dest2_b1 = RevbGetIndexer(RevBuffers.IIR_DEST_B1 + 1);
const u32 acc_src_a0 = RevbGetIndexer( RevBuffers.ACC_SRC_A0 );
const u32 acc_src_b0 = RevbGetIndexer( RevBuffers.ACC_SRC_B0 );
const u32 acc_src_c0 = RevbGetIndexer( RevBuffers.ACC_SRC_C0 );
const u32 acc_src_d0 = RevbGetIndexer( RevBuffers.ACC_SRC_D0 );
const u32 acc_src_a0 = RevbGetIndexer(RevBuffers.ACC_SRC_A0);
const u32 acc_src_b0 = RevbGetIndexer(RevBuffers.ACC_SRC_B0);
const u32 acc_src_c0 = RevbGetIndexer(RevBuffers.ACC_SRC_C0);
const u32 acc_src_d0 = RevbGetIndexer(RevBuffers.ACC_SRC_D0);
const u32 acc_src_a1 = RevbGetIndexer( RevBuffers.ACC_SRC_A1 );
const u32 acc_src_b1 = RevbGetIndexer( RevBuffers.ACC_SRC_B1 );
const u32 acc_src_c1 = RevbGetIndexer( RevBuffers.ACC_SRC_C1 );
const u32 acc_src_d1 = RevbGetIndexer( RevBuffers.ACC_SRC_D1 );
const u32 acc_src_a1 = RevbGetIndexer(RevBuffers.ACC_SRC_A1);
const u32 acc_src_b1 = RevbGetIndexer(RevBuffers.ACC_SRC_B1);
const u32 acc_src_c1 = RevbGetIndexer(RevBuffers.ACC_SRC_C1);
const u32 acc_src_d1 = RevbGetIndexer(RevBuffers.ACC_SRC_D1);
const u32 fb_src_a0 = RevbGetIndexer( RevBuffers.FB_SRC_A0 );
const u32 fb_src_a1 = RevbGetIndexer( RevBuffers.FB_SRC_A1 );
const u32 fb_src_b0 = RevbGetIndexer( RevBuffers.FB_SRC_B0 );
const u32 fb_src_b1 = RevbGetIndexer( RevBuffers.FB_SRC_B1 );
const u32 fb_src_a0 = RevbGetIndexer(RevBuffers.FB_SRC_A0);
const u32 fb_src_a1 = RevbGetIndexer(RevBuffers.FB_SRC_A1);
const u32 fb_src_b0 = RevbGetIndexer(RevBuffers.FB_SRC_B0);
const u32 fb_src_b1 = RevbGetIndexer(RevBuffers.FB_SRC_B1);
const u32 mix_dest_a0 = RevbGetIndexer( RevBuffers.MIX_DEST_A0 );
const u32 mix_dest_a1 = RevbGetIndexer( RevBuffers.MIX_DEST_A1 );
const u32 mix_dest_b0 = RevbGetIndexer( RevBuffers.MIX_DEST_B0 );
const u32 mix_dest_b1 = RevbGetIndexer( RevBuffers.MIX_DEST_B1 );
const u32 mix_dest_a0 = RevbGetIndexer(RevBuffers.MIX_DEST_A0);
const u32 mix_dest_a1 = RevbGetIndexer(RevBuffers.MIX_DEST_A1);
const u32 mix_dest_b0 = RevbGetIndexer(RevBuffers.MIX_DEST_B0);
const u32 mix_dest_b1 = RevbGetIndexer(RevBuffers.MIX_DEST_B1);
// -----------------------------------------
// Optimized IRQ Testing !
// -----------------------------------------
// -----------------------------------------
// Optimized IRQ Testing !
// -----------------------------------------
// This test is enhanced by using the reverb effects area begin/end test as a
// shortcut, since all buffer addresses are within that area. If the IRQA isn't
// within that zone then the "bulk" of the test is skipped, so this should only
// be a slowdown on a few evil games.
// This test is enhanced by using the reverb effects area begin/end test as a
// shortcut, since all buffer addresses are within that area. If the IRQA isn't
// within that zone then the "bulk" of the test is skipped, so this should only
// be a slowdown on a few evil games.
for( int i=0; i<2; i++ )
{
if( Cores[i].IRQEnable && ((Cores[i].IRQA >= EffectsStartA) && (Cores[i].IRQA <= EffectsEndA)) )
{
if( (Cores[i].IRQA == src_a0) || (Cores[i].IRQA == src_a1) ||
(Cores[i].IRQA == src_b0) || (Cores[i].IRQA == src_b1) ||
for (int i = 0; i < 2; i++) {
if (Cores[i].IRQEnable && ((Cores[i].IRQA >= EffectsStartA) && (Cores[i].IRQA <= EffectsEndA))) {
if ((Cores[i].IRQA == src_a0) || (Cores[i].IRQA == src_a1) ||
(Cores[i].IRQA == src_b0) || (Cores[i].IRQA == src_b1) ||
(Cores[i].IRQA == dest_a0) || (Cores[i].IRQA == dest_a1) ||
(Cores[i].IRQA == dest_b0) || (Cores[i].IRQA == dest_b1) ||
(Cores[i].IRQA == dest_a0) || (Cores[i].IRQA == dest_a1) ||
(Cores[i].IRQA == dest_b0) || (Cores[i].IRQA == dest_b1) ||
(Cores[i].IRQA == dest2_a0) || (Cores[i].IRQA == dest2_a1) ||
(Cores[i].IRQA == dest2_b0) || (Cores[i].IRQA == dest2_b1) ||
(Cores[i].IRQA == dest2_a0) || (Cores[i].IRQA == dest2_a1) ||
(Cores[i].IRQA == dest2_b0) || (Cores[i].IRQA == dest2_b1) ||
(Cores[i].IRQA == acc_src_a0) || (Cores[i].IRQA == acc_src_a1) ||
(Cores[i].IRQA == acc_src_b0) || (Cores[i].IRQA == acc_src_b1) ||
(Cores[i].IRQA == acc_src_c0) || (Cores[i].IRQA == acc_src_c1) ||
(Cores[i].IRQA == acc_src_d0) || (Cores[i].IRQA == acc_src_d1) ||
(Cores[i].IRQA == acc_src_a0) || (Cores[i].IRQA == acc_src_a1) ||
(Cores[i].IRQA == acc_src_b0) || (Cores[i].IRQA == acc_src_b1) ||
(Cores[i].IRQA == acc_src_c0) || (Cores[i].IRQA == acc_src_c1) ||
(Cores[i].IRQA == acc_src_d0) || (Cores[i].IRQA == acc_src_d1) ||
(Cores[i].IRQA == fb_src_a0) || (Cores[i].IRQA == fb_src_a1) ||
(Cores[i].IRQA == fb_src_b0) || (Cores[i].IRQA == fb_src_b1) ||
(Cores[i].IRQA == fb_src_a0) || (Cores[i].IRQA == fb_src_a1) ||
(Cores[i].IRQA == fb_src_b0) || (Cores[i].IRQA == fb_src_b1) ||
(Cores[i].IRQA == mix_dest_a0) || (Cores[i].IRQA == mix_dest_a1) ||
(Cores[i].IRQA == mix_dest_b0) || (Cores[i].IRQA == mix_dest_b1) )
{
//printf("Core %d IRQ Called (Reverb). IRQA = %x\n",i,addr);
SetIrqCall(i);
}
}
}
(Cores[i].IRQA == mix_dest_a0) || (Cores[i].IRQA == mix_dest_a1) ||
(Cores[i].IRQA == mix_dest_b0) || (Cores[i].IRQA == mix_dest_b1)) {
//printf("Core %d IRQ Called (Reverb). IRQA = %x\n",i,addr);
SetIrqCall(i);
}
}
}
// -----------------------------------------
// Begin Reverb Processing !
// -----------------------------------------
// -----------------------------------------
// Begin Reverb Processing !
// -----------------------------------------
StereoOut32 INPUT_SAMPLE;
StereoOut32 INPUT_SAMPLE;
for( int x=0; x<8; ++x )
{
INPUT_SAMPLE.Left += (downbuf[(dbpos+x)&7].Left * downcoeffs[x]);
INPUT_SAMPLE.Right += (downbuf[(dbpos+x)&7].Right * downcoeffs[x]);
}
for (int x = 0; x < 8; ++x) {
INPUT_SAMPLE.Left += (downbuf[(dbpos + x) & 7].Left * downcoeffs[x]);
INPUT_SAMPLE.Right += (downbuf[(dbpos + x) & 7].Right * downcoeffs[x]);
}
INPUT_SAMPLE.Left >>= 16;
INPUT_SAMPLE.Right >>= 16;
INPUT_SAMPLE.Left >>= 16;
INPUT_SAMPLE.Right >>= 16;
s32 input_L = INPUT_SAMPLE.Left * Revb.IN_COEF_L;
s32 input_R = INPUT_SAMPLE.Right * Revb.IN_COEF_R;
s32 input_L = INPUT_SAMPLE.Left * Revb.IN_COEF_L;
s32 input_R = INPUT_SAMPLE.Right * Revb.IN_COEF_R;
const s32 IIR_INPUT_A0 = clamp_mix((((s32)_spu2mem[src_a0] * Revb.IIR_COEF) + input_L)>>15);
const s32 IIR_INPUT_A1 = clamp_mix((((s32)_spu2mem[src_a1] * Revb.IIR_COEF) + input_L)>>15);
const s32 IIR_INPUT_B0 = clamp_mix((((s32)_spu2mem[src_b0] * Revb.IIR_COEF) + input_R)>>15);
const s32 IIR_INPUT_B1 = clamp_mix((((s32)_spu2mem[src_b1] * Revb.IIR_COEF) + input_R)>>15);
const s32 IIR_INPUT_A0 = clamp_mix((((s32)_spu2mem[src_a0] * Revb.IIR_COEF) + input_L) >> 15);
const s32 IIR_INPUT_A1 = clamp_mix((((s32)_spu2mem[src_a1] * Revb.IIR_COEF) + input_L) >> 15);
const s32 IIR_INPUT_B0 = clamp_mix((((s32)_spu2mem[src_b0] * Revb.IIR_COEF) + input_R) >> 15);
const s32 IIR_INPUT_B1 = clamp_mix((((s32)_spu2mem[src_b1] * Revb.IIR_COEF) + input_R) >> 15);
const s32 src_dest_a0 = _spu2mem[dest_a0];
const s32 src_dest_a1 = _spu2mem[dest_a1];
const s32 src_dest_b0 = _spu2mem[dest_b0];
const s32 src_dest_b1 = _spu2mem[dest_b1];
const s32 src_dest_a0 = _spu2mem[dest_a0];
const s32 src_dest_a1 = _spu2mem[dest_a1];
const s32 src_dest_b0 = _spu2mem[dest_b0];
const s32 src_dest_b1 = _spu2mem[dest_b1];
// This section differs from Neill's doc as it uses single-mul interpolation instead
// of 0x8000-val inversion. (same result, faster)
const s32 IIR_A0 = src_dest_a0 + (((IIR_INPUT_A0 - src_dest_a0) * Revb.IIR_ALPHA)>>15);
const s32 IIR_A1 = src_dest_a1 + (((IIR_INPUT_A1 - src_dest_a1) * Revb.IIR_ALPHA)>>15);
const s32 IIR_B0 = src_dest_b0 + (((IIR_INPUT_B0 - src_dest_b0) * Revb.IIR_ALPHA)>>15);
const s32 IIR_B1 = src_dest_b1 + (((IIR_INPUT_B1 - src_dest_b1) * Revb.IIR_ALPHA)>>15);
_spu2mem[dest2_a0] = clamp_mix( IIR_A0 );
_spu2mem[dest2_a1] = clamp_mix( IIR_A1 );
_spu2mem[dest2_b0] = clamp_mix( IIR_B0 );
_spu2mem[dest2_b1] = clamp_mix( IIR_B1 );
// This section differs from Neill's doc as it uses single-mul interpolation instead
// of 0x8000-val inversion. (same result, faster)
const s32 IIR_A0 = src_dest_a0 + (((IIR_INPUT_A0 - src_dest_a0) * Revb.IIR_ALPHA) >> 15);
const s32 IIR_A1 = src_dest_a1 + (((IIR_INPUT_A1 - src_dest_a1) * Revb.IIR_ALPHA) >> 15);
const s32 IIR_B0 = src_dest_b0 + (((IIR_INPUT_B0 - src_dest_b0) * Revb.IIR_ALPHA) >> 15);
const s32 IIR_B1 = src_dest_b1 + (((IIR_INPUT_B1 - src_dest_b1) * Revb.IIR_ALPHA) >> 15);
_spu2mem[dest2_a0] = clamp_mix(IIR_A0);
_spu2mem[dest2_a1] = clamp_mix(IIR_A1);
_spu2mem[dest2_b0] = clamp_mix(IIR_B0);
_spu2mem[dest2_b1] = clamp_mix(IIR_B1);
const s32 ACC0 = clamp_mix(
((_spu2mem[acc_src_a0] * Revb.ACC_COEF_A) >> 15) +
((_spu2mem[acc_src_b0] * Revb.ACC_COEF_B) >> 15) +
((_spu2mem[acc_src_c0] * Revb.ACC_COEF_C) >> 15) +
((_spu2mem[acc_src_d0] * Revb.ACC_COEF_D) >> 15)
);
const s32 ACC0 = clamp_mix(
((_spu2mem[acc_src_a0] * Revb.ACC_COEF_A) >> 15) +
((_spu2mem[acc_src_b0] * Revb.ACC_COEF_B) >> 15) +
((_spu2mem[acc_src_c0] * Revb.ACC_COEF_C) >> 15) +
((_spu2mem[acc_src_d0] * Revb.ACC_COEF_D) >> 15));
const s32 ACC1 = clamp_mix(
((_spu2mem[acc_src_a1] * Revb.ACC_COEF_A) >> 15) +
((_spu2mem[acc_src_b1] * Revb.ACC_COEF_B) >> 15) +
((_spu2mem[acc_src_c1] * Revb.ACC_COEF_C) >> 15) +
((_spu2mem[acc_src_d1] * Revb.ACC_COEF_D) >> 15)
);
const s32 ACC1 = clamp_mix(
((_spu2mem[acc_src_a1] * Revb.ACC_COEF_A) >> 15) +
((_spu2mem[acc_src_b1] * Revb.ACC_COEF_B) >> 15) +
((_spu2mem[acc_src_c1] * Revb.ACC_COEF_C) >> 15) +
((_spu2mem[acc_src_d1] * Revb.ACC_COEF_D) >> 15));
// The following code differs from Neill's doc as it uses the more natural single-mul
// interpolative, instead of the funky ^0x8000 stuff. (better result, faster)
// The following code differs from Neill's doc as it uses the more natural single-mul
// interpolative, instead of the funky ^0x8000 stuff. (better result, faster)
const s32 FB_A0 = _spu2mem[fb_src_a0];
const s32 FB_A1 = _spu2mem[fb_src_a1];
const s32 FB_B0 = _spu2mem[fb_src_b0];
const s32 FB_B1 = _spu2mem[fb_src_b1];
const s32 FB_A0 = _spu2mem[fb_src_a0];
const s32 FB_A1 = _spu2mem[fb_src_a1];
const s32 FB_B0 = _spu2mem[fb_src_b0];
const s32 FB_B1 = _spu2mem[fb_src_b1];
const s32 mix_a0 = clamp_mix(ACC0 - ((FB_A0 * Revb.FB_ALPHA) >> 15));
const s32 mix_a1 = clamp_mix(ACC1 - ((FB_A1 * Revb.FB_ALPHA) >> 15));
const s32 mix_b0 = clamp_mix(FB_A0 + (((ACC0 - FB_A0) * Revb.FB_ALPHA - FB_B0 * Revb.FB_X) >> 15));
const s32 mix_b1 = clamp_mix(FB_A1 + (((ACC1 - FB_A1) * Revb.FB_ALPHA - FB_B1 * Revb.FB_X) >> 15));
const s32 mix_a0 = clamp_mix(ACC0 - ((FB_A0 * Revb.FB_ALPHA) >> 15));
const s32 mix_a1 = clamp_mix(ACC1 - ((FB_A1 * Revb.FB_ALPHA) >> 15));
const s32 mix_b0 = clamp_mix(FB_A0 + (((ACC0 - FB_A0) * Revb.FB_ALPHA - FB_B0 * Revb.FB_X) >> 15));
const s32 mix_b1 = clamp_mix(FB_A1 + (((ACC1 - FB_A1) * Revb.FB_ALPHA - FB_B1 * Revb.FB_X) >> 15));
_spu2mem[mix_dest_a0] = mix_a0;
_spu2mem[mix_dest_a1] = mix_a1;
_spu2mem[mix_dest_b0] = mix_b0;
_spu2mem[mix_dest_b1] = mix_b1;
_spu2mem[mix_dest_a0] = mix_a0;
_spu2mem[mix_dest_a1] = mix_a1;
_spu2mem[mix_dest_b0] = mix_b0;
_spu2mem[mix_dest_b1] = mix_b1;
upbuf[ubpos] = clamp_mix( StereoOut32(
mix_a0 + mix_b0, // left
mix_a1 + mix_b1 // right
) );
}
upbuf[ubpos] = clamp_mix(StereoOut32(
mix_a0 + mix_b0, // left
mix_a1 + mix_b1 // right
));
}
StereoOut32 retval;
StereoOut32 retval;
//for( int x=0; x<8; ++x )
//{
// retval.Left += (upbuf[(ubpos+x)&7].Left*downcoeffs[x]);
// retval.Right += (upbuf[(ubpos+x)&7].Right*downcoeffs[x]);
//}
//for( int x=0; x<8; ++x )
//{
// retval.Left += (upbuf[(ubpos+x)&7].Left*downcoeffs[x]);
// retval.Right += (upbuf[(ubpos+x)&7].Right*downcoeffs[x]);
//}
if( (Cycles&1) == 0 )
{
retval.Left = (upbuf[(ubpos+5)&7].Left + upbuf[(ubpos+7)&7].Left)>>1;
retval.Right = (upbuf[(ubpos+5)&7].Right + upbuf[(ubpos+7)&7].Right)>>1;
}
else
{
retval.Left = upbuf[(ubpos+6)&7].Left;
retval.Right = upbuf[(ubpos+6)&7].Right;
}
if ((Cycles & 1) == 0) {
retval.Left = (upbuf[(ubpos + 5) & 7].Left + upbuf[(ubpos + 7) & 7].Left) >> 1;
retval.Right = (upbuf[(ubpos + 5) & 7].Right + upbuf[(ubpos + 7) & 7].Right) >> 1;
} else {
retval.Left = upbuf[(ubpos + 6) & 7].Left;
retval.Right = upbuf[(ubpos + 6) & 7].Right;
}
// Notes:
// the first -1 is to adjust for the null padding in every other upbuf sample (which
// halves the overall volume).
// The second +1 divides by two, which is part of Neill's suggestion to divide by 3.
//
// According Neill the final result should be divided by 3, but currently the output
// is way too quiet for that to fly. In fact no division at all might be better.
// In any case the problem always seems to be that the reverb isn't resonating enough
// (indicating short buffers or bad coefficient math?), not that it isn't loud enough.
// Notes:
// the first -1 is to adjust for the null padding in every other upbuf sample (which
// halves the overall volume).
// The second +1 divides by two, which is part of Neill's suggestion to divide by 3.
//
// According Neill the final result should be divided by 3, but currently the output
// is way too quiet for that to fly. In fact no division at all might be better.
// In any case the problem always seems to be that the reverb isn't resonating enough
// (indicating short buffers or bad coefficient math?), not that it isn't loud enough.
//retval.Left >>= (16-1 + 1);
//retval.Right >>= (16-1 + 1);
//retval.Left >>= (16-1 + 1);
//retval.Right >>= (16-1 + 1);
ubpos = (ubpos+1) & 7;
ubpos = (ubpos + 1) & 7;
return retval;
return retval;
}

View File

@ -18,99 +18,95 @@
#include "Global.h"
StereoOut32 StereoOut32::Empty( 0, 0 );
StereoOut32 StereoOut32::Empty(0, 0);
StereoOut32::StereoOut32( const StereoOut16& src ) :
Left( src.Left ),
Right( src.Right )
StereoOut32::StereoOut32(const StereoOut16 &src)
: Left(src.Left)
, Right(src.Right)
{
}
StereoOut32::StereoOut32( const StereoOutFloat& src ) :
Left( (s32)(src.Left * 2147483647.0f) ),
Right( (s32)(src.Right * 2147483647.0f) )
StereoOut32::StereoOut32(const StereoOutFloat &src)
: Left((s32)(src.Left * 2147483647.0f))
, Right((s32)(src.Right * 2147483647.0f))
{
}
StereoOut16 StereoOut32::DownSample() const
{
return StereoOut16(
Left >> SndOutVolumeShift,
Right >> SndOutVolumeShift
);
return StereoOut16(
Left >> SndOutVolumeShift,
Right >> SndOutVolumeShift);
}
StereoOut32 StereoOut16::UpSample() const
{
return StereoOut32(
Left << SndOutVolumeShift,
Right << SndOutVolumeShift
);
return StereoOut32(
Left << SndOutVolumeShift,
Right << SndOutVolumeShift);
}
class NullOutModule: public SndOutModule
class NullOutModule : public SndOutModule
{
public:
s32 Init() { return 0; }
void Close() { }
s32 Test() const { return 0; }
void Configure(uptr parent) { }
int GetEmptySampleCount() { return 0; }
s32 Init() { return 0; }
void Close() {}
s32 Test() const { return 0; }
void Configure(uptr parent) {}
int GetEmptySampleCount() { return 0; }
const wchar_t* GetIdent() const
{
return L"nullout";
}
const wchar_t *GetIdent() const
{
return L"nullout";
}
const wchar_t* GetLongName() const
{
return L"No Sound (Emulate SPU2 only)";
}
const wchar_t *GetLongName() const
{
return L"No Sound (Emulate SPU2 only)";
}
void ReadSettings()
{
}
void ReadSettings()
{
}
void SetApiSettings(wxString api)
{
}
void SetApiSettings(wxString api)
{
}
void WriteSettings() const
{
}
void WriteSettings() const
{
}
} NullOut;
SndOutModule* mods[]=
{
&NullOut,
SndOutModule *mods[] =
{
&NullOut,
#ifdef _MSC_VER
XAudio2_27_Out,
DSoundOut,
WaveOut,
XAudio2_27_Out,
DSoundOut,
WaveOut,
#endif
PortaudioOut,
PortaudioOut,
#if defined(SPU2X_SDL) || defined(SPU2X_SDL2)
SDLOut,
SDLOut,
#endif
#if defined(__linux__) /* && defined(__ALSA__)*/
AlsaOut,
AlsaOut,
#endif
NULL // signals the end of our list
NULL // signals the end of our list
};
int FindOutputModuleById( const wchar_t* omodid )
int FindOutputModuleById(const wchar_t *omodid)
{
int modcnt = 0;
while( mods[modcnt] != NULL )
{
if( wcscmp( mods[modcnt]->GetIdent(), omodid ) == 0 )
break;
++modcnt;
}
return modcnt;
int modcnt = 0;
while (mods[modcnt] != NULL) {
if (wcscmp(mods[modcnt]->GetIdent(), omodid) == 0)
break;
++modcnt;
}
return modcnt;
}
StereoOut32 *SndBuffer::m_buffer;
@ -119,229 +115,215 @@ __aligned(4) volatile s32 SndBuffer::m_rpos;
__aligned(4) volatile s32 SndBuffer::m_wpos;
bool SndBuffer::m_underrun_freeze;
StereoOut32* SndBuffer::sndTempBuffer = NULL;
StereoOut16* SndBuffer::sndTempBuffer16 = NULL;
StereoOut32 *SndBuffer::sndTempBuffer = NULL;
StereoOut16 *SndBuffer::sndTempBuffer16 = NULL;
int SndBuffer::sndTempProgress = 0;
int GetAlignedBufferSize( int comp )
int GetAlignedBufferSize(int comp)
{
return (comp + SndOutPacketSize-1) & ~(SndOutPacketSize-1);
return (comp + SndOutPacketSize - 1) & ~(SndOutPacketSize - 1);
}
// Returns TRUE if there is data to be output, or false if no data
// is available to be copied.
bool SndBuffer::CheckUnderrunStatus( int& nSamples, int& quietSampleCount )
bool SndBuffer::CheckUnderrunStatus(int &nSamples, int &quietSampleCount)
{
quietSampleCount = 0;
quietSampleCount = 0;
int data = _GetApproximateDataInBuffer();
if( m_underrun_freeze )
{
int toFill = m_size / ( (SynchMode == 2) ? 32 : 400); // TimeStretch and Async off?
toFill = GetAlignedBufferSize( toFill );
int data = _GetApproximateDataInBuffer();
if (m_underrun_freeze) {
int toFill = m_size / ((SynchMode == 2) ? 32 : 400); // TimeStretch and Async off?
toFill = GetAlignedBufferSize(toFill);
// toFill is now aligned to a SndOutPacket
// toFill is now aligned to a SndOutPacket
if( data < toFill )
{
quietSampleCount = nSamples;
return false;
}
if (data < toFill) {
quietSampleCount = nSamples;
return false;
}
m_underrun_freeze = false;
if( MsgOverruns() )
ConLog(" * SPU2 > Underrun compensation (%d packets buffered)\n", toFill / SndOutPacketSize );
lastPct = 0.0; // normalize timestretcher
}
else if( data < nSamples )
{
nSamples = data;
quietSampleCount = SndOutPacketSize - data;
m_underrun_freeze = true;
m_underrun_freeze = false;
if (MsgOverruns())
ConLog(" * SPU2 > Underrun compensation (%d packets buffered)\n", toFill / SndOutPacketSize);
lastPct = 0.0; // normalize timestretcher
} else if (data < nSamples) {
nSamples = data;
quietSampleCount = SndOutPacketSize - data;
m_underrun_freeze = true;
if( SynchMode == 0 ) // TimeStrech on
timeStretchUnderrun();
if (SynchMode == 0) // TimeStrech on
timeStretchUnderrun();
return nSamples != 0;
}
return nSamples != 0;
}
return true;
return true;
}
void SndBuffer::_InitFail()
{
// If a failure occurs, just initialize the NoSound driver. This'll allow
// the game to emulate properly (hopefully), albeit without sound.
OutputModule = FindOutputModuleById( NullOut.GetIdent() );
mods[OutputModule]->Init();
// If a failure occurs, just initialize the NoSound driver. This'll allow
// the game to emulate properly (hopefully), albeit without sound.
OutputModule = FindOutputModuleById(NullOut.GetIdent());
mods[OutputModule]->Init();
}
int SndBuffer::_GetApproximateDataInBuffer()
{
// WARNING: not necessarily 100% up to date by the time it's used, but it will have to do.
return (m_wpos + m_size - m_rpos) % m_size;
// WARNING: not necessarily 100% up to date by the time it's used, but it will have to do.
return (m_wpos + m_size - m_rpos) % m_size;
}
void SndBuffer::_WriteSamples_Internal(StereoOut32 *bData, int nSamples)
{
// WARNING: This assumes the write will NOT wrap around,
// and also assumes there's enough free space in the buffer.
// WARNING: This assumes the write will NOT wrap around,
// and also assumes there's enough free space in the buffer.
memcpy(m_buffer + m_wpos, bData, nSamples * sizeof(StereoOut32));
m_wpos = (m_wpos + nSamples) % m_size;
memcpy(m_buffer + m_wpos, bData, nSamples * sizeof(StereoOut32));
m_wpos = (m_wpos + nSamples) % m_size;
}
void SndBuffer::_DropSamples_Internal(int nSamples)
{
m_rpos = (m_rpos + nSamples) % m_size;
m_rpos = (m_rpos + nSamples) % m_size;
}
void SndBuffer::_ReadSamples_Internal(StereoOut32 *bData, int nSamples)
{
// WARNING: This assumes the read will NOT wrap around,
// and also assumes there's enough data in the buffer.
memcpy(bData, m_buffer + m_rpos, nSamples * sizeof(StereoOut32));
_DropSamples_Internal(nSamples);
// WARNING: This assumes the read will NOT wrap around,
// and also assumes there's enough data in the buffer.
memcpy(bData, m_buffer + m_rpos, nSamples * sizeof(StereoOut32));
_DropSamples_Internal(nSamples);
}
void SndBuffer::_WriteSamples_Safe(StereoOut32 *bData, int nSamples)
{
// WARNING: This code assumes there's only ONE writing process.
if( (m_size - m_wpos) < nSamples)
{
int b1 = m_size - m_wpos;
int b2 = nSamples - b1;
// WARNING: This code assumes there's only ONE writing process.
if ((m_size - m_wpos) < nSamples) {
int b1 = m_size - m_wpos;
int b2 = nSamples - b1;
_WriteSamples_Internal(bData, b1);
_WriteSamples_Internal(bData+b1, b2);
}
else
{
_WriteSamples_Internal(bData, nSamples);
}
_WriteSamples_Internal(bData, b1);
_WriteSamples_Internal(bData + b1, b2);
} else {
_WriteSamples_Internal(bData, nSamples);
}
}
void SndBuffer::_ReadSamples_Safe(StereoOut32* bData, int nSamples)
void SndBuffer::_ReadSamples_Safe(StereoOut32 *bData, int nSamples)
{
// WARNING: This code assumes there's only ONE reading process.
if( (m_size - m_rpos) < nSamples)
{
int b1 = m_size - m_rpos;
int b2 = nSamples - b1;
// WARNING: This code assumes there's only ONE reading process.
if ((m_size - m_rpos) < nSamples) {
int b1 = m_size - m_rpos;
int b2 = nSamples - b1;
_ReadSamples_Internal(bData, b1);
_ReadSamples_Internal(bData+b1, b2);
}
else
{
_ReadSamples_Internal(bData, nSamples);
}
_ReadSamples_Internal(bData, b1);
_ReadSamples_Internal(bData + b1, b2);
} else {
_ReadSamples_Internal(bData, nSamples);
}
}
// Note: When using with 32 bit output buffers, the user of this function is responsible
// for shifting the values to where they need to be manually. The fixed point depth of
// the sample output is determined by the SndOutVolumeShift, which is the number of bits
// to shift right to get a 16 bit result.
template<typename T> void SndBuffer::ReadSamples(T* bData)
template <typename T>
void SndBuffer::ReadSamples(T *bData)
{
int nSamples = SndOutPacketSize;
int nSamples = SndOutPacketSize;
// Problem:
// If the SPU2 gets even the least bit out of sync with the SndOut device,
// the readpos of the circular buffer will overtake the writepos,
// leading to a prolonged period of hopscotching read/write accesses (ie,
// lots of staticy crap sound for several seconds).
//
// Fix:
// If the read position overtakes the write position, abort the
// transfer immediately and force the SndOut driver to wait until
// the read buffer has filled up again before proceeding.
// This will cause one brief hiccup that can never exceed the user's
// set buffer length in duration.
// Problem:
// If the SPU2 gets even the least bit out of sync with the SndOut device,
// the readpos of the circular buffer will overtake the writepos,
// leading to a prolonged period of hopscotching read/write accesses (ie,
// lots of staticy crap sound for several seconds).
//
// Fix:
// If the read position overtakes the write position, abort the
// transfer immediately and force the SndOut driver to wait until
// the read buffer has filled up again before proceeding.
// This will cause one brief hiccup that can never exceed the user's
// set buffer length in duration.
int quietSamples;
if( CheckUnderrunStatus( nSamples, quietSamples ) )
{
pxAssume( nSamples <= SndOutPacketSize );
int quietSamples;
if (CheckUnderrunStatus(nSamples, quietSamples)) {
pxAssume(nSamples <= SndOutPacketSize);
// WARNING: This code assumes there's only ONE reading process.
int b1 = m_size - m_rpos;
// WARNING: This code assumes there's only ONE reading process.
int b1 = m_size - m_rpos;
if(b1 > nSamples)
b1 = nSamples;
if (b1 > nSamples)
b1 = nSamples;
if (AdvancedVolumeControl)
{
// First part
for (int i = 0; i < b1; i++)
bData[i].AdjustFrom(m_buffer[i + m_rpos]);
if (AdvancedVolumeControl) {
// First part
for (int i = 0; i < b1; i++)
bData[i].AdjustFrom(m_buffer[i + m_rpos]);
// Second part
int b2 = nSamples - b1;
for (int i = 0; i < b2; i++)
bData[i + b1].AdjustFrom(m_buffer[i]);
}
else
{
// First part
for (int i = 0; i < b1; i++)
bData[i].ResampleFrom(m_buffer[i + m_rpos]);
// Second part
int b2 = nSamples - b1;
for (int i = 0; i < b2; i++)
bData[i + b1].AdjustFrom(m_buffer[i]);
} else {
// First part
for (int i = 0; i < b1; i++)
bData[i].ResampleFrom(m_buffer[i + m_rpos]);
// Second part
int b2 = nSamples - b1;
for (int i = 0; i < b2; i++)
bData[i + b1].ResampleFrom(m_buffer[i]);
}
// Second part
int b2 = nSamples - b1;
for (int i = 0; i < b2; i++)
bData[i + b1].ResampleFrom(m_buffer[i]);
}
_DropSamples_Internal(nSamples);
}
_DropSamples_Internal(nSamples);
}
// If quietSamples != 0 it means we have an underrun...
// Let's just dull out some silence, because that's usually the least
// painful way of dealing with underruns:
memset( bData, 0, quietSamples * sizeof(T) );
// If quietSamples != 0 it means we have an underrun...
// Let's just dull out some silence, because that's usually the least
// painful way of dealing with underruns:
memset(bData, 0, quietSamples * sizeof(T));
}
template void SndBuffer::ReadSamples(StereoOut16*);
template void SndBuffer::ReadSamples(StereoOut32*);
template void SndBuffer::ReadSamples(StereoOut16 *);
template void SndBuffer::ReadSamples(StereoOut32 *);
//template void SndBuffer::ReadSamples(StereoOutFloat*);
template void SndBuffer::ReadSamples(Stereo21Out16*);
template void SndBuffer::ReadSamples(Stereo40Out16*);
template void SndBuffer::ReadSamples(Stereo41Out16*);
template void SndBuffer::ReadSamples(Stereo51Out16*);
template void SndBuffer::ReadSamples(Stereo51Out16Dpl*);
template void SndBuffer::ReadSamples(Stereo51Out16DplII*);
template void SndBuffer::ReadSamples(Stereo71Out16*);
template void SndBuffer::ReadSamples(Stereo21Out16 *);
template void SndBuffer::ReadSamples(Stereo40Out16 *);
template void SndBuffer::ReadSamples(Stereo41Out16 *);
template void SndBuffer::ReadSamples(Stereo51Out16 *);
template void SndBuffer::ReadSamples(Stereo51Out16Dpl *);
template void SndBuffer::ReadSamples(Stereo51Out16DplII *);
template void SndBuffer::ReadSamples(Stereo71Out16 *);
template void SndBuffer::ReadSamples(Stereo20Out32*);
template void SndBuffer::ReadSamples(Stereo21Out32*);
template void SndBuffer::ReadSamples(Stereo40Out32*);
template void SndBuffer::ReadSamples(Stereo41Out32*);
template void SndBuffer::ReadSamples(Stereo51Out32*);
template void SndBuffer::ReadSamples(Stereo51Out32Dpl*);
template void SndBuffer::ReadSamples(Stereo51Out32DplII*);
template void SndBuffer::ReadSamples(Stereo71Out32*);
template void SndBuffer::ReadSamples(Stereo20Out32 *);
template void SndBuffer::ReadSamples(Stereo21Out32 *);
template void SndBuffer::ReadSamples(Stereo40Out32 *);
template void SndBuffer::ReadSamples(Stereo41Out32 *);
template void SndBuffer::ReadSamples(Stereo51Out32 *);
template void SndBuffer::ReadSamples(Stereo51Out32Dpl *);
template void SndBuffer::ReadSamples(Stereo51Out32DplII *);
template void SndBuffer::ReadSamples(Stereo71Out32 *);
void SndBuffer::_WriteSamples(StereoOut32 *bData, int nSamples)
{
m_predictData = 0;
m_predictData = 0;
// Problem:
// If the SPU2 gets out of sync with the SndOut device, the writepos of the
// circular buffer will overtake the readpos, leading to a prolonged period
// of hopscotching read/write accesses (ie, lots of staticy crap sound for
// several seconds).
//
// Compromise:
// When an overrun occurs, we adapt by discarding a portion of the buffer.
// The older portion of the buffer is discarded rather than incoming data,
// so that the overall audio synchronization is better.
// Problem:
// If the SPU2 gets out of sync with the SndOut device, the writepos of the
// circular buffer will overtake the readpos, leading to a prolonged period
// of hopscotching read/write accesses (ie, lots of staticy crap sound for
// several seconds).
//
// Compromise:
// When an overrun occurs, we adapt by discarding a portion of the buffer.
// The older portion of the buffer is discarded rather than incoming data,
// so that the overall audio synchronization is better.
int free = m_size - _GetApproximateDataInBuffer(); // -1, but the <= handles that
if( free <= nSamples )
{
// Disabled since the lock-free queue can't handle changing the read end from the write thread
int free = m_size - _GetApproximateDataInBuffer(); // -1, but the <= handles that
if (free <= nSamples) {
// Disabled since the lock-free queue can't handle changing the read end from the write thread
#if 0
// Buffer overrun!
// Dump samples from the read portion of the buffer instead of dropping
@ -366,72 +348,69 @@ void SndBuffer::_WriteSamples(StereoOut32 *bData, int nSamples)
ConLog(" * SPU2 > Overrun Compensation (%d packets tossed)\n", comp / SndOutPacketSize );
lastPct = 0.0; // normalize the timestretcher
#else
if( MsgOverruns() )
ConLog(" * SPU2 > Overrun! 1 packet tossed)\n");
lastPct = 0.0; // normalize the timestretcher
return;
if (MsgOverruns())
ConLog(" * SPU2 > Overrun! 1 packet tossed)\n");
lastPct = 0.0; // normalize the timestretcher
return;
#endif
}
}
_WriteSamples_Safe(bData, nSamples);
_WriteSamples_Safe(bData, nSamples);
}
void SndBuffer::Init()
{
if( mods[OutputModule] == NULL )
{
_InitFail();
return;
}
if (mods[OutputModule] == NULL) {
_InitFail();
return;
}
// initialize sound buffer
// Buffer actually attempts to run ~50%, so allocate near double what
// the requested latency is:
m_rpos = 0;
m_wpos = 0;
// initialize sound buffer
// Buffer actually attempts to run ~50%, so allocate near double what
// the requested latency is:
try
{
const float latencyMS = SndOutLatencyMS * 16;
m_size = GetAlignedBufferSize( (int)(latencyMS * SampleRate / 1000.0f ) );
m_buffer = new StereoOut32[m_size];
m_underrun_freeze = false;
m_rpos = 0;
m_wpos = 0;
sndTempBuffer = new StereoOut32[SndOutPacketSize];
sndTempBuffer16 = new StereoOut16[SndOutPacketSize * 2]; // in case of leftovers.
}
catch( std::bad_alloc& )
{
// out of memory exception (most likely)
try {
const float latencyMS = SndOutLatencyMS * 16;
m_size = GetAlignedBufferSize((int)(latencyMS * SampleRate / 1000.0f));
m_buffer = new StereoOut32[m_size];
m_underrun_freeze = false;
SysMessage( "Out of memory error occurred while initializing SPU2." );
_InitFail();
return;
}
sndTempBuffer = new StereoOut32[SndOutPacketSize];
sndTempBuffer16 = new StereoOut16[SndOutPacketSize * 2]; // in case of leftovers.
} catch (std::bad_alloc &) {
// out of memory exception (most likely)
// clear buffers!
// Fixes loopy sounds on emu resets.
memset( sndTempBuffer, 0, sizeof(StereoOut32) * SndOutPacketSize );
memset( sndTempBuffer16, 0, sizeof(StereoOut16) * SndOutPacketSize );
SysMessage("Out of memory error occurred while initializing SPU2.");
_InitFail();
return;
}
sndTempProgress = 0;
// clear buffers!
// Fixes loopy sounds on emu resets.
memset(sndTempBuffer, 0, sizeof(StereoOut32) * SndOutPacketSize);
memset(sndTempBuffer16, 0, sizeof(StereoOut16) * SndOutPacketSize);
soundtouchInit(); // initializes the timestretching
sndTempProgress = 0;
// initialize module
if( mods[OutputModule]->Init() == -1 ) _InitFail();
soundtouchInit(); // initializes the timestretching
// initialize module
if (mods[OutputModule]->Init() == -1)
_InitFail();
}
void SndBuffer::Cleanup()
{
mods[OutputModule]->Close();
mods[OutputModule]->Close();
soundtouchCleanup();
soundtouchCleanup();
safe_delete_array( m_buffer );
safe_delete_array( sndTempBuffer );
safe_delete_array( sndTempBuffer16 );
safe_delete_array(m_buffer);
safe_delete_array(sndTempBuffer);
safe_delete_array(sndTempBuffer16);
}
int SndBuffer::m_dsp_progress = 0;
@ -441,77 +420,77 @@ int SndBuffer::ssFreeze = 0;
void SndBuffer::ClearContents()
{
SndBuffer::soundtouchClearContents();
SndBuffer::ssFreeze = 256; //Delays sound output for about 1 second.
SndBuffer::soundtouchClearContents();
SndBuffer::ssFreeze = 256; //Delays sound output for about 1 second.
}
void SndBuffer::Write( const StereoOut32& Sample )
void SndBuffer::Write(const StereoOut32 &Sample)
{
// Log final output to wavefile.
WaveDump::WriteCore( 1, CoreSrc_External, Sample.DownSample() );
// Log final output to wavefile.
WaveDump::WriteCore(1, CoreSrc_External, Sample.DownSample());
if( WavRecordEnabled ) RecordWrite( Sample.DownSample() );
if (WavRecordEnabled)
RecordWrite(Sample.DownSample());
if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p
return;
if (mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p
return;
sndTempBuffer[sndTempProgress++] = Sample;
sndTempBuffer[sndTempProgress++] = Sample;
// If we haven't accumulated a full packet yet, do nothing more:
if(sndTempProgress < SndOutPacketSize) return;
sndTempProgress = 0;
// If we haven't accumulated a full packet yet, do nothing more:
if (sndTempProgress < SndOutPacketSize)
return;
sndTempProgress = 0;
//Don't play anything directly after loading a savestate, avoids static killing your speakers.
if ( ssFreeze > 0 )
{
ssFreeze--;
memset( sndTempBuffer, 0, sizeof(StereoOut32) * SndOutPacketSize ); // Play silence
}
//Don't play anything directly after loading a savestate, avoids static killing your speakers.
if (ssFreeze > 0) {
ssFreeze--;
memset(sndTempBuffer, 0, sizeof(StereoOut32) * SndOutPacketSize); // Play silence
}
#ifndef __POSIX__
if( dspPluginEnabled )
{
// Convert in, send to winamp DSP, and convert out.
if (dspPluginEnabled) {
// Convert in, send to winamp DSP, and convert out.
int ei= m_dsp_progress;
for( int i=0; i<SndOutPacketSize; ++i, ++ei ) { sndTempBuffer16[ei] = sndTempBuffer[i].DownSample(); }
m_dsp_progress += DspProcess( (s16*)sndTempBuffer16 + m_dsp_progress, SndOutPacketSize );
int ei = m_dsp_progress;
for (int i = 0; i < SndOutPacketSize; ++i, ++ei) {
sndTempBuffer16[ei] = sndTempBuffer[i].DownSample();
}
m_dsp_progress += DspProcess((s16 *)sndTempBuffer16 + m_dsp_progress, SndOutPacketSize);
// Some ugly code to ensure full packet handling:
ei = 0;
while( m_dsp_progress >= SndOutPacketSize )
{
for( int i=0; i<SndOutPacketSize; ++i, ++ei ) { sndTempBuffer[i] = sndTempBuffer16[ei].UpSample(); }
// Some ugly code to ensure full packet handling:
ei = 0;
while (m_dsp_progress >= SndOutPacketSize) {
for (int i = 0; i < SndOutPacketSize; ++i, ++ei) {
sndTempBuffer[i] = sndTempBuffer16[ei].UpSample();
}
if( SynchMode == 0 ) // TimeStrech on
timeStretchWrite();
else
_WriteSamples(sndTempBuffer, SndOutPacketSize);
if (SynchMode == 0) // TimeStrech on
timeStretchWrite();
else
_WriteSamples(sndTempBuffer, SndOutPacketSize);
m_dsp_progress -= SndOutPacketSize;
}
m_dsp_progress -= SndOutPacketSize;
}
// copy any leftovers to the front of the dsp buffer.
if( m_dsp_progress > 0 )
{
memcpy( sndTempBuffer16, &sndTempBuffer16[ei],
sizeof(sndTempBuffer16[0]) * m_dsp_progress
);
}
}
// copy any leftovers to the front of the dsp buffer.
if (m_dsp_progress > 0) {
memcpy(sndTempBuffer16, &sndTempBuffer16[ei],
sizeof(sndTempBuffer16[0]) * m_dsp_progress);
}
}
#endif
else
{
if( SynchMode == 0 ) // TimeStrech on
timeStretchWrite();
else
_WriteSamples(sndTempBuffer, SndOutPacketSize);
}
else {
if (SynchMode == 0) // TimeStrech on
timeStretchWrite();
else
_WriteSamples(sndTempBuffer, SndOutPacketSize);
}
}
s32 SndBuffer::Test()
{
if( mods[OutputModule] == NULL )
return -1;
if (mods[OutputModule] == NULL)
return -1;
return mods[OutputModule]->Test();
return mods[OutputModule]->Test();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -29,152 +29,161 @@
#include <SDL_audio.h>
typedef StereoOut16 StereoOut_SDL;
namespace {
/* Since spu2 only ever outputs stereo, we don't worry about emitting surround sound
namespace
{
/* Since spu2 only ever outputs stereo, we don't worry about emitting surround sound
* even though SDL2 supports it */
const Uint8 channels = 2;
/* SDL2 supports s32 audio */
/* Samples should vary from [512,8192] according to SDL spec. Take note this is the desired
const Uint8 channels = 2;
/* SDL2 supports s32 audio */
/* Samples should vary from [512,8192] according to SDL spec. Take note this is the desired
* sample count and SDL may provide otherwise. Pulseaudio will cut this value in half if
* PA_STREAM_ADJUST_LATENCY is set in the backened, for example. */
const Uint16 desiredSamples = 2048;
const Uint16 format = AUDIO_S16SYS;
const Uint16 desiredSamples = 2048;
const Uint16 format = AUDIO_S16SYS;
Uint16 samples = desiredSamples;
Uint16 samples = desiredSamples;
std::unique_ptr<StereoOut_SDL[]> buffer;
std::unique_ptr<StereoOut_SDL[]> buffer;
void callback_fillBuffer(void *userdata, Uint8 *stream, int len) {
Uint16 sdl_samples = samples;
void callback_fillBuffer(void *userdata, Uint8 *stream, int len)
{
Uint16 sdl_samples = samples;
#if SDL_MAJOR_VERSION >= 2
memset(stream, 0, len);
// As of SDL 2.0.4 the buffer is too small to contains all samples
// len is 2048, samples is 1024 and sizeof(StereoOut_SDL) is 4
sdl_samples = len / sizeof(StereoOut_SDL);
memset(stream, 0, len);
// As of SDL 2.0.4 the buffer is too small to contains all samples
// len is 2048, samples is 1024 and sizeof(StereoOut_SDL) is 4
sdl_samples = len / sizeof(StereoOut_SDL);
#endif
// Length should always be samples in bytes.
assert(len / sizeof(StereoOut_SDL) == sdl_samples);
// Length should always be samples in bytes.
assert(len / sizeof(StereoOut_SDL) == sdl_samples);
for(Uint16 i = 0; i < sdl_samples; i += SndOutPacketSize)
SndBuffer::ReadSamples(&buffer[i]);
SDL_MixAudio(stream, (Uint8*) buffer.get() , len, SDL_MIX_MAXVOLUME);
}
for (Uint16 i = 0; i < sdl_samples; i += SndOutPacketSize)
SndBuffer::ReadSamples(&buffer[i]);
SDL_MixAudio(stream, (Uint8 *)buffer.get(), len, SDL_MIX_MAXVOLUME);
}
}
struct SDLAudioMod : public SndOutModule {
static SDLAudioMod mod;
std::string m_api;
struct SDLAudioMod : public SndOutModule
{
static SDLAudioMod mod;
std::string m_api;
s32 Init() {
ReadSettings();
s32 Init()
{
ReadSettings();
#if SDL_MAJOR_VERSION >= 2
std::cerr << "Request SDL audio driver: " << m_api.c_str() << std::endl;
std::cerr << "Request SDL audio driver: " << m_api.c_str() << std::endl;
#endif
/* SDL backends will mangle the AudioSpec and change the sample count. If we reopen
/* SDL backends will mangle the AudioSpec and change the sample count. If we reopen
* the audio backend, we need to make sure we keep our desired samples in the spec */
spec.samples = desiredSamples;
spec.samples = desiredSamples;
// Mandatory otherwise, init will be redone in SDL_OpenAudio
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
std::cerr << "SPU2-X: SDL INIT audio error: " << SDL_GetError() << std::endl;
return -1;
}
// Mandatory otherwise, init will be redone in SDL_OpenAudio
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
std::cerr << "SPU2-X: SDL INIT audio error: " << SDL_GetError() << std::endl;
return -1;
}
#if SDL_MAJOR_VERSION >= 2
if (m_api.compare("pulseaudio")) {
// Close the audio, but keep the subsystem open
SDL_AudioQuit();
// Reopen the audio
if (SDL_AudioInit(m_api.c_str()) < 0) {
std::cerr << "SPU2-X: SDL audio init error: " << SDL_GetError() << std::endl;
return -1;
}
}
if (m_api.compare("pulseaudio")) {
// Close the audio, but keep the subsystem open
SDL_AudioQuit();
// Reopen the audio
if (SDL_AudioInit(m_api.c_str()) < 0) {
std::cerr << "SPU2-X: SDL audio init error: " << SDL_GetError() << std::endl;
return -1;
}
}
#endif
if (SDL_OpenAudio(&spec, NULL) < 0) {
std::cerr << "SPU2-X: SDL audio error: " << SDL_GetError() << std::endl;
return -1;
}
if (SDL_OpenAudio(&spec, NULL) < 0) {
std::cerr << "SPU2-X: SDL audio error: " << SDL_GetError() << std::endl;
return -1;
}
#if SDL_MAJOR_VERSION >= 2
std::cerr << "Opened SDL audio driver: " << SDL_GetCurrentAudioDriver() << std::endl;
std::cerr << "Opened SDL audio driver: " << SDL_GetCurrentAudioDriver() << std::endl;
#endif
/* This is so ugly. It is hilariously ugly. I didn't use a vector to save reallocs. */
if(samples != spec.samples || buffer == NULL)
buffer = std::unique_ptr<StereoOut_SDL[]>(new StereoOut_SDL[spec.samples]);
if(samples != spec.samples) {
fprintf(stderr, "SPU2-X: SDL failed to get desired samples (%d) got %d samples instead\n", samples, spec.samples);
/* This is so ugly. It is hilariously ugly. I didn't use a vector to save reallocs. */
if (samples != spec.samples || buffer == NULL)
buffer = std::unique_ptr<StereoOut_SDL[]>(new StereoOut_SDL[spec.samples]);
if (samples != spec.samples) {
fprintf(stderr, "SPU2-X: SDL failed to get desired samples (%d) got %d samples instead\n", samples, spec.samples);
// Samples must always be a multiple of packet size.
assert(spec.samples % SndOutPacketSize == 0);
samples = spec.samples;
}
SDL_PauseAudio(0);
return 0;
}
// Samples must always be a multiple of packet size.
assert(spec.samples % SndOutPacketSize == 0);
samples = spec.samples;
}
SDL_PauseAudio(0);
return 0;
}
const wchar_t* GetIdent() const { return L"SDLAudio"; }
const wchar_t* GetLongName() const { return L"SDL Audio"; }
const wchar_t *GetIdent() const { return L"SDLAudio"; }
const wchar_t *GetLongName() const { return L"SDL Audio"; }
void Close() {
// Related to SDL_Init(SDL_INIT_AUDIO)
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
void Close()
{
// Related to SDL_Init(SDL_INIT_AUDIO)
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
~SDLAudioMod() { Close(); }
~SDLAudioMod() { Close(); }
s32 Test() const { return 0; }
int GetEmptySampleCount() { return 0; }
s32 Test() const { return 0; }
int GetEmptySampleCount() { return 0; }
void Configure(uptr parent) {}
void Configure(uptr parent) {}
void ReadSettings() {
wxString api(L"EMPTYEMPTYEMPTY");
CfgReadStr(L"SDL", L"HostApi", api, L"pulseaudio");
SetApiSettings(api);
}
void ReadSettings()
{
wxString api(L"EMPTYEMPTYEMPTY");
CfgReadStr(L"SDL", L"HostApi", api, L"pulseaudio");
SetApiSettings(api);
}
void WriteSettings() const {
CfgWriteStr(L"SDL", L"HostApi", wxString(m_api.c_str(), wxConvUTF8));
};
void WriteSettings() const
{
CfgWriteStr(L"SDL", L"HostApi", wxString(m_api.c_str(), wxConvUTF8));
};
void SetApiSettings(wxString api) {
void SetApiSettings(wxString api)
{
#if SDL_MAJOR_VERSION >= 2
// Validate the api name
bool valid = false;
std::string api_name = std::string(api.utf8_str());
for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
valid |= (api_name.compare(SDL_GetAudioDriver(i)) == 0);
}
if (valid) {
m_api = api.utf8_str();
} else {
std::cerr << "SDL audio driver configuration is invalid!" << std::endl
<< "It will be replaced by pulseaudio!" << std::endl;
m_api = "pulseaudio";
}
// Validate the api name
bool valid = false;
std::string api_name = std::string(api.utf8_str());
for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
valid |= (api_name.compare(SDL_GetAudioDriver(i)) == 0);
}
if (valid) {
m_api = api.utf8_str();
} else {
std::cerr << "SDL audio driver configuration is invalid!" << std::endl
<< "It will be replaced by pulseaudio!" << std::endl;
m_api = "pulseaudio";
}
#endif
}
}
private:
SDL_AudioSpec spec;
private:
SDL_AudioSpec spec;
SDLAudioMod() : m_api("pulseaudio"),
spec({SampleRate, format, channels, 0,
desiredSamples, 0, 0, &callback_fillBuffer, nullptr})
{
// Number of samples must be a multiple of packet size.
assert(samples % SndOutPacketSize == 0);
}
SDLAudioMod()
: m_api("pulseaudio")
, spec({SampleRate, format, channels, 0,
desiredSamples, 0, 0, &callback_fillBuffer, nullptr})
{
// Number of samples must be a multiple of packet size.
assert(samples % SndOutPacketSize == 0);
}
};
SDLAudioMod SDLAudioMod::mod;
SndOutModule * const SDLOut = &SDLAudioMod::mod;
SndOutModule *const SDLOut = &SDLAudioMod::mod;

View File

@ -20,73 +20,78 @@
#include "PS2E-spu2.h"
#ifdef _MSC_VER
# include "Windows.h"
#include "Windows.h"
#endif
FILE* s2rfile;
FILE *s2rfile;
void s2r_write16(s16 data)
{
fwrite(&data,2,1,s2rfile);
fwrite(&data, 2, 1, s2rfile);
}
void s2r_write32(u32 data)
{
fwrite(&data,4,1,s2rfile);
fwrite(&data, 4, 1, s2rfile);
}
static void EMITC(u32 i, u32 a)
{
s2r_write32(((i&0x7u)<<29u)|(a&0x1FFFFFFFu));
s2r_write32(((i & 0x7u) << 29u) | (a & 0x1FFFFFFFu));
}
int s2r_open(u32 ticks, char *filename)
{
s2rfile=fopen(filename,"wb");
if(s2rfile)
s2r_write32(ticks);
return s2rfile?0:-1;
s2rfile = fopen(filename, "wb");
if (s2rfile)
s2r_write32(ticks);
return s2rfile ? 0 : -1;
}
void s2r_readreg(u32 ticks,u32 addr)
void s2r_readreg(u32 ticks, u32 addr)
{
if(!s2rfile) return;
s2r_write32(ticks);
EMITC(0,addr);
if (!s2rfile)
return;
s2r_write32(ticks);
EMITC(0, addr);
}
void s2r_writereg(u32 ticks,u32 addr,s16 value)
void s2r_writereg(u32 ticks, u32 addr, s16 value)
{
if(!s2rfile) return;
s2r_write32(ticks);
EMITC(1,addr);
s2r_write16(value);
if (!s2rfile)
return;
s2r_write32(ticks);
EMITC(1, addr);
s2r_write16(value);
}
void s2r_writedma4(u32 ticks,u16*data,u32 len)
void s2r_writedma4(u32 ticks, u16 *data, u32 len)
{
u32 i;
if(!s2rfile) return;
s2r_write32(ticks);
EMITC(2,len);
for(i=0;i<len;i++,data++)
s2r_write16(*data);
u32 i;
if (!s2rfile)
return;
s2r_write32(ticks);
EMITC(2, len);
for (i = 0; i < len; i++, data++)
s2r_write16(*data);
}
void s2r_writedma7(u32 ticks,u16*data,u32 len)
void s2r_writedma7(u32 ticks, u16 *data, u32 len)
{
u32 i;
if(!s2rfile) return;
s2r_write32(ticks);
EMITC(3,len);
for(i=0;i<len;i++,data++)
s2r_write16(*data);
u32 i;
if (!s2rfile)
return;
s2r_write32(ticks);
EMITC(3, len);
for (i = 0; i < len; i++, data++)
s2r_write16(*data);
}
void s2r_close()
{
if(!s2rfile) return;
fclose(s2rfile);
if (!s2rfile)
return;
fclose(s2rfile);
}
///////////////////////////////////////////////////////////////
@ -94,13 +99,13 @@ void s2r_close()
///////////////////////////////////////////////////////////////
// replay code
bool replay_mode=false;
bool replay_mode = false;
u16 dmabuffer[0xFFFFF];
const u32 IOP_CLK = 768*48000;
const u32 IOPCiclesPerMS = 768*48;
u32 CurrentIOPCycle=0;
const u32 IOP_CLK = 768 * 48000;
const u32 IOPCiclesPerMS = 768 * 48;
u32 CurrentIOPCycle = 0;
u64 HighResFreq;
u64 HighResPrev;
@ -110,31 +115,31 @@ bool Running = false;
#ifdef _MSC_VER
int conprintf(const char* fmt, ...)
int conprintf(const char *fmt, ...)
{
#ifdef _WIN32
char s[1024];
va_list list;
char s[1024];
va_list list;
va_start(list, fmt);
vsprintf(s,fmt, list);
va_end(list);
va_start(list, fmt);
vsprintf(s, fmt, list);
va_end(list);
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
if(handle == INVALID_HANDLE_VALUE)
return 0;
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
if (handle == INVALID_HANDLE_VALUE)
return 0;
DWORD written = 0;
WriteConsoleA(handle, s, strlen(s), &written, 0);
FlushFileBuffers(handle);
DWORD written = 0;
WriteConsoleA(handle, s, strlen(s), &written, 0);
FlushFileBuffers(handle);
return written;
return written;
#else
va_list list;
va_start(list, fmt);
int ret = vsprintf(stderr,fmt,list);
va_end(list);
return ret;
va_list list;
va_start(list, fmt);
int ret = vsprintf(stderr, fmt, list);
va_end(list);
return ret;
#endif
}
@ -145,190 +150,188 @@ void dummy1()
void dummy4()
{
#ifndef ENABLE_NEW_IOPDMA_SPU2
SPU2interruptDMA4();
SPU2interruptDMA4();
#endif
}
void dummy7()
{
#ifndef ENABLE_NEW_IOPDMA_SPU2
SPU2interruptDMA7();
SPU2interruptDMA7();
#endif
}
u64 HighResFrequency()
{
u64 freq;
u64 freq;
#ifdef _WIN32
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
#else
// TODO
// TODO
#endif
return freq;
return freq;
}
u64 HighResCounter()
{
u64 time;
u64 time;
#ifdef _WIN32
QueryPerformanceCounter((LARGE_INTEGER*)&time);
QueryPerformanceCounter((LARGE_INTEGER *)&time);
#else
// TODO
// TODO
#endif
return time;
return time;
}
void InitWaitSync() // not extremely accurate but enough.
void InitWaitSync() // not extremely accurate but enough.
{
HighResFreq = HighResFrequency();
HighResPrev = HighResCounter();
HighResScale = (double)HighResFreq / (double)IOP_CLK;
HighResFreq = HighResFrequency();
HighResPrev = HighResCounter();
HighResScale = (double)HighResFreq / (double)IOP_CLK;
}
u32 WaitSync( u32 TargetCycle )
u32 WaitSync(u32 TargetCycle)
{
u32 WaitCycles = (TargetCycle - CurrentIOPCycle);
u32 WaitTime = WaitCycles / IOPCiclesPerMS;
if(WaitTime > 10)
WaitTime = 10;
if(WaitTime == 0)
WaitTime = 1;
SleepEx(WaitTime, TRUE);
u32 WaitCycles = (TargetCycle - CurrentIOPCycle);
u32 WaitTime = WaitCycles / IOPCiclesPerMS;
if (WaitTime > 10)
WaitTime = 10;
if (WaitTime == 0)
WaitTime = 1;
SleepEx(WaitTime, TRUE);
// Refresh current time after sleeping
u64 Current = HighResCounter();
u32 delta = (u32)floor((Current-HighResPrev) / HighResScale + 0.5); // We lose some precision here, cycles might drift away over long periods of time ;P
// Refresh current time after sleeping
u64 Current = HighResCounter();
u32 delta = (u32)floor((Current - HighResPrev) / HighResScale + 0.5); // We lose some precision here, cycles might drift away over long periods of time ;P
// Calculate time delta
CurrentIOPCycle += delta;
HighResPrev += (u64)floor(delta * HighResScale + 0.5); // Trying to compensate drifting mentioned above, not necessarily useful.
// Calculate time delta
CurrentIOPCycle += delta;
HighResPrev += (u64)floor(delta * HighResScale + 0.5); // Trying to compensate drifting mentioned above, not necessarily useful.
return delta;
return delta;
}
#ifdef _WIN32
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
{
Running = false;
return TRUE;
Running = false;
return TRUE;
}
#endif
#include "Windows/Dialogs.h"
EXPORT_C_(void) s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow)
EXPORT_C_(void)
s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow)
{
#ifndef ENABLE_NEW_IOPDMA_SPU2
int events=0;
int events = 0;
Running = true;
Running = true;
#ifdef _WIN32
AllocConsole();
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
conprintf("Playing %s file on %x...",filename,hwnd);
AllocConsole();
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
if (IsWindows8OrGreater())
{
for (int n = 0; mods[n] != nullptr; ++n)
{
if (mods[n] == XAudio2_27_Out)
{
mods[n] = XAudio2Out;
break;
}
}
}
conprintf("Playing %s file on %x...", filename, hwnd);
if (IsWindows8OrGreater()) {
for (int n = 0; mods[n] != nullptr; ++n) {
if (mods[n] == XAudio2_27_Out) {
mods[n] = XAudio2Out;
break;
}
}
}
#endif
// load file
FILE *file=fopen(filename,"rb");
// load file
FILE *file = fopen(filename, "rb");
if(!file)
{
conprintf("Could not open the replay file.");
return;
}
// if successful, init the plugin
if (!file) {
conprintf("Could not open the replay file.");
return;
}
// if successful, init the plugin
#define TryRead(dest,size,count,file) if(fread(dest,size,count,file)<count) { conprintf("Error reading from file."); goto Finish; /* Need to exit the while() loop and maybe also the switch */ }
#define TryRead(dest, size, count, file) \
if (fread(dest, size, count, file) < count) { \
conprintf("Error reading from file."); \
goto Finish; /* Need to exit the while() loop and maybe also the switch */ \
}
TryRead(&CurrentIOPCycle,4,1,file);
replay_mode=true;
TryRead(&CurrentIOPCycle, 4, 1, file);
InitWaitSync(); // Initialize the WaitSync stuff
replay_mode = true;
SPU2init();
SPU2irqCallback(dummy1,dummy4,dummy7);
SPU2setClockPtr(&CurrentIOPCycle);
SPU2open(&hwnd);
InitWaitSync(); // Initialize the WaitSync stuff
CurrentIOPCycle=0;
SPU2init();
SPU2irqCallback(dummy1, dummy4, dummy7);
SPU2setClockPtr(&CurrentIOPCycle);
SPU2open(&hwnd);
SPU2async(0);
CurrentIOPCycle = 0;
while(!feof(file) && Running)
{
u32 ccycle=0;
u32 evid=0;
u32 sval=0;
u32 tval=0;
SPU2async(0);
TryRead(&ccycle,4,1,file);
TryRead(&sval,4,1,file);
while (!feof(file) && Running) {
u32 ccycle = 0;
u32 evid = 0;
u32 sval = 0;
u32 tval = 0;
evid=sval>>29;
sval&=0x1FFFFFFF;
TryRead(&ccycle, 4, 1, file);
TryRead(&sval, 4, 1, file);
u32 TargetCycle = ccycle * 768;
evid = sval >> 29;
sval &= 0x1FFFFFFF;
while(TargetCycle > CurrentIOPCycle)
{
u32 delta = WaitSync(TargetCycle);
SPU2async(delta);
}
switch(evid)
{
case 0:
SPU2read(sval);
break;
case 1:
TryRead(&tval,2,1,file);
SPU2write(sval,tval);
break;
case 2:
TryRead(dmabuffer,sval,2,file);
SPU2writeDMA4Mem(dmabuffer,sval);
break;
case 3:
TryRead(dmabuffer,sval,2,file);
SPU2writeDMA7Mem(dmabuffer,sval);
break;
default:
// not implemented
return;
break;
}
events++;
}
u32 TargetCycle = ccycle * 768;
while (TargetCycle > CurrentIOPCycle) {
u32 delta = WaitSync(TargetCycle);
SPU2async(delta);
}
switch (evid) {
case 0:
SPU2read(sval);
break;
case 1:
TryRead(&tval, 2, 1, file);
SPU2write(sval, tval);
break;
case 2:
TryRead(dmabuffer, sval, 2, file);
SPU2writeDMA4Mem(dmabuffer, sval);
break;
case 3:
TryRead(dmabuffer, sval, 2, file);
SPU2writeDMA7Mem(dmabuffer, sval);
break;
default:
// not implemented
return;
break;
}
events++;
}
Finish:
//shutdown
SPU2close();
SPU2shutdown();
fclose(file);
//shutdown
SPU2close();
SPU2shutdown();
fclose(file);
conprintf("Finished playing %s file (%d cycles, %d events).",filename,CurrentIOPCycle,events);
conprintf("Finished playing %s file (%d cycles, %d events).", filename, CurrentIOPCycle, events);
#ifdef _WIN32
FreeConsole();
FreeConsole();
#endif
replay_mode=false;
replay_mode = false;
#endif
}
#endif

View File

@ -22,10 +22,10 @@
// s2r dumping
int s2r_open(u32 ticks, char *filename);
void s2r_readreg(u32 ticks,u32 addr);
void s2r_writereg(u32 ticks,u32 addr,s16 value);
void s2r_writedma4(u32 ticks,u16*data,u32 len);
void s2r_writedma7(u32 ticks,u16*data,u32 len);
void s2r_readreg(u32 ticks, u32 addr);
void s2r_writereg(u32 ticks, u32 addr, s16 value);
void s2r_writedma4(u32 ticks, u16 *data, u32 len);
void s2r_writedma7(u32 ticks, u16 *data, u32 len);
void s2r_close();
extern bool replay_mode;

View File

@ -23,7 +23,7 @@
//Uncomment the next line to use the old time stretcher
//#define SPU2X_USE_OLD_STRETCHER
static soundtouch::SoundTouch* pSoundTouch = NULL;
static soundtouch::SoundTouch *pSoundTouch = NULL;
// data prediction amount, used to "commit" data that hasn't
// finished timestretch processing.
@ -36,9 +36,9 @@ float SndBuffer::lastEmergencyAdj;
float SndBuffer::cTempo = 1;
float SndBuffer::eTempo = 1;
void SndBuffer::PredictDataWrite( int samples )
void SndBuffer::PredictDataWrite(int samples)
{
m_predictData += samples;
m_predictData += samples;
}
// Calculate the buffer status percentage.
@ -48,17 +48,17 @@ void SndBuffer::PredictDataWrite( int samples )
// -1.0 = buffer underflow!
float SndBuffer::GetStatusPct()
{
// Get the buffer status of the output driver too, so that we can
// obtain a more accurate overall buffer status.
// Get the buffer status of the output driver too, so that we can
// obtain a more accurate overall buffer status.
int drvempty = mods[OutputModule]->GetEmptySampleCount(); // / 2;
int drvempty = mods[OutputModule]->GetEmptySampleCount(); // / 2;
//ConLog( "Data %d >>> driver: %d predict: %d\n", m_data, drvempty, m_predictData );
//ConLog( "Data %d >>> driver: %d predict: %d\n", m_data, drvempty, m_predictData );
int data = _GetApproximateDataInBuffer();
float result = (float)( data + m_predictData - drvempty) - (m_size/16);
result /= (m_size/16);
return result;
int data = _GetApproximateDataInBuffer();
float result = (float)(data + m_predictData - drvempty) - (m_size / 16);
result /= (m_size / 16);
return result;
}
@ -87,7 +87,7 @@ float SndBuffer::GetStatusPct()
// These params were tested to show good respond and stability, on all audio systems (dsound, wav, port audio, xaudio2),
// even at extreme small latency of 50ms which can handle 50%-100% variations without audible glitches.
int targetIPS=750;
int targetIPS = 750;
//Dynamic tuning changes the values of the base algorithm parameters (derived from targetIPS) to adapt, in real time, to
// different number of invocations/sec (mostly affects number of iterations to average).
@ -99,277 +99,277 @@ int targetIPS=750;
//#define NEWSTRETCHER_USE_DYNAMIC_TUNING
//Additional performance note: since MAX_STRETCH_AVERAGE_LEN = 128 (or any power of 2), the '%' below
//Additional performance note: since MAX_STRETCH_AVERAGE_LEN = 128 (or any power of 2), the '%' below
//could be replaced with a faster '&'. The compiler is highly likely to do it since all the values are unsigned.
#define AVERAGING_BUFFER_SIZE 256U
unsigned int AVERAGING_WINDOW = 50.0 * targetIPS/750;
unsigned int AVERAGING_WINDOW = 50.0 * targetIPS / 750;
#define STRETCHER_RESET_THRESHOLD 5
int gRequestStretcherReset = STRETCHER_RESET_THRESHOLD;
//Adds a value to the running average buffer, and return the new running average.
float addToAvg(float val){
static float avg_fullness[AVERAGING_BUFFER_SIZE];
static unsigned int nextAvgPos = 0;
static unsigned int available = 0; // Make sure we're not averaging AVERAGING_WINDOW items if we inserted less.
if (gRequestStretcherReset >= STRETCHER_RESET_THRESHOLD)
available = 0;
float addToAvg(float val)
{
static float avg_fullness[AVERAGING_BUFFER_SIZE];
static unsigned int nextAvgPos = 0;
static unsigned int available = 0; // Make sure we're not averaging AVERAGING_WINDOW items if we inserted less.
if (gRequestStretcherReset >= STRETCHER_RESET_THRESHOLD)
available = 0;
if (available < AVERAGING_BUFFER_SIZE)
available++;
if (available < AVERAGING_BUFFER_SIZE)
available++;
avg_fullness[nextAvgPos] = val;
nextAvgPos = (nextAvgPos + 1U) % AVERAGING_BUFFER_SIZE;
unsigned int actualWindow = std::min(available, AVERAGING_WINDOW);
unsigned int first = (nextAvgPos - actualWindow + AVERAGING_BUFFER_SIZE)
% AVERAGING_BUFFER_SIZE;
avg_fullness[nextAvgPos] = val;
nextAvgPos = (nextAvgPos + 1U) % AVERAGING_BUFFER_SIZE;
// Possible optimization: if we know that actualWindow hasn't changed since
// last invocation, we could calculate the running average in O(1) instead of O(N)
// by keeping a running sum between invocations, and then
// do "runningSum = runningSum + val - avg_fullness[(first-1)%...]" instead of the following loop.
// Few gotchas: val overwrites first-1, handling actualWindow changes, etc.
// However, this isn't hot code, so unless proven otherwise, we can live with unoptimized code.
float sum = 0;
for(unsigned int i = first; i < first + actualWindow; i++) {
sum += avg_fullness[i % AVERAGING_BUFFER_SIZE];
}
sum = sum / actualWindow;
unsigned int actualWindow = std::min(available, AVERAGING_WINDOW);
unsigned int first = (nextAvgPos - actualWindow + AVERAGING_BUFFER_SIZE) % AVERAGING_BUFFER_SIZE;
return sum ? sum : 1; // 1 because that's the 100% perfect speed value
// Possible optimization: if we know that actualWindow hasn't changed since
// last invocation, we could calculate the running average in O(1) instead of O(N)
// by keeping a running sum between invocations, and then
// do "runningSum = runningSum + val - avg_fullness[(first-1)%...]" instead of the following loop.
// Few gotchas: val overwrites first-1, handling actualWindow changes, etc.
// However, this isn't hot code, so unless proven otherwise, we can live with unoptimized code.
float sum = 0;
for (unsigned int i = first; i < first + actualWindow; i++) {
sum += avg_fullness[i % AVERAGING_BUFFER_SIZE];
}
sum = sum / actualWindow;
return sum ? sum : 1; // 1 because that's the 100% perfect speed value
}
template <class T>
bool IsInRange(const T& val, const T& min, const T& max)
bool IsInRange(const T &val, const T &min, const T &max)
{
return ( min <= val && val <= max );
return (min <= val && val <= max);
}
//actual stretch algorithm implementation
void SndBuffer::UpdateTempoChangeSoundTouch2()
{
long targetSamplesReservoir=48*SndOutLatencyMS;//48000*SndOutLatencyMS/1000
//base aim at buffer filled %
float baseTargetFullness=(double)targetSamplesReservoir;///(double)m_size;//0.05;
long targetSamplesReservoir = 48 * SndOutLatencyMS; //48000*SndOutLatencyMS/1000
//base aim at buffer filled %
float baseTargetFullness = (double)targetSamplesReservoir; ///(double)m_size;//0.05;
//state vars
static bool inside_hysteresis;//=false;
static int hys_ok_count;//=0;
static float dynamicTargetFullness;//=baseTargetFullness;
if (gRequestStretcherReset >= STRETCHER_RESET_THRESHOLD) {
ConLog("______> stretch: Reset.\n");
inside_hysteresis=false;
hys_ok_count=0;
dynamicTargetFullness=baseTargetFullness;
}
//state vars
static bool inside_hysteresis; //=false;
static int hys_ok_count; //=0;
static float dynamicTargetFullness; //=baseTargetFullness;
if (gRequestStretcherReset >= STRETCHER_RESET_THRESHOLD) {
ConLog("______> stretch: Reset.\n");
inside_hysteresis = false;
hys_ok_count = 0;
dynamicTargetFullness = baseTargetFullness;
}
int data = _GetApproximateDataInBuffer();
float bufferFullness=(float)data;///(float)m_size;
int data = _GetApproximateDataInBuffer();
float bufferFullness = (float)data; ///(float)m_size;
#ifdef NEWSTRETCHER_USE_DYNAMIC_TUNING
{//test current iterations/sec every 0.5s, and change algo params accordingly if different than previous IPS more than 30%
static long iters=0;
static wxDateTime last=wxDateTime::UNow();
wxDateTime unow=wxDateTime::UNow();
wxTimeSpan delta = unow.Subtract(last);
if( delta.GetMilliseconds()>500 ){
int pot_targetIPS=1000.0/delta.GetMilliseconds().ToDouble()*iters;
if(!IsInRange(pot_targetIPS, int((float)targetIPS/1.3f), int((float)targetIPS*1.3f)) ){
if(MsgOverruns()) ConLog("Stretcher: setting iters/sec from %d to %d\n", targetIPS, pot_targetIPS);
targetIPS=pot_targetIPS;
AVERAGING_WINDOW=GetClamped((int)(50.0f *(float)targetIPS/750.0f), 3, (int)AVERAGING_BUFFER_SIZE);
}
last=unow;
iters=0;
}
iters++;
}
{ //test current iterations/sec every 0.5s, and change algo params accordingly if different than previous IPS more than 30%
static long iters = 0;
static wxDateTime last = wxDateTime::UNow();
wxDateTime unow = wxDateTime::UNow();
wxTimeSpan delta = unow.Subtract(last);
if (delta.GetMilliseconds() > 500) {
int pot_targetIPS = 1000.0 / delta.GetMilliseconds().ToDouble() * iters;
if (!IsInRange(pot_targetIPS, int((float)targetIPS / 1.3f), int((float)targetIPS * 1.3f))) {
if (MsgOverruns())
ConLog("Stretcher: setting iters/sec from %d to %d\n", targetIPS, pot_targetIPS);
targetIPS = pot_targetIPS;
AVERAGING_WINDOW = GetClamped((int)(50.0f * (float)targetIPS / 750.0f), 3, (int)AVERAGING_BUFFER_SIZE);
}
last = unow;
iters = 0;
}
iters++;
}
#endif
//Algorithm params: (threshold params (hysteresis), etc)
const float hys_ok_factor = 1.04f;
const float hys_bad_factor = 1.2f;
int hys_min_ok_count = GetClamped((int)(50.0 *(float)targetIPS/750.0), 2, 100); //consecutive iterations within hys_ok before going to 1:1 mode
int compensationDivider = GetClamped((int)(100.0 *(float)targetIPS/750), 15, 150);
//Algorithm params: (threshold params (hysteresis), etc)
const float hys_ok_factor = 1.04f;
const float hys_bad_factor = 1.2f;
int hys_min_ok_count = GetClamped((int)(50.0 * (float)targetIPS / 750.0), 2, 100); //consecutive iterations within hys_ok before going to 1:1 mode
int compensationDivider = GetClamped((int)(100.0 * (float)targetIPS / 750), 15, 150);
float tempoAdjust=bufferFullness/dynamicTargetFullness;
float avgerage = addToAvg(tempoAdjust);
tempoAdjust = avgerage;
float tempoAdjust = bufferFullness / dynamicTargetFullness;
float avgerage = addToAvg(tempoAdjust);
tempoAdjust = avgerage;
// Dampen the adjustment to avoid overshoots (this means the average will compensate to the other side).
// This is different than simply bigger averaging window since bigger window also has bigger "momentum",
// so it's slower to slow down when it gets close to the equilibrium state and can therefore resonate.
// The dampening (sqrt was chosen for no very good reason) manages to mostly prevent that.
tempoAdjust = sqrt(tempoAdjust);
// Dampen the adjustment to avoid overshoots (this means the average will compensate to the other side).
// This is different than simply bigger averaging window since bigger window also has bigger "momentum",
// so it's slower to slow down when it gets close to the equilibrium state and can therefore resonate.
// The dampening (sqrt was chosen for no very good reason) manages to mostly prevent that.
tempoAdjust = sqrt(tempoAdjust);
tempoAdjust = GetClamped( tempoAdjust, 0.05f, 10.0f);
if (tempoAdjust < 1)
baseTargetFullness /= sqrt(tempoAdjust); // slightly increase latency when running slow.
dynamicTargetFullness += (baseTargetFullness/tempoAdjust - dynamicTargetFullness)/(double)compensationDivider;
if( IsInRange(tempoAdjust, 0.9f, 1.1f) && IsInRange( dynamicTargetFullness, baseTargetFullness*0.9f, baseTargetFullness*1.1f) )
dynamicTargetFullness=baseTargetFullness;
tempoAdjust = GetClamped(tempoAdjust, 0.05f, 10.0f);
if( !inside_hysteresis )
{
if( IsInRange( tempoAdjust, 1.0f/hys_ok_factor, hys_ok_factor ) )
hys_ok_count++;
else
hys_ok_count=0;
if (tempoAdjust < 1)
baseTargetFullness /= sqrt(tempoAdjust); // slightly increase latency when running slow.
if( hys_ok_count >= hys_min_ok_count ){
inside_hysteresis=true;
if(MsgOverruns()) ConLog("======> stretch: None (1:1)\n");
}
dynamicTargetFullness += (baseTargetFullness / tempoAdjust - dynamicTargetFullness) / (double)compensationDivider;
if (IsInRange(tempoAdjust, 0.9f, 1.1f) && IsInRange(dynamicTargetFullness, baseTargetFullness * 0.9f, baseTargetFullness * 1.1f))
dynamicTargetFullness = baseTargetFullness;
}
else if( !IsInRange( tempoAdjust, 1.0f/hys_bad_factor, hys_bad_factor ) ){
if(MsgOverruns()) ConLog("~~~~~~> stretch: Dynamic\n");
inside_hysteresis=false;
hys_ok_count=0;
}
if (!inside_hysteresis) {
if (IsInRange(tempoAdjust, 1.0f / hys_ok_factor, hys_ok_factor))
hys_ok_count++;
else
hys_ok_count = 0;
if(inside_hysteresis)
tempoAdjust=1.0;
if (hys_ok_count >= hys_min_ok_count) {
inside_hysteresis = true;
if (MsgOverruns())
ConLog("======> stretch: None (1:1)\n");
}
if(MsgOverruns()){
static int iters=0;
static wxDateTime last=wxDateTime::UNow();
wxDateTime unow=wxDateTime::UNow();
wxTimeSpan delta = unow.Subtract(last);
} else if (!IsInRange(tempoAdjust, 1.0f / hys_bad_factor, hys_bad_factor)) {
if (MsgOverruns())
ConLog("~~~~~~> stretch: Dynamic\n");
inside_hysteresis = false;
hys_ok_count = 0;
}
if(delta.GetMilliseconds()>1000){//report buffers state and tempo adjust every second
ConLog("buffers: %4d ms (%3.0f%%), tempo: %f, comp: %2.3f, iters: %d, (N-IPS:%d -> avg:%d, minokc:%d, div:%d) reset:%d\n",
(int)(data/48), (double)(100.0*bufferFullness/baseTargetFullness), (double)tempoAdjust, (double)(dynamicTargetFullness/baseTargetFullness), iters, (int)targetIPS
, AVERAGING_WINDOW, hys_min_ok_count, compensationDivider, gRequestStretcherReset
);
last=unow;
iters=0;
}
iters++;
}
if (inside_hysteresis)
tempoAdjust = 1.0;
pSoundTouch->setTempo(tempoAdjust);
if (gRequestStretcherReset >= STRETCHER_RESET_THRESHOLD)
gRequestStretcherReset = 0;
if (MsgOverruns()) {
static int iters = 0;
static wxDateTime last = wxDateTime::UNow();
wxDateTime unow = wxDateTime::UNow();
wxTimeSpan delta = unow.Subtract(last);
return;
if (delta.GetMilliseconds() > 1000) { //report buffers state and tempo adjust every second
ConLog("buffers: %4d ms (%3.0f%%), tempo: %f, comp: %2.3f, iters: %d, (N-IPS:%d -> avg:%d, minokc:%d, div:%d) reset:%d\n",
(int)(data / 48), (double)(100.0 * bufferFullness / baseTargetFullness), (double)tempoAdjust, (double)(dynamicTargetFullness / baseTargetFullness), iters, (int)targetIPS, AVERAGING_WINDOW, hys_min_ok_count, compensationDivider, gRequestStretcherReset);
last = unow;
iters = 0;
}
iters++;
}
pSoundTouch->setTempo(tempoAdjust);
if (gRequestStretcherReset >= STRETCHER_RESET_THRESHOLD)
gRequestStretcherReset = 0;
return;
}
void SndBuffer::UpdateTempoChangeSoundTouch()
{
float statusPct = GetStatusPct();
float pctChange = statusPct - lastPct;
float statusPct = GetStatusPct();
float pctChange = statusPct - lastPct;
float tempoChange;
float emergencyAdj = 0;
float newcee = cTempo; // workspace var. for cTempo
float tempoChange;
float emergencyAdj = 0;
float newcee = cTempo; // workspace var. for cTempo
// IMPORTANT!
// If you plan to tweak these values, make sure you're using a release build
// OUTSIDE THE DEBUGGER to test it! The Visual Studio debugger can really cause
// erratic behavior in the audio buffers, and makes the timestretcher seem a
// lot more inconsistent than it really is.
// IMPORTANT!
// If you plan to tweak these values, make sure you're using a release build
// OUTSIDE THE DEBUGGER to test it! The Visual Studio debugger can really cause
// erratic behavior in the audio buffers, and makes the timestretcher seem a
// lot more inconsistent than it really is.
// We have two factors.
// * Distance from nominal buffer status (50% full)
// * The change from previous update to this update.
// We have two factors.
// * Distance from nominal buffer status (50% full)
// * The change from previous update to this update.
// Prediction based on the buffer change:
// (linear seems to work better here)
// Prediction based on the buffer change:
// (linear seems to work better here)
tempoChange = pctChange * 0.75f;
tempoChange = pctChange * 0.75f;
if( statusPct * tempoChange < 0.0f )
{
// only apply tempo change if it is in synch with the buffer status.
// In other words, if the buffer is high (over 0%), and is decreasing,
// ignore it. It'll just muck things up.
if (statusPct * tempoChange < 0.0f) {
// only apply tempo change if it is in synch with the buffer status.
// In other words, if the buffer is high (over 0%), and is decreasing,
// ignore it. It'll just muck things up.
tempoChange = 0;
}
tempoChange = 0;
}
// Sudden spikes in framerate can cause the nominal buffer status
// to go critical, in which case we have to enact an emergency
// stretch. The following cubic formulas do that. Values near
// the extremeites give much larger results than those near 0.
// And the value is added only this time, and does not accumulate.
// (otherwise a large value like this would cause problems down the road)
// Sudden spikes in framerate can cause the nominal buffer status
// to go critical, in which case we have to enact an emergency
// stretch. The following cubic formulas do that. Values near
// the extremeites give much larger results than those near 0.
// And the value is added only this time, and does not accumulate.
// (otherwise a large value like this would cause problems down the road)
// Constants:
// Weight - weights the statusPct's "emergency" consideration.
// higher values here will make the buffer perform more drastic
// compensations at the outer edges of the buffer (at -75 or +75%
// or beyond, for example).
// Constants:
// Weight - weights the statusPct's "emergency" consideration.
// higher values here will make the buffer perform more drastic
// compensations at the outer edges of the buffer (at -75 or +75%
// or beyond, for example).
// Range - scales the adjustment to the given range (more or less).
// The actual range is dependent on the weight used, so if you increase
// Weight you'll usually want to decrease Range somewhat to compensate.
// Range - scales the adjustment to the given range (more or less).
// The actual range is dependent on the weight used, so if you increase
// Weight you'll usually want to decrease Range somewhat to compensate.
// Prediction based on the buffer fill status:
// Prediction based on the buffer fill status:
const float statusWeight = 2.99f;
const float statusRange = 0.068f;
const float statusWeight = 2.99f;
const float statusRange = 0.068f;
// "non-emergency" deadzone: In this area stretching will be strongly discouraged.
// Note: due tot he nature of timestretch latency, it's always a wee bit harder to
// cope with low fps (underruns) than it is high fps (overruns). So to help out a
// little, the low-end portions of this check are less forgiving than the high-sides.
// "non-emergency" deadzone: In this area stretching will be strongly discouraged.
// Note: due tot he nature of timestretch latency, it's always a wee bit harder to
// cope with low fps (underruns) than it is high fps (overruns). So to help out a
// little, the low-end portions of this check are less forgiving than the high-sides.
if( cTempo < 0.965f || cTempo > 1.060f ||
pctChange < -0.38f || pctChange > 0.54f ||
statusPct < -0.42f || statusPct > 0.70f ||
eTempo < 0.89f || eTempo > 1.19f )
{
//printf("Emergency stretch: cTempo = %f eTempo = %f pctChange = %f statusPct = %f\n",cTempo,eTempo,pctChange,statusPct);
emergencyAdj = ( pow( statusPct*statusWeight, 3.0f ) * statusRange);
}
if (cTempo < 0.965f || cTempo > 1.060f ||
pctChange < -0.38f || pctChange > 0.54f ||
statusPct < -0.42f || statusPct > 0.70f ||
eTempo < 0.89f || eTempo > 1.19f) {
//printf("Emergency stretch: cTempo = %f eTempo = %f pctChange = %f statusPct = %f\n",cTempo,eTempo,pctChange,statusPct);
emergencyAdj = (pow(statusPct * statusWeight, 3.0f) * statusRange);
}
// Smooth things out by factoring our previous adjustment into this one.
// It helps make the system 'feel' a little smarter by giving it at least
// one packet worth of history to help work off of:
// Smooth things out by factoring our previous adjustment into this one.
// It helps make the system 'feel' a little smarter by giving it at least
// one packet worth of history to help work off of:
emergencyAdj = (emergencyAdj * 0.75f) + (lastEmergencyAdj * 0.25f );
emergencyAdj = (emergencyAdj * 0.75f) + (lastEmergencyAdj * 0.25f);
lastEmergencyAdj = emergencyAdj;
lastPct = statusPct;
lastEmergencyAdj = emergencyAdj;
lastPct = statusPct;
// Accumulate a fraction of the tempo change into the tempo itself.
// This helps the system run "smarter" to games that run consistently
// fast or slow by altering the base tempo to something closer to the
// game's active speed. In tests most games normalize within 2 seconds
// at 100ms latency, which is pretty good (larger buffers normalize even
// quicker).
// Accumulate a fraction of the tempo change into the tempo itself.
// This helps the system run "smarter" to games that run consistently
// fast or slow by altering the base tempo to something closer to the
// game's active speed. In tests most games normalize within 2 seconds
// at 100ms latency, which is pretty good (larger buffers normalize even
// quicker).
newcee += newcee * (tempoChange+emergencyAdj) * 0.03f;
newcee += newcee * (tempoChange + emergencyAdj) * 0.03f;
// Apply tempoChange as a scale of cTempo. That way the effect is proportional
// to the current tempo. (otherwise tempos rate of change at the extremes would
// be too drastic)
// Apply tempoChange as a scale of cTempo. That way the effect is proportional
// to the current tempo. (otherwise tempos rate of change at the extremes would
// be too drastic)
float newTempo = newcee + ( emergencyAdj * cTempo );
float newTempo = newcee + (emergencyAdj * cTempo);
// ... and as a final optimization, only stretch if the new tempo is outside
// a nominal threshold. Keep this threshold check small, because it could
// cause some serious side effects otherwise. (enlarging the cTempo check above
// is usually better/safer)
if( newTempo < 0.970f || newTempo > 1.045f )
{
cTempo = (float)newcee;
// ... and as a final optimization, only stretch if the new tempo is outside
// a nominal threshold. Keep this threshold check small, because it could
// cause some serious side effects otherwise. (enlarging the cTempo check above
// is usually better/safer)
if (newTempo < 0.970f || newTempo > 1.045f) {
cTempo = (float)newcee;
if( newTempo < 0.10f ) newTempo = 0.10f;
else if( newTempo > 10.0f ) newTempo = 10.0f;
if (newTempo < 0.10f)
newTempo = 0.10f;
else if (newTempo > 10.0f)
newTempo = 10.0f;
if( cTempo < 0.15f ) cTempo = 0.15f;
else if( cTempo > 7.5f ) cTempo = 7.5f;
if (cTempo < 0.15f)
cTempo = 0.15f;
else if (cTempo > 7.5f)
cTempo = 7.5f;
pSoundTouch->setTempo( eTempo = (float)newTempo );
pSoundTouch->setTempo(eTempo = (float)newTempo);
/*ConLog("* SPU2-X: [Nominal %d%%] [Emergency: %d%%] (baseTempo: %d%% ) (newTempo: %d%%) (buffer: %d%%)\n",
/*ConLog("* SPU2-X: [Nominal %d%%] [Emergency: %d%%] (baseTempo: %d%% ) (newTempo: %d%%) (buffer: %d%%)\n",
//(relation < 0.0) ? "Normalize" : "",
(int)(tempoChange * 100.0 * 0.03),
(int)(emergencyAdj * 100.0),
@ -377,168 +377,164 @@ void SndBuffer::UpdateTempoChangeSoundTouch()
(int)(newTempo * 100.0),
(int)(statusPct * 100.0)
);*/
}
else
{
// Nominal operation -- turn off stretching.
// note: eTempo 'slides' toward 1.0 for smoother audio and better
// protection against spikes.
if( cTempo != 1.0f )
{
cTempo = 1.0f;
eTempo = ( 1.0f + eTempo ) * 0.5f;
pSoundTouch->setTempo( eTempo );
}
else
{
if( eTempo != cTempo )
pSoundTouch->setTempo( eTempo=cTempo );
}
}
} else {
// Nominal operation -- turn off stretching.
// note: eTempo 'slides' toward 1.0 for smoother audio and better
// protection against spikes.
if (cTempo != 1.0f) {
cTempo = 1.0f;
eTempo = (1.0f + eTempo) * 0.5f;
pSoundTouch->setTempo(eTempo);
} else {
if (eTempo != cTempo)
pSoundTouch->setTempo(eTempo = cTempo);
}
}
}
extern uint TickInterval;
void SndBuffer::UpdateTempoChangeAsyncMixing()
{
float statusPct = GetStatusPct();
float statusPct = GetStatusPct();
lastPct = statusPct;
if( statusPct < -0.1f )
{
TickInterval -= 4;
if( statusPct < -0.3f ) TickInterval = 64;
if( TickInterval < 64 ) TickInterval = 64;
//printf("-- %d, %f\n",TickInterval,statusPct);
}
else if( statusPct > 0.2f )
{
TickInterval += 1;
if( TickInterval >= 7000 ) TickInterval = 7000;
//printf("++ %d, %f\n",TickInterval,statusPct);
}
else TickInterval = 768;
lastPct = statusPct;
if (statusPct < -0.1f) {
TickInterval -= 4;
if (statusPct < -0.3f)
TickInterval = 64;
if (TickInterval < 64)
TickInterval = 64;
//printf("-- %d, %f\n",TickInterval,statusPct);
} else if (statusPct > 0.2f) {
TickInterval += 1;
if (TickInterval >= 7000)
TickInterval = 7000;
//printf("++ %d, %f\n",TickInterval,statusPct);
} else
TickInterval = 768;
}
void SndBuffer::timeStretchUnderrun()
{
gRequestStretcherReset++;
// timeStretcher failed it's job. We need to slow down the audio some.
gRequestStretcherReset++;
// timeStretcher failed it's job. We need to slow down the audio some.
cTempo -= (cTempo * 0.12f);
eTempo -= (eTempo * 0.30f);
if( eTempo < 0.1f ) eTempo = 0.1f;
// pSoundTouch->setTempo( eTempo );
//pSoundTouch->setTempoChange(-30); // temporary (until stretcher is called) slow down
cTempo -= (cTempo * 0.12f);
eTempo -= (eTempo * 0.30f);
if (eTempo < 0.1f)
eTempo = 0.1f;
// pSoundTouch->setTempo( eTempo );
//pSoundTouch->setTempoChange(-30); // temporary (until stretcher is called) slow down
}
s32 SndBuffer::timeStretchOverrun()
{
// If we overran it means the timestretcher failed. We need to speed
// up audio playback.
cTempo += cTempo * 0.12f;
eTempo += eTempo * 0.40f;
if( eTempo > 7.5f ) eTempo = 7.5f;
//pSoundTouch->setTempo( eTempo );
//pSoundTouch->setTempoChange(30);// temporary (until stretcher is called) speed up
// If we overran it means the timestretcher failed. We need to speed
// up audio playback.
cTempo += cTempo * 0.12f;
eTempo += eTempo * 0.40f;
if (eTempo > 7.5f)
eTempo = 7.5f;
//pSoundTouch->setTempo( eTempo );
//pSoundTouch->setTempoChange(30);// temporary (until stretcher is called) speed up
// Throw out just a little bit (two packets worth) to help
// give the TS some room to work:
gRequestStretcherReset++;
return SndOutPacketSize*2;
// Throw out just a little bit (two packets worth) to help
// give the TS some room to work:
gRequestStretcherReset++;
return SndOutPacketSize * 2;
}
static void CvtPacketToFloat( StereoOut32* srcdest )
static void CvtPacketToFloat(StereoOut32 *srcdest)
{
StereoOutFloat* dest = (StereoOutFloat*)srcdest;
const StereoOut32* src = (StereoOut32*)srcdest;
for( uint i=0; i<SndOutPacketSize; ++i, ++dest, ++src )
*dest = (StereoOutFloat)*src;
StereoOutFloat *dest = (StereoOutFloat *)srcdest;
const StereoOut32 *src = (StereoOut32 *)srcdest;
for (uint i = 0; i < SndOutPacketSize; ++i, ++dest, ++src)
*dest = (StereoOutFloat)*src;
}
// Parameter note: Size should always be a multiple of 128, thanks!
static void CvtPacketToInt( StereoOut32* srcdest, uint size )
static void CvtPacketToInt(StereoOut32 *srcdest, uint size)
{
//pxAssume( (size & 127) == 0 );
//pxAssume( (size & 127) == 0 );
const StereoOutFloat* src = (StereoOutFloat*)srcdest;
StereoOut32* dest = srcdest;
const StereoOutFloat *src = (StereoOutFloat *)srcdest;
StereoOut32 *dest = srcdest;
for( uint i=0; i<size; ++i, ++dest, ++src )
*dest = (StereoOut32)*src;
for (uint i = 0; i < size; ++i, ++dest, ++src)
*dest = (StereoOut32)*src;
}
void SndBuffer::timeStretchWrite()
{
// data prediction helps keep the tempo adjustments more accurate.
// The timestretcher returns packets in belated "clump" form.
// Meaning that most of the time we'll get nothing back, and then
// suddenly we'll get several chunks back at once. Thus we use
// data prediction to make the timestretcher more responsive.
// data prediction helps keep the tempo adjustments more accurate.
// The timestretcher returns packets in belated "clump" form.
// Meaning that most of the time we'll get nothing back, and then
// suddenly we'll get several chunks back at once. Thus we use
// data prediction to make the timestretcher more responsive.
PredictDataWrite( (int)( SndOutPacketSize / eTempo ) );
CvtPacketToFloat( sndTempBuffer );
PredictDataWrite((int)(SndOutPacketSize / eTempo));
CvtPacketToFloat(sndTempBuffer);
pSoundTouch->putSamples( (float*)sndTempBuffer, SndOutPacketSize );
pSoundTouch->putSamples((float *)sndTempBuffer, SndOutPacketSize);
int tempProgress;
while( tempProgress = pSoundTouch->receiveSamples( (float*)sndTempBuffer, SndOutPacketSize),
tempProgress != 0 )
{
// Hint: It's assumed that pSoundTouch will return chunks of 128 bytes (it always does as
// long as the SSE optimizations are enabled), which means we can do our own SSE opts here.
int tempProgress;
while (tempProgress = pSoundTouch->receiveSamples((float *)sndTempBuffer, SndOutPacketSize),
tempProgress != 0) {
// Hint: It's assumed that pSoundTouch will return chunks of 128 bytes (it always does as
// long as the SSE optimizations are enabled), which means we can do our own SSE opts here.
CvtPacketToInt( sndTempBuffer, tempProgress );
_WriteSamples( sndTempBuffer, tempProgress );
}
CvtPacketToInt(sndTempBuffer, tempProgress);
_WriteSamples(sndTempBuffer, tempProgress);
}
#ifdef SPU2X_USE_OLD_STRETCHER
UpdateTempoChangeSoundTouch();
UpdateTempoChangeSoundTouch();
#else
UpdateTempoChangeSoundTouch2();
UpdateTempoChangeSoundTouch2();
#endif
}
void SndBuffer::soundtouchInit()
{
pSoundTouch = new soundtouch::SoundTouch();
pSoundTouch->setSampleRate(SampleRate);
pSoundTouch->setChannels(2);
pSoundTouch = new soundtouch::SoundTouch();
pSoundTouch->setSampleRate(SampleRate);
pSoundTouch->setChannels(2);
pSoundTouch->setSetting( SETTING_USE_QUICKSEEK, 0 );
pSoundTouch->setSetting( SETTING_USE_AA_FILTER, 0 );
pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, 0);
pSoundTouch->setSetting(SETTING_USE_AA_FILTER, 0);
SoundtouchCfg::ApplySettings( *pSoundTouch );
SoundtouchCfg::ApplySettings(*pSoundTouch);
pSoundTouch->setTempo(1);
pSoundTouch->setTempo(1);
// some timestretch management vars:
// some timestretch management vars:
cTempo = 1.0;
eTempo = 1.0;
lastPct = 0;
lastEmergencyAdj = 0;
cTempo = 1.0;
eTempo = 1.0;
lastPct = 0;
lastEmergencyAdj = 0;
m_predictData = 0;
m_predictData = 0;
}
// reset timestretch management vars, and delay updates a bit:
void SndBuffer::soundtouchClearContents()
{
if( pSoundTouch == NULL ) return;
if (pSoundTouch == NULL)
return;
pSoundTouch->clear();
pSoundTouch->setTempo(1);
pSoundTouch->clear();
pSoundTouch->setTempo(1);
cTempo = 1.0;
eTempo = 1.0;
lastPct = 0;
lastEmergencyAdj = 0;
cTempo = 1.0;
eTempo = 1.0;
lastPct = 0;
lastEmergencyAdj = 0;
m_predictData = 0;
m_predictData = 0;
}
void SndBuffer::soundtouchCleanup()
{
safe_delete( pSoundTouch );
safe_delete(pSoundTouch);
}

View File

@ -16,7 +16,7 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
// Note the file is mostly a copy paste of the WavFile.h from SoundTouch library. It was
// Note the file is mostly a copy paste of the WavFile.h from SoundTouch library. It was
// shrunken to support only output 16 bits wav files
#include <stdio.h>
@ -32,7 +32,7 @@ using namespace std;
static const char riffStr[] = "RIFF";
static const char waveStr[] = "WAVE";
static const char fmtStr[] = "fmt ";
static const char fmtStr[] = "fmt ";
static const char dataStr[] = "data";
//////////////////////////////////////////////////////////////////////////////
@ -44,8 +44,7 @@ WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int chann
{
bytesWritten = 0;
fptr = fopen(fileName, "wb");
if (fptr == NULL)
{
if (fptr == NULL) {
string msg = "Error : Unable to open file \"";
msg += fileName;
msg += "\" for writing.";
@ -60,8 +59,7 @@ WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int chann
WavOutFile::~WavOutFile()
{
if (fptr)
{
if (fptr) {
finishHeader();
fclose(fptr);
}
@ -122,8 +120,7 @@ void WavOutFile::writeHeader()
// write the supplemented header in the beginning of the file
fseek(fptr, 0, SEEK_SET);
res = fwrite(&header, sizeof(header), 1, fptr);
if (res != 1)
{
if (res != 1) {
throw runtime_error("Error while writing to a wav file.");
}
@ -139,12 +136,12 @@ void WavOutFile::write(const short *buffer, int numElems)
// 16bit format & 16 bit samples
assert(header.format.bits_per_sample == 16);
if (numElems < 1) return; // nothing to do
if (numElems < 1)
return; // nothing to do
res = fwrite(buffer, 2, numElems, fptr);
if (res != numElems)
{
if (res != numElems) {
throw runtime_error("Error while writing to a wav file.");
}
bytesWritten += 2 * numElems;

View File

@ -16,7 +16,7 @@
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
// Note the file is mostly a copy paste of the WavFile.h from SoundTouch library. It was
// Note the file is mostly a copy paste of the WavFile.h from SoundTouch library. It was
// shrunken to support only output 16 bits wav files
#ifndef WAVFILE_H
@ -26,44 +26,44 @@
#ifndef uint
typedef unsigned int uint;
#endif
#endif
/// WAV audio file 'riff' section header
typedef struct
typedef struct
{
char riff_char[4];
int package_len;
int package_len;
char wave[4];
} WavRiff;
/// WAV audio file 'format' section header
typedef struct
typedef struct
{
char fmt[4];
int format_len;
char fmt[4];
int format_len;
short fixed;
short channel_number;
int sample_rate;
int byte_rate;
int sample_rate;
int byte_rate;
short byte_per_sample;
short bits_per_sample;
} WavFormat;
/// WAV audio file 'data' section header
typedef struct
typedef struct
{
char data_field[4];
uint data_len;
char data_field[4];
uint data_len;
} WavData;
/// WAV audio file header
typedef struct
typedef struct
{
WavRiff riff;
WavRiff riff;
WavFormat format;
WavData data;
WavData data;
} WavHeader;
@ -91,12 +91,12 @@ private:
void writeHeader();
public:
/// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
/// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
/// if file creation fails.
WavOutFile(const char *fileName, ///< Filename
int sampleRate, ///< Sample rate (e.g. 44100 etc)
int bits, ///< Bits per sample (8 or 16 bits)
int channels ///< Number of channels (1=mono, 2=stereo)
WavOutFile(const char *fileName, ///< Filename
int sampleRate, ///< Sample rate (e.g. 44100 etc)
int bits, ///< Bits per sample (8 or 16 bits)
int channels ///< Number of channels (1=mono, 2=stereo)
);
/// Destructor: Finalizes & closes the WAV file.
@ -104,10 +104,9 @@ public:
/// Write data to WAV file. Throws a 'runtime_error' exception if writing to
/// file fails.
void write(const short *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file.
void write(const short *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file.
);
};
#endif

View File

@ -22,81 +22,77 @@
#include "soundtouch/source/SoundStretch/WavFile.h"
#endif
static WavOutFile* _new_WavOutFile( const char* destfile )
static WavOutFile *_new_WavOutFile(const char *destfile)
{
return new WavOutFile( destfile, 48000, 16, 2 );
return new WavOutFile(destfile, 48000, 16, 2);
}
namespace WaveDump
{
static WavOutFile* m_CoreWav[2][CoreSrc_Count] = { NULL };
static WavOutFile *m_CoreWav[2][CoreSrc_Count] = {NULL};
static const char* m_tbl_CoreOutputTypeNames[CoreSrc_Count] =
{
"Input",
"DryVoiceMix",
"WetVoiceMix",
"PreReverb",
"PostReverb",
"External"
};
static const char *m_tbl_CoreOutputTypeNames[CoreSrc_Count] =
{
"Input",
"DryVoiceMix",
"WetVoiceMix",
"PreReverb",
"PostReverb",
"External"};
void Open()
{
if( !IsDevBuild ) return;
if( !WaveLog() ) return;
void Open()
{
if (!IsDevBuild)
return;
if (!WaveLog())
return;
char wavfilename[256];
char wavfilename[256];
for( uint cidx=0; cidx<2; cidx++ )
{
for( int srcidx=0; srcidx<CoreSrc_Count; srcidx++ )
{
safe_delete( m_CoreWav[cidx][srcidx] );
for (uint cidx = 0; cidx < 2; cidx++) {
for (int srcidx = 0; srcidx < CoreSrc_Count; srcidx++) {
safe_delete(m_CoreWav[cidx][srcidx]);
#ifdef __POSIX__
sprintf( wavfilename, "logs/spu2x-Core%d-%s.wav",
cidx, m_tbl_CoreOutputTypeNames[ srcidx ] );
sprintf(wavfilename, "logs/spu2x-Core%d-%s.wav",
cidx, m_tbl_CoreOutputTypeNames[srcidx]);
#else
sprintf( wavfilename, "logs\\spu2x-Core%d-%s.wav",
cidx, m_tbl_CoreOutputTypeNames[ srcidx ] );
sprintf(wavfilename, "logs\\spu2x-Core%d-%s.wav",
cidx, m_tbl_CoreOutputTypeNames[srcidx]);
#endif
try
{
m_CoreWav[cidx][srcidx] = _new_WavOutFile( wavfilename );
}
catch( std::runtime_error& ex )
{
printf( "SPU2-X > %s.\n\tWave Log for this core source disabled.", ex.what() );
m_CoreWav[cidx][srcidx] = NULL;
}
}
}
}
try {
m_CoreWav[cidx][srcidx] = _new_WavOutFile(wavfilename);
} catch (std::runtime_error &ex) {
printf("SPU2-X > %s.\n\tWave Log for this core source disabled.", ex.what());
m_CoreWav[cidx][srcidx] = NULL;
}
}
}
}
void Close()
{
if( !IsDevBuild ) return;
for( uint cidx=0; cidx<2; cidx++ )
{
for( int srcidx=0; srcidx<CoreSrc_Count; srcidx++ )
{
safe_delete( m_CoreWav[cidx][srcidx] );
}
}
}
void Close()
{
if (!IsDevBuild)
return;
for (uint cidx = 0; cidx < 2; cidx++) {
for (int srcidx = 0; srcidx < CoreSrc_Count; srcidx++) {
safe_delete(m_CoreWav[cidx][srcidx]);
}
}
}
void WriteCore( uint coreidx, CoreSourceType src, const StereoOut16& sample )
{
if( !IsDevBuild ) return;
if( m_CoreWav[coreidx][src] != NULL )
m_CoreWav[coreidx][src]->write( (s16*)&sample, 2 );
}
void WriteCore(uint coreidx, CoreSourceType src, const StereoOut16 &sample)
{
if (!IsDevBuild)
return;
if (m_CoreWav[coreidx][src] != NULL)
m_CoreWav[coreidx][src]->write((s16 *)&sample, 2);
}
void WriteCore( uint coreidx, CoreSourceType src, s16 left, s16 right )
{
WriteCore( coreidx, src, StereoOut16( left, right ) );
}
void WriteCore(uint coreidx, CoreSourceType src, s16 left, s16 right)
{
WriteCore(coreidx, src, StereoOut16(left, right));
}
}
#include "Utilities/Threading.h"
@ -105,37 +101,35 @@ using namespace Threading;
bool WavRecordEnabled = false;
static WavOutFile* m_wavrecord = NULL;
static Mutex WavRecordMutex;
static WavOutFile *m_wavrecord = NULL;
static Mutex WavRecordMutex;
void RecordStart()
{
WavRecordEnabled = false;
WavRecordEnabled = false;
try
{
ScopedLock lock( WavRecordMutex );
safe_delete( m_wavrecord );
m_wavrecord = new WavOutFile( "recording.wav", 48000, 16, 2 );
WavRecordEnabled = true;
}
catch( std::runtime_error& )
{
m_wavrecord = NULL; // not needed, but what the heck. :)
SysMessage("SPU2-X couldn't open file for recording: %s.\nRecording to wavfile disabled.", "recording.wav");
}
try {
ScopedLock lock(WavRecordMutex);
safe_delete(m_wavrecord);
m_wavrecord = new WavOutFile("recording.wav", 48000, 16, 2);
WavRecordEnabled = true;
} catch (std::runtime_error &) {
m_wavrecord = NULL; // not needed, but what the heck. :)
SysMessage("SPU2-X couldn't open file for recording: %s.\nRecording to wavfile disabled.", "recording.wav");
}
}
void RecordStop()
{
WavRecordEnabled = false;
ScopedLock lock( WavRecordMutex );
safe_delete( m_wavrecord );
WavRecordEnabled = false;
ScopedLock lock(WavRecordMutex);
safe_delete(m_wavrecord);
}
void RecordWrite( const StereoOut16& sample )
void RecordWrite(const StereoOut16 &sample)
{
ScopedLock lock( WavRecordMutex );
if( m_wavrecord == NULL ) return;
m_wavrecord->write( (s16*)&sample, 2 );
ScopedLock lock(WavRecordMutex);
if (m_wavrecord == NULL)
return;
m_wavrecord->write((s16 *)&sample, 2);
}

View File

@ -22,48 +22,45 @@
static LRESULT WINAPI AboutProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
{
wchar_t outstr[256];
if( IsDevBuild )
swprintf_s( outstr, L"Build %lld -- Compiled on " _T(__DATE__), SVN_REV );
else
swprintf_s( outstr, L"Release v%d.%d -- Compiled on " _T(__DATE__),
VersionInfo::Release, VersionInfo::Revision );
switch (uMsg) {
case WM_INITDIALOG: {
wchar_t outstr[256];
if (IsDevBuild)
swprintf_s(outstr, L"Build %lld -- Compiled on " _T(__DATE__), SVN_REV);
else
swprintf_s(outstr, L"Release v%d.%d -- Compiled on " _T(__DATE__),
VersionInfo::Release, VersionInfo::Revision);
SetWindowText( GetDlgItem(hDlg, IDC_LABEL_VERSION_INFO), outstr );
ShowWindow( hDlg, true );
}
return TRUE;
SetWindowText(GetDlgItem(hDlg, IDC_LABEL_VERSION_INFO), outstr);
ShowWindow(hDlg, true);
}
return TRUE;
case WM_COMMAND:
switch( LOWORD(wParam) )
{
case IDOK:
EndDialog(hDlg, TRUE );
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
EndDialog(hDlg, TRUE);
return TRUE;
case IDC_LINK_WEBSITE:
ShellExecute(hDlg, L"open", L"http://www.pcsx2.net/",
NULL, NULL, SW_SHOWNORMAL);
return TRUE;
case IDC_LINK_WEBSITE:
ShellExecute(hDlg, L"open", L"http://www.pcsx2.net/",
NULL, NULL, SW_SHOWNORMAL);
return TRUE;
case IDC_LINK_GOOGLECODE:
ShellExecute(hDlg, L"open", L"https://github.com/PCSX2/pcsx2",
NULL, NULL, SW_SHOWNORMAL);
return TRUE;
}
break;
case IDC_LINK_GOOGLECODE:
ShellExecute(hDlg, L"open", L"https://github.com/PCSX2/pcsx2",
NULL, NULL, SW_SHOWNORMAL);
return TRUE;
}
break;
default:
return FALSE;
}
return TRUE;
default:
return FALSE;
}
return TRUE;
}
void AboutBox()
{
DialogBox( hInstance, MAKEINTRESOURCE(IDD_ABOUT), GetActiveWindow(), (DLGPROC)AboutProc );
DialogBox(hInstance, MAKEINTRESOURCE(IDD_ABOUT), GetActiveWindow(), (DLGPROC)AboutProc);
}

View File

@ -24,38 +24,38 @@ extern uptr gsWindowHandle;
void SysMessage(const char *fmt, ...)
{
va_list list;
char tmp[512];
wchar_t wtmp[512];
va_list list;
char tmp[512];
wchar_t wtmp[512];
va_start(list,fmt);
vsprintf_s(tmp,fmt,list);
va_end(list);
swprintf_s(wtmp, L"%S", tmp);
MessageBox( (!!gsWindowHandle) ? (HWND)gsWindowHandle : GetActiveWindow(), wtmp,
L"SPU2-X System Message", MB_OK | MB_SETFOREGROUND);
va_start(list, fmt);
vsprintf_s(tmp, fmt, list);
va_end(list);
swprintf_s(wtmp, L"%S", tmp);
MessageBox((!!gsWindowHandle) ? (HWND)gsWindowHandle : GetActiveWindow(), wtmp,
L"SPU2-X System Message", MB_OK | MB_SETFOREGROUND);
}
void SysMessage(const wchar_t *fmt, ...)
{
va_list list;
va_start(list,fmt);
wxString wtmp;
wtmp.PrintfV( fmt, list );
va_end(list);
MessageBox( (!!gsWindowHandle) ? (HWND)gsWindowHandle : GetActiveWindow(), wtmp,
L"SPU2-X System Message", MB_OK | MB_SETFOREGROUND);
va_list list;
va_start(list, fmt);
wxString wtmp;
wtmp.PrintfV(fmt, list);
va_end(list);
MessageBox((!!gsWindowHandle) ? (HWND)gsWindowHandle : GetActiveWindow(), wtmp,
L"SPU2-X System Message", MB_OK | MB_SETFOREGROUND);
}
//////
#include "Utilities/Path.h"
static wxString CfgFile( L"inis/SPU2-X.ini" );
static wxString CfgFile(L"inis/SPU2-X.ini");
void CfgSetSettingsDir( const char* dir )
void CfgSetSettingsDir(const char *dir)
{
CfgFile = Path::Combine( (dir==NULL) ? wxString(L"inis") : wxString(dir, wxConvFile), L"SPU2-X.ini" );
CfgFile = Path::Combine((dir == NULL) ? wxString(L"inis") : wxString(dir, wxConvFile), L"SPU2-X.ini");
}
@ -74,24 +74,24 @@ void CfgSetSettingsDir( const char* dir )
\*_____________________________________________*/
void CfgWriteBool(const TCHAR* Section, const TCHAR* Name, bool Value)
void CfgWriteBool(const TCHAR *Section, const TCHAR *Name, bool Value)
{
const TCHAR *Data = Value ? L"TRUE" : L"FALSE";
WritePrivateProfileString( Section, Name, Data, CfgFile );
const TCHAR *Data = Value ? L"TRUE" : L"FALSE";
WritePrivateProfileString(Section, Name, Data, CfgFile);
}
void CfgWriteInt(const TCHAR* Section, const TCHAR* Name, int Value)
void CfgWriteInt(const TCHAR *Section, const TCHAR *Name, int Value)
{
TCHAR Data[32];
_itow( Value, Data, 10 );
WritePrivateProfileString(Section,Name,Data,CfgFile);
TCHAR Data[32];
_itow(Value, Data, 10);
WritePrivateProfileString(Section, Name, Data, CfgFile);
}
void CfgWriteFloat(const TCHAR* Section, const TCHAR* Name, float Value)
void CfgWriteFloat(const TCHAR *Section, const TCHAR *Name, float Value)
{
TCHAR Data[32];
_swprintf(Data, L"%f", Value);
WritePrivateProfileString(Section, Name, Data, CfgFile);
TCHAR Data[32];
_swprintf(Data, L"%f", Value);
WritePrivateProfileString(Section, Name, Data, CfgFile);
}
/*void CfgWriteStr(const TCHAR* Section, const TCHAR* Name, const TCHAR *Data)
@ -99,94 +99,99 @@ void CfgWriteFloat(const TCHAR* Section, const TCHAR* Name, float Value)
WritePrivateProfileString( Section, Name, Data, CfgFile );
}*/
void CfgWriteStr(const TCHAR* Section, const TCHAR* Name, const wxString& Data)
void CfgWriteStr(const TCHAR *Section, const TCHAR *Name, const wxString &Data)
{
WritePrivateProfileString( Section, Name, Data, CfgFile );
WritePrivateProfileString(Section, Name, Data, CfgFile);
}
/*****************************************************************************/
bool CfgReadBool(const TCHAR *Section,const TCHAR* Name, bool Default)
bool CfgReadBool(const TCHAR *Section, const TCHAR *Name, bool Default)
{
TCHAR Data[255] = {0};
TCHAR Data[255] = {0};
GetPrivateProfileString( Section, Name, L"", Data, 255, CfgFile );
Data[254]=0;
if(wcslen(Data)==0) {
CfgWriteBool(Section,Name,Default);
return Default;
}
GetPrivateProfileString(Section, Name, L"", Data, 255, CfgFile);
Data[254] = 0;
if (wcslen(Data) == 0) {
CfgWriteBool(Section, Name, Default);
return Default;
}
if(wcscmp(Data,L"1")==0) return true;
if(wcscmp(Data,L"Y")==0) return true;
if(wcscmp(Data,L"T")==0) return true;
if(wcscmp(Data,L"YES")==0) return true;
if(wcscmp(Data,L"TRUE")==0) return true;
return false;
if (wcscmp(Data, L"1") == 0)
return true;
if (wcscmp(Data, L"Y") == 0)
return true;
if (wcscmp(Data, L"T") == 0)
return true;
if (wcscmp(Data, L"YES") == 0)
return true;
if (wcscmp(Data, L"TRUE") == 0)
return true;
return false;
}
int CfgReadInt(const TCHAR* Section, const TCHAR* Name,int Default)
int CfgReadInt(const TCHAR *Section, const TCHAR *Name, int Default)
{
TCHAR Data[255]={0};
GetPrivateProfileString(Section,Name,L"",Data,255,CfgFile);
Data[254]=0;
TCHAR Data[255] = {0};
GetPrivateProfileString(Section, Name, L"", Data, 255, CfgFile);
Data[254] = 0;
if(wcslen(Data)==0) {
CfgWriteInt(Section,Name,Default);
return Default;
}
if (wcslen(Data) == 0) {
CfgWriteInt(Section, Name, Default);
return Default;
}
return _wtoi(Data);
return _wtoi(Data);
}
float CfgReadFloat(const TCHAR* Section, const TCHAR* Name, float Default)
float CfgReadFloat(const TCHAR *Section, const TCHAR *Name, float Default)
{
TCHAR Data[255] = { 0 };
GetPrivateProfileString(Section, Name, L"", Data, 255, CfgFile);
Data[254] = 0;
TCHAR Data[255] = {0};
GetPrivateProfileString(Section, Name, L"", Data, 255, CfgFile);
Data[254] = 0;
if (wcslen(Data) == 0) {
CfgWriteFloat(Section, Name, Default);
return Default;
}
if (wcslen(Data) == 0) {
CfgWriteFloat(Section, Name, Default);
return Default;
}
return (float)_wtof(Data);
return (float)_wtof(Data);
}
void CfgReadStr(const TCHAR* Section, const TCHAR* Name, TCHAR* Data, int DataSize, const TCHAR* Default)
void CfgReadStr(const TCHAR *Section, const TCHAR *Name, TCHAR *Data, int DataSize, const TCHAR *Default)
{
GetPrivateProfileString(Section,Name,L"",Data,DataSize,CfgFile);
GetPrivateProfileString(Section, Name, L"", Data, DataSize, CfgFile);
if(wcslen(Data)==0) {
swprintf_s( Data, DataSize, L"%s", Default );
CfgWriteStr( Section, Name, Data );
}
if (wcslen(Data) == 0) {
swprintf_s(Data, DataSize, L"%s", Default);
CfgWriteStr(Section, Name, Data);
}
}
void CfgReadStr(const TCHAR* Section, const TCHAR* Name, wxString& Data, const TCHAR* Default)
void CfgReadStr(const TCHAR *Section, const TCHAR *Name, wxString &Data, const TCHAR *Default)
{
wchar_t workspace[512];
GetPrivateProfileString(Section,Name,L"",workspace,ArraySize(workspace),CfgFile);
wchar_t workspace[512];
GetPrivateProfileString(Section, Name, L"", workspace, ArraySize(workspace), CfgFile);
Data = workspace;
Data = workspace;
if(Data.empty())
{
Data = Default;
CfgWriteStr( Section, Name, Default );
}
if (Data.empty()) {
Data = Default;
CfgWriteStr(Section, Name, Default);
}
}
// Tries to read the requested value.
// Returns FALSE if the value isn't found.
bool CfgFindName( const TCHAR *Section, const TCHAR* Name)
bool CfgFindName(const TCHAR *Section, const TCHAR *Name)
{
// Only load 24 characters. No need to load more.
TCHAR Data[24]={0};
GetPrivateProfileString(Section,Name,L"",Data,24,CfgFile);
Data[23]=0;
// Only load 24 characters. No need to load more.
TCHAR Data[24] = {0};
GetPrivateProfileString(Section, Name, L"", Data, 24, CfgFile);
Data[23] = 0;
if(wcslen(Data)==0) return false;
return true;
if (wcslen(Data) == 0)
return false;
return true;
}

View File

@ -40,9 +40,9 @@ int Interpolation = 4;
bool EffectsDisabled = false;
float FinalVolume; // Global
float FinalVolume; // Global
bool AdvancedVolumeControl;
float VolumeAdjustFLdb; // decibels settings, cos audiophiles love that
float VolumeAdjustFLdb; // decibels settings, cos audiophiles love that
float VolumeAdjustCdb;
float VolumeAdjustFRdb;
float VolumeAdjustBLdb;
@ -50,7 +50,7 @@ float VolumeAdjustBRdb;
float VolumeAdjustSLdb;
float VolumeAdjustSRdb;
float VolumeAdjustLFEdb;
float VolumeAdjustFL; // linear coefs calcualted from decibels,
float VolumeAdjustFL; // linear coefs calcualted from decibels,
float VolumeAdjustC;
float VolumeAdjustFR;
float VolumeAdjustBL;
@ -65,7 +65,7 @@ bool postprocess_filter_dealias = false;
// OUTPUT
int SndOutLatencyMS = 100;
int SynchMode = 0; // Time Stretch, Async or Disabled
int SynchMode = 0; // Time Stretch, Async or Disabled
u32 OutputModule = 0;
@ -74,7 +74,7 @@ CONFIG_XAUDIO2 Config_XAudio2;
// DSP
bool dspPluginEnabled = false;
int dspPluginModule = 0;
int dspPluginModule = 0;
wchar_t dspPlugin[256];
int numSpeakers = 0;
@ -85,344 +85,324 @@ int dplLevel = 0;
void ReadSettings()
{
Interpolation = CfgReadInt( L"MIXING",L"Interpolation", 4 );
Interpolation = CfgReadInt(L"MIXING", L"Interpolation", 4);
EffectsDisabled = CfgReadBool( L"MIXING", L"Disable_Effects", false );
postprocess_filter_dealias = CfgReadBool( L"MIXING", L"DealiasFilter", false );
FinalVolume = ((float)CfgReadInt( L"MIXING", L"FinalVolume", 100 )) / 100;
if ( FinalVolume > 1.0f) FinalVolume = 1.0f;
EffectsDisabled = CfgReadBool(L"MIXING", L"Disable_Effects", false);
postprocess_filter_dealias = CfgReadBool(L"MIXING", L"DealiasFilter", false);
FinalVolume = ((float)CfgReadInt(L"MIXING", L"FinalVolume", 100)) / 100;
if (FinalVolume > 1.0f)
FinalVolume = 1.0f;
AdvancedVolumeControl = CfgReadBool(L"MIXING", L"AdvancedVolumeControl", false);
VolumeAdjustCdb = CfgReadFloat(L"MIXING", L"VolumeAdjustC(dB)", 0);
VolumeAdjustFLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustFL(dB)", 0);
VolumeAdjustFRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustFR(dB)", 0);
VolumeAdjustBLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustBL(dB)", 0);
VolumeAdjustBRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustBR(dB)", 0);
VolumeAdjustSLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustSL(dB)", 0);
VolumeAdjustSRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustSR(dB)", 0);
VolumeAdjustLFEdb = CfgReadFloat(L"MIXING", L"VolumeAdjustLFE(dB)", 0);
delayCycles = CfgReadInt(L"DEBUG", L"DelayCycles", 4);
VolumeAdjustC = powf(10, VolumeAdjustCdb / 10);
VolumeAdjustFL = powf(10, VolumeAdjustFLdb / 10);
VolumeAdjustFR = powf(10, VolumeAdjustFRdb / 10);
VolumeAdjustBL = powf(10, VolumeAdjustBLdb / 10);
VolumeAdjustBR = powf(10, VolumeAdjustBRdb / 10);
VolumeAdjustSL = powf(10, VolumeAdjustSLdb / 10);
VolumeAdjustSR = powf(10, VolumeAdjustSRdb / 10);
VolumeAdjustLFE = powf(10, VolumeAdjustLFEdb / 10);
AdvancedVolumeControl = CfgReadBool(L"MIXING", L"AdvancedVolumeControl", false);
VolumeAdjustCdb = CfgReadFloat(L"MIXING", L"VolumeAdjustC(dB)", 0);
VolumeAdjustFLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustFL(dB)", 0);
VolumeAdjustFRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustFR(dB)", 0);
VolumeAdjustBLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustBL(dB)", 0);
VolumeAdjustBRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustBR(dB)", 0);
VolumeAdjustSLdb = CfgReadFloat(L"MIXING", L"VolumeAdjustSL(dB)", 0);
VolumeAdjustSRdb = CfgReadFloat(L"MIXING", L"VolumeAdjustSR(dB)", 0);
VolumeAdjustLFEdb = CfgReadFloat(L"MIXING", L"VolumeAdjustLFE(dB)", 0);
delayCycles = CfgReadInt(L"DEBUG", L"DelayCycles", 4);
VolumeAdjustC = powf(10, VolumeAdjustCdb / 10);
VolumeAdjustFL = powf(10, VolumeAdjustFLdb / 10);
VolumeAdjustFR = powf(10, VolumeAdjustFRdb / 10);
VolumeAdjustBL = powf(10, VolumeAdjustBLdb / 10);
VolumeAdjustBR = powf(10, VolumeAdjustBRdb / 10);
VolumeAdjustSL = powf(10, VolumeAdjustSLdb / 10);
VolumeAdjustSR = powf(10, VolumeAdjustSRdb / 10);
VolumeAdjustLFE = powf(10, VolumeAdjustLFEdb / 10);
SynchMode = CfgReadInt( L"OUTPUT", L"Synch_Mode", 0);
numSpeakers = CfgReadInt( L"OUTPUT", L"SpeakerConfiguration", 0);
dplLevel = CfgReadInt( L"OUTPUT", L"DplDecodingLevel", 0);
SndOutLatencyMS = CfgReadInt(L"OUTPUT",L"Latency", 100);
SynchMode = CfgReadInt(L"OUTPUT", L"Synch_Mode", 0);
numSpeakers = CfgReadInt(L"OUTPUT", L"SpeakerConfiguration", 0);
dplLevel = CfgReadInt(L"OUTPUT", L"DplDecodingLevel", 0);
SndOutLatencyMS = CfgReadInt(L"OUTPUT", L"Latency", 100);
if((SynchMode == 0) && (SndOutLatencyMS < LATENCY_MIN_TS)) // can't use low-latency with timestretcher atm
SndOutLatencyMS = LATENCY_MIN_TS;
else if(SndOutLatencyMS < LATENCY_MIN)
SndOutLatencyMS = LATENCY_MIN;
if ((SynchMode == 0) && (SndOutLatencyMS < LATENCY_MIN_TS)) // can't use low-latency with timestretcher atm
SndOutLatencyMS = LATENCY_MIN_TS;
else if (SndOutLatencyMS < LATENCY_MIN)
SndOutLatencyMS = LATENCY_MIN;
wchar_t omodid[128];
wchar_t omodid[128];
// portaudio occasionally has issues selecting the proper default audio device.
// let's use xaudio2 until this is sorted (rama)
// portaudio occasionally has issues selecting the proper default audio device.
// let's use xaudio2 until this is sorted (rama)
// CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, PortaudioOut->GetIdent());
if (IsWindows8OrGreater())
CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2Out->GetIdent());
else
CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2_27_Out->GetIdent());
// CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, PortaudioOut->GetIdent());
if (IsWindows8OrGreater())
CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2Out->GetIdent());
else
CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2_27_Out->GetIdent());
// find the driver index of this module:
OutputModule = FindOutputModuleById( omodid );
// find the driver index of this module:
OutputModule = FindOutputModuleById(omodid);
CfgReadStr( L"DSP PLUGIN",L"Filename",dspPlugin,255,L"");
dspPluginModule = CfgReadInt(L"DSP PLUGIN",L"ModuleNum",0);
dspPluginEnabled= CfgReadBool(L"DSP PLUGIN",L"Enabled",false);
CfgReadStr(L"DSP PLUGIN", L"Filename", dspPlugin, 255, L"");
dspPluginModule = CfgReadInt(L"DSP PLUGIN", L"ModuleNum", 0);
dspPluginEnabled = CfgReadBool(L"DSP PLUGIN", L"Enabled", false);
// Read DSOUNDOUT and WAVEOUT configs:
CfgReadStr( L"WAVEOUT", L"Device", Config_WaveOut.Device, L"default" );
Config_WaveOut.NumBuffers = CfgReadInt( L"WAVEOUT", L"Buffer_Count", 4 );
// Read DSOUNDOUT and WAVEOUT configs:
CfgReadStr(L"WAVEOUT", L"Device", Config_WaveOut.Device, L"default");
Config_WaveOut.NumBuffers = CfgReadInt(L"WAVEOUT", L"Buffer_Count", 4);
DSoundOut->ReadSettings();
PortaudioOut->ReadSettings();
DSoundOut->ReadSettings();
PortaudioOut->ReadSettings();
SoundtouchCfg::ReadSettings();
DebugConfig::ReadSettings();
SoundtouchCfg::ReadSettings();
DebugConfig::ReadSettings();
// Sanity Checks
// -------------
// Sanity Checks
// -------------
Clampify( SndOutLatencyMS, LATENCY_MIN, LATENCY_MAX );
Clampify(SndOutLatencyMS, LATENCY_MIN, LATENCY_MAX);
if( mods[OutputModule] == NULL )
{
// Unsupported or legacy module.
fwprintf( stderr, L"* SPU2-X: Unknown output module '%s' specified in configuration file.\n", omodid );
fprintf( stderr, "* SPU2-X: Defaulting to DirectSound (%S).\n", DSoundOut->GetIdent() );
OutputModule = FindOutputModuleById( DSoundOut->GetIdent() );
}
if (mods[OutputModule] == NULL) {
// Unsupported or legacy module.
fwprintf(stderr, L"* SPU2-X: Unknown output module '%s' specified in configuration file.\n", omodid);
fprintf(stderr, "* SPU2-X: Defaulting to DirectSound (%S).\n", DSoundOut->GetIdent());
OutputModule = FindOutputModuleById(DSoundOut->GetIdent());
}
}
/*****************************************************************************/
void WriteSettings()
{
CfgWriteInt(L"MIXING",L"Interpolation",Interpolation);
CfgWriteInt(L"MIXING", L"Interpolation", Interpolation);
CfgWriteBool(L"MIXING",L"Disable_Effects",EffectsDisabled);
CfgWriteBool(L"MIXING",L"DealiasFilter",postprocess_filter_dealias);
CfgWriteInt(L"MIXING",L"FinalVolume",(int)(FinalVolume * 100 + 0.5f));
CfgWriteBool(L"MIXING", L"Disable_Effects", EffectsDisabled);
CfgWriteBool(L"MIXING", L"DealiasFilter", postprocess_filter_dealias);
CfgWriteInt(L"MIXING", L"FinalVolume", (int)(FinalVolume * 100 + 0.5f));
CfgWriteBool(L"MIXING", L"AdvancedVolumeControl", AdvancedVolumeControl);
CfgWriteFloat(L"MIXING", L"VolumeAdjustC(dB)", VolumeAdjustCdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustFL(dB)", VolumeAdjustFLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustFR(dB)", VolumeAdjustFRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustBL(dB)", VolumeAdjustBLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustBR(dB)", VolumeAdjustBRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustSL(dB)", VolumeAdjustSLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustSR(dB)", VolumeAdjustSRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustLFE(dB)", VolumeAdjustLFEdb);
CfgWriteBool(L"MIXING", L"AdvancedVolumeControl", AdvancedVolumeControl);
CfgWriteFloat(L"MIXING", L"VolumeAdjustC(dB)", VolumeAdjustCdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustFL(dB)", VolumeAdjustFLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustFR(dB)", VolumeAdjustFRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustBL(dB)", VolumeAdjustBLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustBR(dB)", VolumeAdjustBRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustSL(dB)", VolumeAdjustSLdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustSR(dB)", VolumeAdjustSRdb);
CfgWriteFloat(L"MIXING", L"VolumeAdjustLFE(dB)", VolumeAdjustLFEdb);
CfgWriteStr(L"OUTPUT",L"Output_Module", mods[OutputModule]->GetIdent() );
CfgWriteInt(L"OUTPUT",L"Latency", SndOutLatencyMS);
CfgWriteInt(L"OUTPUT",L"Synch_Mode", SynchMode);
CfgWriteInt(L"OUTPUT",L"SpeakerConfiguration", numSpeakers);
CfgWriteInt( L"OUTPUT", L"DplDecodingLevel", dplLevel);
CfgWriteInt(L"DEBUG", L"DelayCycles", delayCycles);
CfgWriteStr(L"OUTPUT", L"Output_Module", mods[OutputModule]->GetIdent());
CfgWriteInt(L"OUTPUT", L"Latency", SndOutLatencyMS);
CfgWriteInt(L"OUTPUT", L"Synch_Mode", SynchMode);
CfgWriteInt(L"OUTPUT", L"SpeakerConfiguration", numSpeakers);
CfgWriteInt(L"OUTPUT", L"DplDecodingLevel", dplLevel);
CfgWriteInt(L"DEBUG", L"DelayCycles", delayCycles);
if( Config_WaveOut.Device.empty() ) Config_WaveOut.Device = L"default";
CfgWriteStr(L"WAVEOUT",L"Device",Config_WaveOut.Device);
CfgWriteInt(L"WAVEOUT",L"Buffer_Count",Config_WaveOut.NumBuffers);
if (Config_WaveOut.Device.empty())
Config_WaveOut.Device = L"default";
CfgWriteStr(L"WAVEOUT", L"Device", Config_WaveOut.Device);
CfgWriteInt(L"WAVEOUT", L"Buffer_Count", Config_WaveOut.NumBuffers);
CfgWriteStr(L"DSP PLUGIN",L"Filename",dspPlugin);
CfgWriteInt(L"DSP PLUGIN",L"ModuleNum",dspPluginModule);
CfgWriteBool(L"DSP PLUGIN",L"Enabled",dspPluginEnabled);
PortaudioOut->WriteSettings();
DSoundOut->WriteSettings();
SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings();
CfgWriteStr(L"DSP PLUGIN", L"Filename", dspPlugin);
CfgWriteInt(L"DSP PLUGIN", L"ModuleNum", dspPluginModule);
CfgWriteBool(L"DSP PLUGIN", L"Enabled", dspPluginEnabled);
PortaudioOut->WriteSettings();
DSoundOut->WriteSettings();
SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings();
}
BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId,wmEvent;
wchar_t temp[384]={0};
int wmId, wmEvent;
wchar_t temp[384] = {0};
switch(uMsg)
{
case WM_PAINT:
return FALSE;
switch (uMsg) {
case WM_PAINT:
return FALSE;
case WM_INITDIALOG:
{
SendDialogMsg( hWnd, IDC_INTERPOLATE, CB_RESETCONTENT,0,0 );
SendDialogMsg( hWnd, IDC_INTERPOLATE, CB_ADDSTRING,0,(LPARAM) L"0 - Nearest (fastest/bad quality)" );
SendDialogMsg( hWnd, IDC_INTERPOLATE, CB_ADDSTRING,0,(LPARAM) L"1 - Linear (simple/okay sound)" );
SendDialogMsg( hWnd, IDC_INTERPOLATE, CB_ADDSTRING,0,(LPARAM) L"2 - Cubic (artificial highs)" );
SendDialogMsg( hWnd, IDC_INTERPOLATE, CB_ADDSTRING,0,(LPARAM) L"3 - Hermite (better highs)" );
SendDialogMsg( hWnd, IDC_INTERPOLATE, CB_ADDSTRING,0,(LPARAM) L"4 - Catmull-Rom (PS2-like/slow)" );
SendDialogMsg( hWnd, IDC_INTERPOLATE, CB_SETCURSEL,Interpolation,0 );
case WM_INITDIALOG: {
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_RESETCONTENT, 0, 0);
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_ADDSTRING, 0, (LPARAM)L"0 - Nearest (fastest/bad quality)");
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_ADDSTRING, 0, (LPARAM)L"1 - Linear (simple/okay sound)");
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_ADDSTRING, 0, (LPARAM)L"2 - Cubic (artificial highs)");
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_ADDSTRING, 0, (LPARAM)L"3 - Hermite (better highs)");
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_ADDSTRING, 0, (LPARAM)L"4 - Catmull-Rom (PS2-like/slow)");
SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_SETCURSEL, Interpolation, 0);
SendDialogMsg( hWnd, IDC_SYNCHMODE, CB_RESETCONTENT,0,0 );
SendDialogMsg( hWnd, IDC_SYNCHMODE, CB_ADDSTRING,0,(LPARAM) L"TimeStretch (Recommended)" );
SendDialogMsg( hWnd, IDC_SYNCHMODE, CB_ADDSTRING,0,(LPARAM) L"Async Mix (Breaks some games!)" );
SendDialogMsg( hWnd, IDC_SYNCHMODE, CB_ADDSTRING,0,(LPARAM) L"None (Audio can skip.)" );
SendDialogMsg( hWnd, IDC_SYNCHMODE, CB_SETCURSEL,SynchMode,0 );
SendDialogMsg( hWnd, IDC_SPEAKERS, CB_RESETCONTENT,0,0 );
SendDialogMsg( hWnd, IDC_SPEAKERS, CB_ADDSTRING,0,(LPARAM) L"Stereo (none, default)" );
SendDialogMsg( hWnd, IDC_SPEAKERS, CB_ADDSTRING,0,(LPARAM) L"Quadrafonic" );
SendDialogMsg( hWnd, IDC_SPEAKERS, CB_ADDSTRING,0,(LPARAM) L"Surround 5.1" );
SendDialogMsg( hWnd, IDC_SPEAKERS, CB_ADDSTRING,0,(LPARAM) L"Surround 7.1" );
SendDialogMsg( hWnd, IDC_SPEAKERS, CB_SETCURSEL,numSpeakers,0 );
SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_RESETCONTENT, 0, 0);
SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_ADDSTRING, 0, (LPARAM)L"TimeStretch (Recommended)");
SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_ADDSTRING, 0, (LPARAM)L"Async Mix (Breaks some games!)");
SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_ADDSTRING, 0, (LPARAM)L"None (Audio can skip.)");
SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_SETCURSEL, SynchMode, 0);
SendDialogMsg( hWnd, IDC_OUTPUT, CB_RESETCONTENT,0,0 );
SendDialogMsg(hWnd, IDC_SPEAKERS, CB_RESETCONTENT, 0, 0);
SendDialogMsg(hWnd, IDC_SPEAKERS, CB_ADDSTRING, 0, (LPARAM)L"Stereo (none, default)");
SendDialogMsg(hWnd, IDC_SPEAKERS, CB_ADDSTRING, 0, (LPARAM)L"Quadrafonic");
SendDialogMsg(hWnd, IDC_SPEAKERS, CB_ADDSTRING, 0, (LPARAM)L"Surround 5.1");
SendDialogMsg(hWnd, IDC_SPEAKERS, CB_ADDSTRING, 0, (LPARAM)L"Surround 7.1");
SendDialogMsg(hWnd, IDC_SPEAKERS, CB_SETCURSEL, numSpeakers, 0);
int modidx = 0;
while( mods[modidx] != NULL )
{
swprintf_s( temp, 72, L"%d - %s", modidx, mods[modidx]->GetLongName() );
SendDialogMsg( hWnd, IDC_OUTPUT, CB_ADDSTRING,0,(LPARAM)temp );
++modidx;
}
SendDialogMsg( hWnd, IDC_OUTPUT, CB_SETCURSEL, OutputModule, 0 );
SendDialogMsg(hWnd, IDC_OUTPUT, CB_RESETCONTENT, 0, 0);
double minlat = (SynchMode == 0)?LATENCY_MIN_TS:LATENCY_MIN;
int minexp = (int)(pow( minlat+1, 1.0/3.0 ) * 128.0);
int maxexp = (int)(pow( (double)LATENCY_MAX+2, 1.0/3.0 ) * 128.0);
INIT_SLIDER( IDC_LATENCY_SLIDER, minexp, maxexp, 200, 42, 1 );
int modidx = 0;
while (mods[modidx] != NULL) {
swprintf_s(temp, 72, L"%d - %s", modidx, mods[modidx]->GetLongName());
SendDialogMsg(hWnd, IDC_OUTPUT, CB_ADDSTRING, 0, (LPARAM)temp);
++modidx;
}
SendDialogMsg(hWnd, IDC_OUTPUT, CB_SETCURSEL, OutputModule, 0);
SendDialogMsg( hWnd, IDC_LATENCY_SLIDER, TBM_SETPOS, TRUE, (int)((pow( (double)SndOutLatencyMS, 1.0/3.0 ) * 128.0) + 1) );
swprintf_s(temp,L"%d ms (avg)",SndOutLatencyMS);
SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp);
double minlat = (SynchMode == 0) ? LATENCY_MIN_TS : LATENCY_MIN;
int minexp = (int)(pow(minlat + 1, 1.0 / 3.0) * 128.0);
int maxexp = (int)(pow((double)LATENCY_MAX + 2, 1.0 / 3.0) * 128.0);
INIT_SLIDER(IDC_LATENCY_SLIDER, minexp, maxexp, 200, 42, 1);
int configvol = (int)(FinalVolume * 100 + 0.5f);
INIT_SLIDER( IDC_VOLUME_SLIDER, 0, 100, 10, 42, 1 );
SendDialogMsg(hWnd, IDC_LATENCY_SLIDER, TBM_SETPOS, TRUE, (int)((pow((double)SndOutLatencyMS, 1.0 / 3.0) * 128.0) + 1));
swprintf_s(temp, L"%d ms (avg)", SndOutLatencyMS);
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
SendDialogMsg( hWnd, IDC_VOLUME_SLIDER, TBM_SETPOS, TRUE, configvol );
swprintf_s(temp,L"%d%%",configvol);
SetWindowText(GetDlgItem(hWnd,IDC_VOLUME_LABEL),temp);
EnableWindow( GetDlgItem( hWnd, IDC_OPEN_CONFIG_SOUNDTOUCH ), (SynchMode == 0) );
EnableWindow( GetDlgItem( hWnd, IDC_OPEN_CONFIG_DEBUG ), DebugEnabled );
int configvol = (int)(FinalVolume * 100 + 0.5f);
INIT_SLIDER(IDC_VOLUME_SLIDER, 0, 100, 10, 42, 1);
SET_CHECK(IDC_EFFECTS_DISABLE, EffectsDisabled);
SET_CHECK(IDC_DEALIASFILTER, postprocess_filter_dealias);
SET_CHECK(IDC_DEBUG_ENABLE, DebugEnabled);
SET_CHECK(IDC_DSP_ENABLE, dspPluginEnabled);
}
break;
SendDialogMsg(hWnd, IDC_VOLUME_SLIDER, TBM_SETPOS, TRUE, configvol);
swprintf_s(temp, L"%d%%", configvol);
SetWindowText(GetDlgItem(hWnd, IDC_VOLUME_LABEL), temp);
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDOK:
{
double res = ((int)SendDialogMsg( hWnd, IDC_LATENCY_SLIDER, TBM_GETPOS, 0, 0 )) / 128.0;
SndOutLatencyMS = (int)pow( res, 3.0 );
Clampify( SndOutLatencyMS, LATENCY_MIN, LATENCY_MAX );
FinalVolume = (float)(SendDialogMsg( hWnd, IDC_VOLUME_SLIDER, TBM_GETPOS, 0, 0 )) / 100;
Interpolation = (int)SendDialogMsg( hWnd, IDC_INTERPOLATE, CB_GETCURSEL,0,0 );
OutputModule = (int)SendDialogMsg( hWnd, IDC_OUTPUT, CB_GETCURSEL,0,0 );
SynchMode = (int)SendDialogMsg( hWnd, IDC_SYNCHMODE, CB_GETCURSEL,0,0 );
numSpeakers = (int)SendDialogMsg( hWnd, IDC_SPEAKERS, CB_GETCURSEL,0,0 );
EnableWindow(GetDlgItem(hWnd, IDC_OPEN_CONFIG_SOUNDTOUCH), (SynchMode == 0));
EnableWindow(GetDlgItem(hWnd, IDC_OPEN_CONFIG_DEBUG), DebugEnabled);
WriteSettings();
EndDialog(hWnd,0);
}
break;
SET_CHECK(IDC_EFFECTS_DISABLE, EffectsDisabled);
SET_CHECK(IDC_DEALIASFILTER, postprocess_filter_dealias);
SET_CHECK(IDC_DEBUG_ENABLE, DebugEnabled);
SET_CHECK(IDC_DSP_ENABLE, dspPluginEnabled);
} break;
case IDCANCEL:
EndDialog(hWnd,0);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId) {
case IDOK: {
double res = ((int)SendDialogMsg(hWnd, IDC_LATENCY_SLIDER, TBM_GETPOS, 0, 0)) / 128.0;
SndOutLatencyMS = (int)pow(res, 3.0);
Clampify(SndOutLatencyMS, LATENCY_MIN, LATENCY_MAX);
FinalVolume = (float)(SendDialogMsg(hWnd, IDC_VOLUME_SLIDER, TBM_GETPOS, 0, 0)) / 100;
Interpolation = (int)SendDialogMsg(hWnd, IDC_INTERPOLATE, CB_GETCURSEL, 0, 0);
OutputModule = (int)SendDialogMsg(hWnd, IDC_OUTPUT, CB_GETCURSEL, 0, 0);
SynchMode = (int)SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_GETCURSEL, 0, 0);
numSpeakers = (int)SendDialogMsg(hWnd, IDC_SPEAKERS, CB_GETCURSEL, 0, 0);
case IDC_OUTCONF:
{
const int module = (int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0);
if( mods[module] == NULL ) break;
mods[module]->Configure((uptr)hWnd);
}
break;
WriteSettings();
EndDialog(hWnd, 0);
} break;
case IDC_OPEN_CONFIG_DEBUG:
{
// Quick Hack -- DebugEnabled is re-loaded with the DebugConfig's API,
// so we need to override it here:
case IDCANCEL:
EndDialog(hWnd, 0);
break;
bool dbgtmp = DebugEnabled;
DebugConfig::OpenDialog();
DebugEnabled = dbgtmp;
}
break;
case IDC_OUTCONF: {
const int module = (int)SendMessage(GetDlgItem(hWnd, IDC_OUTPUT), CB_GETCURSEL, 0, 0);
if (mods[module] == NULL)
break;
mods[module]->Configure((uptr)hWnd);
} break;
case IDC_SYNCHMODE:
{
if(wmEvent == CBN_SELCHANGE)
{
int sMode = (int)SendDialogMsg( hWnd, IDC_SYNCHMODE, CB_GETCURSEL,0,0 );
double minlat = (sMode == 0)?LATENCY_MIN_TS:LATENCY_MIN;
int minexp = (int)(pow( minlat+1, 1.0/3.0 ) * 128.0);
int maxexp = (int)(pow( (double)LATENCY_MAX+2, 1.0/3.0 ) * 128.0);
INIT_SLIDER( IDC_LATENCY_SLIDER, minexp, maxexp, 200, 42, 1 );
int curpos = (int)SendMessage(GetDlgItem( hWnd, IDC_LATENCY_SLIDER ),TBM_GETPOS,0,0);
double res = pow( curpos / 128.0, 3.0 );
curpos = (int)res;
swprintf_s(temp,L"%d ms (avg)",curpos);
SetDlgItemText(hWnd,IDC_LATENCY_LABEL,temp);
bool soundtouch = sMode == 0;
EnableWindow(GetDlgItem(hWnd, IDC_OPEN_CONFIG_SOUNDTOUCH), soundtouch);
}
}
break;
case IDC_OPEN_CONFIG_DEBUG: {
// Quick Hack -- DebugEnabled is re-loaded with the DebugConfig's API,
// so we need to override it here:
bool dbgtmp = DebugEnabled;
DebugConfig::OpenDialog();
DebugEnabled = dbgtmp;
} break;
case IDC_SYNCHMODE: {
if (wmEvent == CBN_SELCHANGE) {
int sMode = (int)SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_GETCURSEL, 0, 0);
double minlat = (sMode == 0) ? LATENCY_MIN_TS : LATENCY_MIN;
int minexp = (int)(pow(minlat + 1, 1.0 / 3.0) * 128.0);
int maxexp = (int)(pow((double)LATENCY_MAX + 2, 1.0 / 3.0) * 128.0);
INIT_SLIDER(IDC_LATENCY_SLIDER, minexp, maxexp, 200, 42, 1);
int curpos = (int)SendMessage(GetDlgItem(hWnd, IDC_LATENCY_SLIDER), TBM_GETPOS, 0, 0);
double res = pow(curpos / 128.0, 3.0);
curpos = (int)res;
swprintf_s(temp, L"%d ms (avg)", curpos);
SetDlgItemText(hWnd, IDC_LATENCY_LABEL, temp);
bool soundtouch = sMode == 0;
EnableWindow(GetDlgItem(hWnd, IDC_OPEN_CONFIG_SOUNDTOUCH), soundtouch);
}
} break;
case IDC_OPEN_CONFIG_SOUNDTOUCH:
SoundtouchCfg::OpenDialog( hWnd );
break;
case IDC_OPEN_CONFIG_SOUNDTOUCH:
SoundtouchCfg::OpenDialog(hWnd);
break;
HANDLE_CHECK(IDC_EFFECTS_DISABLE,EffectsDisabled);
HANDLE_CHECK(IDC_DEALIASFILTER,postprocess_filter_dealias);
HANDLE_CHECK(IDC_DSP_ENABLE,dspPluginEnabled);
HANDLE_CHECKNB(IDC_DEBUG_ENABLE,DebugEnabled);
DebugConfig::EnableControls( hWnd );
EnableWindow( GetDlgItem( hWnd, IDC_OPEN_CONFIG_DEBUG ), DebugEnabled );
break;
HANDLE_CHECK(IDC_EFFECTS_DISABLE, EffectsDisabled);
HANDLE_CHECK(IDC_DEALIASFILTER, postprocess_filter_dealias);
HANDLE_CHECK(IDC_DSP_ENABLE, dspPluginEnabled);
HANDLE_CHECKNB(IDC_DEBUG_ENABLE, DebugEnabled);
DebugConfig::EnableControls(hWnd);
EnableWindow(GetDlgItem(hWnd, IDC_OPEN_CONFIG_DEBUG), DebugEnabled);
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
break;
case WM_HSCROLL:
{
wmEvent = LOWORD(wParam);
HWND hwndDlg = (HWND)lParam;
case WM_HSCROLL: {
wmEvent = LOWORD(wParam);
HWND hwndDlg = (HWND)lParam;
// TB_THUMBTRACK passes the curpos in wParam. Other messages
// have to use TBM_GETPOS, so they will override this assignment (see below)
// TB_THUMBTRACK passes the curpos in wParam. Other messages
// have to use TBM_GETPOS, so they will override this assignment (see below)
int curpos = HIWORD( wParam );
int curpos = HIWORD(wParam);
switch( wmEvent )
{
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
curpos = (int)SendMessage(hwndDlg,TBM_GETPOS,0,0);
switch (wmEvent) {
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
curpos = (int)SendMessage(hwndDlg, TBM_GETPOS, 0, 0);
case TB_THUMBTRACK:
Clampify( curpos,
(int)SendMessage(hwndDlg,TBM_GETRANGEMIN,0,0),
(int)SendMessage(hwndDlg,TBM_GETRANGEMAX,0,0)
);
case TB_THUMBTRACK:
Clampify(curpos,
(int)SendMessage(hwndDlg, TBM_GETRANGEMIN, 0, 0),
(int)SendMessage(hwndDlg, TBM_GETRANGEMAX, 0, 0));
SendMessage((HWND)lParam,TBM_SETPOS,TRUE,curpos);
SendMessage((HWND)lParam, TBM_SETPOS, TRUE, curpos);
if( hwndDlg == GetDlgItem( hWnd, IDC_LATENCY_SLIDER ) )
{
double res = pow( curpos / 128.0, 3.0 );
curpos = (int)res;
swprintf_s(temp,L"%d ms (avg)",curpos);
SetDlgItemText(hWnd,IDC_LATENCY_LABEL,temp);
}
if( hwndDlg == GetDlgItem( hWnd, IDC_VOLUME_SLIDER ) )
{
swprintf_s(temp,L"%d%%",curpos);
SetDlgItemText(hWnd,IDC_VOLUME_LABEL,temp);
}
break;
if (hwndDlg == GetDlgItem(hWnd, IDC_LATENCY_SLIDER)) {
double res = pow(curpos / 128.0, 3.0);
curpos = (int)res;
swprintf_s(temp, L"%d ms (avg)", curpos);
SetDlgItemText(hWnd, IDC_LATENCY_LABEL, temp);
}
default:
return FALSE;
}
}
break;
if (hwndDlg == GetDlgItem(hWnd, IDC_VOLUME_SLIDER)) {
swprintf_s(temp, L"%d%%", curpos);
SetDlgItemText(hWnd, IDC_VOLUME_LABEL, temp);
}
break;
default:
return FALSE;
}
return TRUE;
default:
return FALSE;
}
} break;
default:
return FALSE;
}
return TRUE;
}
void configure()
{
INT_PTR ret;
ReadSettings();
ret = DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_CONFIG),GetActiveWindow(),(DLGPROC)ConfigProc,1);
if(ret==-1)
{
MessageBox(GetActiveWindow(),L"Error Opening the config dialog.",L"OMG ERROR!",MB_OK | MB_SETFOREGROUND);
return;
}
ReadSettings();
INT_PTR ret;
ReadSettings();
ret = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_CONFIG), GetActiveWindow(), (DLGPROC)ConfigProc, 1);
if (ret == -1) {
MessageBox(GetActiveWindow(), L"Error Opening the config dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
ReadSettings();
}

View File

@ -20,24 +20,24 @@
#include "Utilities\Path.h"
bool DebugEnabled=false;
bool _MsgToConsole=false;
bool _MsgKeyOnOff=false;
bool _MsgVoiceOff=false;
bool _MsgDMA=false;
bool _MsgAutoDMA=false;
bool _MsgOverruns=false;
bool _MsgCache=false;
bool DebugEnabled = false;
bool _MsgToConsole = false;
bool _MsgKeyOnOff = false;
bool _MsgVoiceOff = false;
bool _MsgDMA = false;
bool _MsgAutoDMA = false;
bool _MsgOverruns = false;
bool _MsgCache = false;
bool _AccessLog=false;
bool _DMALog=false;
bool _WaveLog=false;
bool _AccessLog = false;
bool _DMALog = false;
bool _WaveLog = false;
bool _CoresDump=false;
bool _MemDump=false;
bool _RegDump=false;
bool _CoresDump = false;
bool _MemDump = false;
bool _RegDump = false;
bool _visual_debug_enabled=false;
bool _visual_debug_enabled = false;
// this is set true if PCSX2 invokes the SetLogDir callback, which tells SPU2-X to use that over
// the configured crap in the ini file.
@ -57,220 +57,213 @@ wxString CoresDumpFileName;
wxString MemDumpFileName;
wxString RegDumpFileName;
void CfgSetLogDir( const char* dir )
void CfgSetLogDir(const char *dir)
{
LogsFolder = (dir==NULL) ? wxString(L"logs") : wxString(dir, wxConvFile);
DumpsFolder = (dir==NULL) ? wxString(L"logs") : wxString(dir, wxConvFile);
LogLocationSetByPcsx2 = (dir!=NULL);
LogsFolder = (dir == NULL) ? wxString(L"logs") : wxString(dir, wxConvFile);
DumpsFolder = (dir == NULL) ? wxString(L"logs") : wxString(dir, wxConvFile);
LogLocationSetByPcsx2 = (dir != NULL);
}
FILE* OpenBinaryLog( const wxString& logfile )
FILE *OpenBinaryLog(const wxString &logfile)
{
return wxFopen( Path::Combine(LogsFolder, logfile), L"wb" );
return wxFopen(Path::Combine(LogsFolder, logfile), L"wb");
}
FILE* OpenLog( const wxString& logfile )
FILE *OpenLog(const wxString &logfile)
{
return wxFopen( Path::Combine(LogsFolder, logfile), L"w" );
return wxFopen(Path::Combine(LogsFolder, logfile), L"w");
}
FILE* OpenDump( const wxString& logfile )
FILE *OpenDump(const wxString &logfile)
{
return wxFopen( Path::Combine(DumpsFolder, logfile), L"w" );
return wxFopen(Path::Combine(DumpsFolder, logfile), L"w");
}
namespace DebugConfig {
namespace DebugConfig
{
static const wxChar* Section = L"DEBUG";
static const wxChar *Section = L"DEBUG";
void ReadSettings()
{
DebugEnabled = CfgReadBool(Section, L"Global_Enable",0);
_MsgToConsole= CfgReadBool(Section, L"Show_Messages",0);
_MsgKeyOnOff = CfgReadBool(Section, L"Show_Messages_Key_On_Off",0);
_MsgVoiceOff = CfgReadBool(Section, L"Show_Messages_Voice_Off",0);
_MsgDMA = CfgReadBool(Section, L"Show_Messages_DMA_Transfer",0);
_MsgAutoDMA = CfgReadBool(Section, L"Show_Messages_AutoDMA",0);
_MsgOverruns = CfgReadBool(Section, L"Show_Messages_Overruns",0);
_MsgCache = CfgReadBool(Section, L"Show_Messages_CacheStats",0);
DebugEnabled = CfgReadBool(Section, L"Global_Enable", 0);
_MsgToConsole = CfgReadBool(Section, L"Show_Messages", 0);
_MsgKeyOnOff = CfgReadBool(Section, L"Show_Messages_Key_On_Off", 0);
_MsgVoiceOff = CfgReadBool(Section, L"Show_Messages_Voice_Off", 0);
_MsgDMA = CfgReadBool(Section, L"Show_Messages_DMA_Transfer", 0);
_MsgAutoDMA = CfgReadBool(Section, L"Show_Messages_AutoDMA", 0);
_MsgOverruns = CfgReadBool(Section, L"Show_Messages_Overruns", 0);
_MsgCache = CfgReadBool(Section, L"Show_Messages_CacheStats", 0);
_AccessLog = CfgReadBool(Section, L"Log_Register_Access",0);
_DMALog = CfgReadBool(Section, L"Log_DMA_Transfers",0);
_WaveLog = CfgReadBool(Section, L"Log_WAVE_Output",0);
_AccessLog = CfgReadBool(Section, L"Log_Register_Access", 0);
_DMALog = CfgReadBool(Section, L"Log_DMA_Transfers", 0);
_WaveLog = CfgReadBool(Section, L"Log_WAVE_Output", 0);
_CoresDump = CfgReadBool(Section, L"Dump_Info",0);
_MemDump = CfgReadBool(Section, L"Dump_Memory",0);
_RegDump = CfgReadBool(Section, L"Dump_Regs",0);
_CoresDump = CfgReadBool(Section, L"Dump_Info", 0);
_MemDump = CfgReadBool(Section, L"Dump_Memory", 0);
_RegDump = CfgReadBool(Section, L"Dump_Regs", 0);
_visual_debug_enabled = CfgReadBool(Section, L"Visual_Debug_Enabled",0);
_visual_debug_enabled = CfgReadBool(Section, L"Visual_Debug_Enabled", 0);
CfgReadStr(Section,L"Logs_Folder", CfgLogsFolder, L"logs");
CfgReadStr(Section,L"Dumps_Folder",CfgDumpsFolder,L"logs");
CfgReadStr(Section, L"Logs_Folder", CfgLogsFolder, L"logs");
CfgReadStr(Section, L"Dumps_Folder", CfgDumpsFolder, L"logs");
CfgReadStr(Section,L"Access_Log_Filename",AccessLogFileName, L"SPU2Log.txt");
CfgReadStr(Section,L"DMA4Log_Filename", DMA4LogFileName, L"SPU2dma4.dat");
CfgReadStr(Section,L"DMA7Log_Filename", DMA7LogFileName, L"SPU2dma7.dat");
CfgReadStr(Section, L"Access_Log_Filename", AccessLogFileName, L"SPU2Log.txt");
CfgReadStr(Section, L"DMA4Log_Filename", DMA4LogFileName, L"SPU2dma4.dat");
CfgReadStr(Section, L"DMA7Log_Filename", DMA7LogFileName, L"SPU2dma7.dat");
CfgReadStr(Section,L"Info_Dump_Filename", CoresDumpFileName, L"SPU2Cores.txt");
CfgReadStr(Section,L"Mem_Dump_Filename", MemDumpFileName, L"SPU2mem.dat");
CfgReadStr(Section,L"Reg_Dump_Filename", RegDumpFileName, L"SPU2regs.dat");
CfgReadStr(Section, L"Info_Dump_Filename", CoresDumpFileName, L"SPU2Cores.txt");
CfgReadStr(Section, L"Mem_Dump_Filename", MemDumpFileName, L"SPU2mem.dat");
CfgReadStr(Section, L"Reg_Dump_Filename", RegDumpFileName, L"SPU2regs.dat");
if( !LogLocationSetByPcsx2 )
{
LogsFolder = CfgLogsFolder;
DumpsFolder = CfgLogsFolder;
}
if (!LogLocationSetByPcsx2) {
LogsFolder = CfgLogsFolder;
DumpsFolder = CfgLogsFolder;
}
}
void WriteSettings()
{
CfgWriteBool(Section,L"Global_Enable",DebugEnabled);
CfgWriteBool(Section, L"Global_Enable", DebugEnabled);
CfgWriteBool(Section,L"Show_Messages", _MsgToConsole);
CfgWriteBool(Section,L"Show_Messages_Key_On_Off", _MsgKeyOnOff);
CfgWriteBool(Section,L"Show_Messages_Voice_Off", _MsgVoiceOff);
CfgWriteBool(Section,L"Show_Messages_DMA_Transfer",_MsgDMA);
CfgWriteBool(Section,L"Show_Messages_AutoDMA", _MsgAutoDMA);
CfgWriteBool(Section,L"Show_Messages_Overruns", _MsgOverruns);
CfgWriteBool(Section,L"Show_Messages_CacheStats", _MsgCache);
CfgWriteBool(Section, L"Show_Messages", _MsgToConsole);
CfgWriteBool(Section, L"Show_Messages_Key_On_Off", _MsgKeyOnOff);
CfgWriteBool(Section, L"Show_Messages_Voice_Off", _MsgVoiceOff);
CfgWriteBool(Section, L"Show_Messages_DMA_Transfer", _MsgDMA);
CfgWriteBool(Section, L"Show_Messages_AutoDMA", _MsgAutoDMA);
CfgWriteBool(Section, L"Show_Messages_Overruns", _MsgOverruns);
CfgWriteBool(Section, L"Show_Messages_CacheStats", _MsgCache);
CfgWriteBool(Section,L"Log_Register_Access",_AccessLog);
CfgWriteBool(Section,L"Log_DMA_Transfers", _DMALog);
CfgWriteBool(Section,L"Log_WAVE_Output", _WaveLog);
CfgWriteBool(Section, L"Log_Register_Access", _AccessLog);
CfgWriteBool(Section, L"Log_DMA_Transfers", _DMALog);
CfgWriteBool(Section, L"Log_WAVE_Output", _WaveLog);
CfgWriteBool(Section,L"Dump_Info", _CoresDump);
CfgWriteBool(Section,L"Dump_Memory",_MemDump);
CfgWriteBool(Section,L"Dump_Regs", _RegDump);
CfgWriteBool(Section, L"Dump_Info", _CoresDump);
CfgWriteBool(Section, L"Dump_Memory", _MemDump);
CfgWriteBool(Section, L"Dump_Regs", _RegDump);
CfgWriteBool(Section,L"Visual_Debug_Enabled", _visual_debug_enabled);
CfgWriteBool(Section, L"Visual_Debug_Enabled", _visual_debug_enabled);
// None of the logs strings are changable via GUI, so no point in bothering to
// write them back out.
CfgWriteStr(Section,L"Logs_Folder", CfgLogsFolder);
CfgWriteStr(Section,L"Dumps_Folder",CfgDumpsFolder);
// None of the logs strings are changable via GUI, so no point in bothering to
// write them back out.
CfgWriteStr(Section, L"Logs_Folder", CfgLogsFolder);
CfgWriteStr(Section, L"Dumps_Folder", CfgDumpsFolder);
CfgWriteStr(Section,L"Access_Log_Filename",AccessLogFileName);
CfgWriteStr(Section,L"DMA4Log_Filename", DMA4LogFileName);
CfgWriteStr(Section,L"DMA7Log_Filename", DMA7LogFileName);
CfgWriteStr(Section, L"Access_Log_Filename", AccessLogFileName);
CfgWriteStr(Section, L"DMA4Log_Filename", DMA4LogFileName);
CfgWriteStr(Section, L"DMA7Log_Filename", DMA7LogFileName);
CfgWriteStr(Section,L"Info_Dump_Filename",CoresDumpFileName);
CfgWriteStr(Section,L"Mem_Dump_Filename", MemDumpFileName);
CfgWriteStr(Section,L"Reg_Dump_Filename", RegDumpFileName);
CfgWriteStr(Section, L"Info_Dump_Filename", CoresDumpFileName);
CfgWriteStr(Section, L"Mem_Dump_Filename", MemDumpFileName);
CfgWriteStr(Section, L"Reg_Dump_Filename", RegDumpFileName);
}
static void EnableMessages( HWND hWnd )
static void EnableMessages(HWND hWnd)
{
ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled);
ENABLE_CONTROL(IDC_MSGKEY, MsgToConsole());
ENABLE_CONTROL(IDC_MSGVOICE,MsgToConsole());
ENABLE_CONTROL(IDC_MSGDMA, MsgToConsole());
ENABLE_CONTROL(IDC_MSGADMA, MsgToConsole());
ENABLE_CONTROL(IDC_DBG_OVERRUNS, MsgToConsole());
ENABLE_CONTROL(IDC_DBG_CACHE, MsgToConsole());
ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled);
ENABLE_CONTROL(IDC_MSGKEY, MsgToConsole());
ENABLE_CONTROL(IDC_MSGVOICE, MsgToConsole());
ENABLE_CONTROL(IDC_MSGDMA, MsgToConsole());
ENABLE_CONTROL(IDC_MSGADMA, MsgToConsole());
ENABLE_CONTROL(IDC_DBG_OVERRUNS, MsgToConsole());
ENABLE_CONTROL(IDC_DBG_CACHE, MsgToConsole());
}
void EnableControls( HWND hWnd )
void EnableControls(HWND hWnd)
{
EnableMessages( hWnd );
ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled);
ENABLE_CONTROL(IDC_LOGREGS, IsDevBuild ? DebugEnabled : false);
ENABLE_CONTROL(IDC_LOGWAVE, IsDevBuild ? DebugEnabled : false);
ENABLE_CONTROL(IDC_DUMPCORE,DebugEnabled);
ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPREGS,DebugEnabled);
ENABLE_CONTROL(IDC_DEBUG_VISUAL, IsDevBuild ? DebugEnabled : false);
EnableMessages(hWnd);
ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled);
ENABLE_CONTROL(IDC_LOGREGS, IsDevBuild ? DebugEnabled : false);
ENABLE_CONTROL(IDC_LOGWAVE, IsDevBuild ? DebugEnabled : false);
ENABLE_CONTROL(IDC_DUMPCORE, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPREGS, DebugEnabled);
ENABLE_CONTROL(IDC_DEBUG_VISUAL, IsDevBuild ? DebugEnabled : false);
}
static BOOL CALLBACK DialogProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
static BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId;
//wchar_t temp[384]={0};
int wmId;
//wchar_t temp[384]={0};
switch(uMsg)
{
case WM_PAINT:
return FALSE;
switch (uMsg) {
case WM_PAINT:
return FALSE;
case WM_INITDIALOG:
{
EnableControls( hWnd );
case WM_INITDIALOG: {
EnableControls(hWnd);
// Debugging / Logging Flags:
SET_CHECK(IDC_DEBUG, DebugEnabled);
SET_CHECK(IDC_MSGSHOW, _MsgToConsole);
SET_CHECK(IDC_MSGKEY, _MsgKeyOnOff);
SET_CHECK(IDC_MSGVOICE,_MsgVoiceOff);
SET_CHECK(IDC_MSGDMA, _MsgDMA);
SET_CHECK(IDC_MSGADMA, _MsgAutoDMA);
SET_CHECK(IDC_DBG_OVERRUNS, _MsgOverruns );
SET_CHECK(IDC_DBG_CACHE, _MsgCache );
SET_CHECK(IDC_LOGREGS, _AccessLog);
SET_CHECK(IDC_LOGDMA, _DMALog);
SET_CHECK(IDC_LOGWAVE, _WaveLog);
SET_CHECK(IDC_DUMPCORE,_CoresDump);
SET_CHECK(IDC_DUMPMEM, _MemDump);
SET_CHECK(IDC_DUMPREGS,_RegDump);
SET_CHECK(IDC_DEBUG_VISUAL,_visual_debug_enabled);
// Debugging / Logging Flags:
SET_CHECK(IDC_DEBUG, DebugEnabled);
SET_CHECK(IDC_MSGSHOW, _MsgToConsole);
SET_CHECK(IDC_MSGKEY, _MsgKeyOnOff);
SET_CHECK(IDC_MSGVOICE, _MsgVoiceOff);
SET_CHECK(IDC_MSGDMA, _MsgDMA);
SET_CHECK(IDC_MSGADMA, _MsgAutoDMA);
SET_CHECK(IDC_DBG_OVERRUNS, _MsgOverruns);
SET_CHECK(IDC_DBG_CACHE, _MsgCache);
SET_CHECK(IDC_LOGREGS, _AccessLog);
SET_CHECK(IDC_LOGDMA, _DMALog);
SET_CHECK(IDC_LOGWAVE, _WaveLog);
SET_CHECK(IDC_DUMPCORE, _CoresDump);
SET_CHECK(IDC_DUMPMEM, _MemDump);
SET_CHECK(IDC_DUMPREGS, _RegDump);
SET_CHECK(IDC_DEBUG_VISUAL, _visual_debug_enabled);
ShowWindow( GetDlgItem( hWnd, IDC_MSG_PUBLIC_BUILD ), !IsDevBuild );
}
break;
ShowWindow(GetDlgItem(hWnd, IDC_MSG_PUBLIC_BUILD), !IsDevBuild);
} break;
case WM_COMMAND:
wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDOK:
WriteSettings();
EndDialog(hWnd,0);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId) {
case IDOK:
WriteSettings();
EndDialog(hWnd, 0);
break;
case IDCANCEL:
EndDialog(hWnd,0);
break;
case IDCANCEL:
EndDialog(hWnd, 0);
break;
HANDLE_CHECKNB(IDC_MSGSHOW,_MsgToConsole);
EnableMessages( hWnd );
break;
HANDLE_CHECKNB(IDC_MSGSHOW, _MsgToConsole);
EnableMessages(hWnd);
break;
HANDLE_CHECK(IDC_MSGKEY,_MsgKeyOnOff);
HANDLE_CHECK(IDC_MSGVOICE,_MsgVoiceOff);
HANDLE_CHECK(IDC_MSGDMA,_MsgDMA);
HANDLE_CHECK(IDC_MSGADMA,_MsgAutoDMA);
break;
HANDLE_CHECK(IDC_MSGKEY, _MsgKeyOnOff);
HANDLE_CHECK(IDC_MSGVOICE, _MsgVoiceOff);
HANDLE_CHECK(IDC_MSGDMA, _MsgDMA);
HANDLE_CHECK(IDC_MSGADMA, _MsgAutoDMA);
break;
HANDLE_CHECK(IDC_DBG_OVERRUNS,_MsgOverruns);
HANDLE_CHECK(IDC_DBG_CACHE,_MsgCache);
HANDLE_CHECK(IDC_LOGREGS,_AccessLog);
HANDLE_CHECK(IDC_LOGDMA, _DMALog);
HANDLE_CHECK(IDC_LOGWAVE,_WaveLog);
HANDLE_CHECK(IDC_DUMPCORE,_CoresDump);
HANDLE_CHECK(IDC_DUMPMEM, _MemDump);
HANDLE_CHECK(IDC_DUMPREGS,_RegDump);
HANDLE_CHECK(IDC_DEBUG_VISUAL,_visual_debug_enabled);
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
HANDLE_CHECK(IDC_DBG_OVERRUNS, _MsgOverruns);
HANDLE_CHECK(IDC_DBG_CACHE, _MsgCache);
HANDLE_CHECK(IDC_LOGREGS, _AccessLog);
HANDLE_CHECK(IDC_LOGDMA, _DMALog);
HANDLE_CHECK(IDC_LOGWAVE, _WaveLog);
HANDLE_CHECK(IDC_DUMPCORE, _CoresDump);
HANDLE_CHECK(IDC_DUMPMEM, _MemDump);
HANDLE_CHECK(IDC_DUMPREGS, _RegDump);
HANDLE_CHECK(IDC_DEBUG_VISUAL, _visual_debug_enabled);
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
void OpenDialog()
{
INT_PTR ret = DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_CONFIG_DEBUG),GetActiveWindow(),(DLGPROC)DialogProc,1);
if(ret == -1)
{
MessageBox(GetActiveWindow(),L"Error Opening the debug configuration dialog.",L"OMG ERROR!",MB_OK | MB_SETFOREGROUND);
return;
}
ReadSettings();
INT_PTR ret = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_CONFIG_DEBUG), GetActiveWindow(), (DLGPROC)DialogProc, 1);
if (ret == -1) {
MessageBox(GetActiveWindow(), L"Error Opening the debug configuration dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
ReadSettings();
}
}

View File

@ -34,106 +34,98 @@ static const int SeekWindow_Max = 30;
static const int Overlap_Min = 5;
static const int Overlap_Max = 15;
void SoundtouchCfg::ApplySettings( soundtouch::SoundTouch& sndtouch )
void SoundtouchCfg::ApplySettings(soundtouch::SoundTouch &sndtouch)
{
sndtouch.setSetting( SETTING_SEQUENCE_MS, SequenceLenMS );
sndtouch.setSetting( SETTING_SEEKWINDOW_MS, SeekWindowMS );
sndtouch.setSetting( SETTING_OVERLAP_MS, OverlapMS );
sndtouch.setSetting(SETTING_SEQUENCE_MS, SequenceLenMS);
sndtouch.setSetting(SETTING_SEEKWINDOW_MS, SeekWindowMS);
sndtouch.setSetting(SETTING_OVERLAP_MS, OverlapMS);
}
static void ClampValues()
{
Clampify( SequenceLenMS, SequenceLen_Min, SequenceLen_Max );
Clampify( SeekWindowMS, SeekWindow_Min, SeekWindow_Max );
Clampify( OverlapMS, Overlap_Min, Overlap_Max );
Clampify(SequenceLenMS, SequenceLen_Min, SequenceLen_Max);
Clampify(SeekWindowMS, SeekWindow_Min, SeekWindow_Max);
Clampify(OverlapMS, Overlap_Min, Overlap_Max);
}
void SoundtouchCfg::ReadSettings()
{
SequenceLenMS = CfgReadInt( L"SOUNDTOUCH", L"SequenceLengthMS", 30 );
SeekWindowMS = CfgReadInt( L"SOUNDTOUCH", L"SeekWindowMS", 20 );
OverlapMS = CfgReadInt( L"SOUNDTOUCH", L"OverlapMS", 10 );
SequenceLenMS = CfgReadInt(L"SOUNDTOUCH", L"SequenceLengthMS", 30);
SeekWindowMS = CfgReadInt(L"SOUNDTOUCH", L"SeekWindowMS", 20);
OverlapMS = CfgReadInt(L"SOUNDTOUCH", L"OverlapMS", 10);
ClampValues();
ClampValues();
}
void SoundtouchCfg::WriteSettings()
{
CfgWriteInt( L"SOUNDTOUCH", L"SequenceLengthMS", SequenceLenMS );
CfgWriteInt( L"SOUNDTOUCH", L"SeekWindowMS", SeekWindowMS );
CfgWriteInt( L"SOUNDTOUCH", L"OverlapMS", OverlapMS );
CfgWriteInt(L"SOUNDTOUCH", L"SequenceLengthMS", SequenceLenMS);
CfgWriteInt(L"SOUNDTOUCH", L"SeekWindowMS", SeekWindowMS);
CfgWriteInt(L"SOUNDTOUCH", L"OverlapMS", OverlapMS);
}
BOOL CALLBACK SoundtouchCfg::DialogProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
BOOL CALLBACK SoundtouchCfg::DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId;
//wchar_t temp[384]={0};
int wmId;
//wchar_t temp[384]={0};
switch(uMsg)
{
case WM_PAINT:
return FALSE;
switch (uMsg) {
case WM_PAINT:
return FALSE;
case WM_INITDIALOG:
{
INIT_SLIDER( IDC_SEQLEN_SLIDER, SequenceLen_Min, SequenceLen_Max, 20, 5, 1 );
INIT_SLIDER( IDC_SEEKWIN_SLIDER, SeekWindow_Min, SeekWindow_Max, 5, 2, 1 );
INIT_SLIDER( IDC_OVERLAP_SLIDER, Overlap_Min, Overlap_Max, 3, 2, 1 );
case WM_INITDIALOG: {
INIT_SLIDER(IDC_SEQLEN_SLIDER, SequenceLen_Min, SequenceLen_Max, 20, 5, 1);
INIT_SLIDER(IDC_SEEKWIN_SLIDER, SeekWindow_Min, SeekWindow_Max, 5, 2, 1);
INIT_SLIDER(IDC_OVERLAP_SLIDER, Overlap_Min, Overlap_Max, 3, 2, 1);
SendDialogMsg( hWnd, IDC_SEQLEN_SLIDER, TBM_SETPOS, TRUE, SequenceLenMS );
SendDialogMsg( hWnd, IDC_SEEKWIN_SLIDER, TBM_SETPOS, TRUE, SeekWindowMS );
SendDialogMsg( hWnd, IDC_OVERLAP_SLIDER, TBM_SETPOS, TRUE, OverlapMS );
}
SendDialogMsg(hWnd, IDC_SEQLEN_SLIDER, TBM_SETPOS, TRUE, SequenceLenMS);
SendDialogMsg(hWnd, IDC_SEEKWIN_SLIDER, TBM_SETPOS, TRUE, SeekWindowMS);
SendDialogMsg(hWnd, IDC_OVERLAP_SLIDER, TBM_SETPOS, TRUE, OverlapMS);
}
case WM_COMMAND:
wmId = LOWORD(wParam);
// Parse the menu selections:
if( wmId == IDOK )
{
SequenceLenMS = (int)SendDialogMsg( hWnd, IDC_SEQLEN_SLIDER, TBM_GETPOS, 0, 0 );
SeekWindowMS = (int)SendDialogMsg( hWnd, IDC_SEEKWIN_SLIDER, TBM_GETPOS, 0, 0 );
OverlapMS = (int)SendDialogMsg( hWnd, IDC_OVERLAP_SLIDER, TBM_GETPOS, 0, 0 );
case WM_COMMAND:
wmId = LOWORD(wParam);
// Parse the menu selections:
if (wmId == IDOK) {
SequenceLenMS = (int)SendDialogMsg(hWnd, IDC_SEQLEN_SLIDER, TBM_GETPOS, 0, 0);
SeekWindowMS = (int)SendDialogMsg(hWnd, IDC_SEEKWIN_SLIDER, TBM_GETPOS, 0, 0);
OverlapMS = (int)SendDialogMsg(hWnd, IDC_OVERLAP_SLIDER, TBM_GETPOS, 0, 0);
ClampValues();
WriteSettings();
EndDialog(hWnd,0);
}
else if( wmId == IDC_RESET_DEFAULTS )
{
SequenceLenMS = 30;
SeekWindowMS = 20;
OverlapMS = 10;
ClampValues();
WriteSettings();
EndDialog(hWnd, 0);
} else if (wmId == IDC_RESET_DEFAULTS) {
SequenceLenMS = 30;
SeekWindowMS = 20;
OverlapMS = 10;
SendDialogMsg( hWnd, IDC_SEQLEN_SLIDER, TBM_SETPOS, TRUE, SequenceLenMS );
SendDialogMsg( hWnd, IDC_SEEKWIN_SLIDER, TBM_SETPOS, TRUE, SeekWindowMS );
SendDialogMsg( hWnd, IDC_OVERLAP_SLIDER, TBM_SETPOS, TRUE, OverlapMS );
SendDialogMsg(hWnd, IDC_SEQLEN_SLIDER, TBM_SETPOS, TRUE, SequenceLenMS);
SendDialogMsg(hWnd, IDC_SEEKWIN_SLIDER, TBM_SETPOS, TRUE, SeekWindowMS);
SendDialogMsg(hWnd, IDC_OVERLAP_SLIDER, TBM_SETPOS, TRUE, OverlapMS);
AssignSliderValue((HWND)lParam, hWnd, SequenceLenMS);
}
else if( wmId == IDCANCEL )
{
EndDialog(hWnd,0);
}
break;
AssignSliderValue((HWND)lParam, hWnd, SequenceLenMS);
} else if (wmId == IDCANCEL) {
EndDialog(hWnd, 0);
}
break;
case WM_HSCROLL:
DoHandleScrollMessage( hWnd, wParam, lParam );
break;
case WM_HSCROLL:
DoHandleScrollMessage(hWnd, wParam, lParam);
break;
default:
return FALSE;
}
return TRUE;
default:
return FALSE;
}
return TRUE;
}
void SoundtouchCfg::OpenDialog( HWND hWnd )
void SoundtouchCfg::OpenDialog(HWND hWnd)
{
INT_PTR ret;
ret = DialogBox( hInstance, MAKEINTRESOURCE(IDD_CONFIG_SOUNDTOUCH), hWnd, (DLGPROC)DialogProc );
if(ret==-1)
{
MessageBox(GetActiveWindow(), L"Error Opening the Soundtouch advanced dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
ReadSettings();
INT_PTR ret;
ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_CONFIG_SOUNDTOUCH), hWnd, (DLGPROC)DialogProc);
if (ret == -1) {
MessageBox(GetActiveWindow(), L"Error Opening the Soundtouch advanced dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
ReadSettings();
}

View File

@ -18,61 +18,60 @@
#pragma once
#ifdef _WIN32
# include "WinConfig.h"
#include "WinConfig.h"
#else
# include "LnxConfig.h"
#include "LnxConfig.h"
#endif
namespace DebugConfig
{
extern void ReadSettings();
extern void WriteSettings();
extern void OpenDialog();
extern void EnableControls( HWND hWnd );
extern void ReadSettings();
extern void WriteSettings();
extern void OpenDialog();
extern void EnableControls(HWND hWnd);
}
namespace SoundtouchCfg
{
extern void ReadSettings();
extern void WriteSettings();
extern void OpenDialog( HWND hWnd );
extern BOOL CALLBACK DialogProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
extern void ReadSettings();
extern void WriteSettings();
extern void OpenDialog(HWND hWnd);
extern BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
}
extern int SendDialogMsg( HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam);
extern HRESULT GUIDFromString( const wchar_t *str, LPGUID guid );
extern int SendDialogMsg(HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam);
extern HRESULT GUIDFromString(const wchar_t *str, LPGUID guid);
extern void AssignSliderValue( HWND idcwnd, HWND hwndDisplay, int value );
extern void AssignSliderValue( HWND hWnd, int idc, int editbox, int value );
extern int GetSliderValue( HWND hWnd, int idc );
extern BOOL DoHandleScrollMessage( HWND hwndDisplay, WPARAM wParam, LPARAM lParam );
extern void AssignSliderValue(HWND idcwnd, HWND hwndDisplay, int value);
extern void AssignSliderValue(HWND hWnd, int idc, int editbox, int value);
extern int GetSliderValue(HWND hWnd, int idc);
extern BOOL DoHandleScrollMessage(HWND hwndDisplay, WPARAM wParam, LPARAM lParam);
extern void CfgSetSettingsDir( const char* dir );
extern void CfgSetLogDir( const char* dir );
extern void CfgSetSettingsDir(const char *dir);
extern void CfgSetLogDir(const char *dir);
extern bool CfgFindName( const TCHAR *Section, const TCHAR* Name);
extern bool CfgFindName(const TCHAR *Section, const TCHAR *Name);
extern void CfgWriteBool(const TCHAR* Section, const TCHAR* Name, bool Value);
extern void CfgWriteInt(const TCHAR* Section, const TCHAR* Name, int Value);
extern void CfgWriteFloat(const TCHAR* Section, const TCHAR* Name, float Value);
extern void CfgWriteStr(const TCHAR* Section, const TCHAR* Name, const wxString& Data);
extern void CfgWriteBool(const TCHAR *Section, const TCHAR *Name, bool Value);
extern void CfgWriteInt(const TCHAR *Section, const TCHAR *Name, int Value);
extern void CfgWriteFloat(const TCHAR *Section, const TCHAR *Name, float Value);
extern void CfgWriteStr(const TCHAR *Section, const TCHAR *Name, const wxString &Data);
extern bool CfgReadBool(const TCHAR *Section,const TCHAR* Name, bool Default);
extern void CfgReadStr(const TCHAR* Section, const TCHAR* Name, wxString& Data, const TCHAR* Default);
extern void CfgReadStr(const TCHAR* Section, const TCHAR* Name, TCHAR* Data, int DataSize, const TCHAR* Default);
extern int CfgReadInt(const TCHAR* Section, const TCHAR* Name, int Default);
extern float CfgReadFloat(const TCHAR* Section, const TCHAR* Name, float Default);
extern bool CfgReadBool(const TCHAR *Section, const TCHAR *Name, bool Default);
extern void CfgReadStr(const TCHAR *Section, const TCHAR *Name, wxString &Data, const TCHAR *Default);
extern void CfgReadStr(const TCHAR *Section, const TCHAR *Name, TCHAR *Data, int DataSize, const TCHAR *Default);
extern int CfgReadInt(const TCHAR *Section, const TCHAR *Name, int Default);
extern float CfgReadFloat(const TCHAR *Section, const TCHAR *Name, float Default);
// Items Specific to DirectSound
#define STRFY(x) #x
#define verifyc(x) Verifyc(x,STRFY(x))
#define verifyc(x) Verifyc(x, STRFY(x))
extern void Verifyc(HRESULT hr, const char* fn);
extern void Verifyc(HRESULT hr, const char *fn);
struct ds_device_data
{
wxString name;
GUID guid;
bool hasGuid;
wxString name;
GUID guid;
bool hasGuid;
};

View File

@ -18,75 +18,72 @@
#include "Global.h"
#include "Dialogs.h"
bool debugDialogOpen=false;
HWND hDebugDialog=NULL;
bool debugDialogOpen = false;
HWND hDebugDialog = NULL;
#ifdef PCSX2_DEVBUILD
int FillRectangle(HDC dc, int left, int top, int width, int height)
{
RECT r = { left, top, left+width, top+height };
RECT r = {left, top, left + width, top + height};
return FillRect(dc, &r, (HBRUSH)GetStockObject(DC_BRUSH));
return FillRect(dc, &r, (HBRUSH)GetStockObject(DC_BRUSH));
}
BOOL DrawRectangle(HDC dc, int left, int top, int width, int height)
{
RECT r = { left, top, left+width, top+height };
RECT r = {left, top, left + width, top + height};
POINT p[5] = {
{ r.left, r.top },
{ r.right, r.top },
{ r.right, r.bottom },
{ r.left, r.bottom },
{ r.left, r.top },
};
POINT p[5] = {
{r.left, r.top},
{r.right, r.top},
{r.right, r.bottom},
{r.left, r.bottom},
{r.left, r.top},
};
return Polyline(dc, p, 5);
return Polyline(dc, p, 5);
}
HFONT hf = NULL;
int lCount=0;
int lCount = 0;
void UpdateDebugDialog()
{
if(!debugDialogOpen) return;
if (!debugDialogOpen)
return;
lCount++;
if(lCount>=(SampleRate/100)) // Increase to SampleRate/200 for smooth display.
{
HDC hdc = GetDC(hDebugDialog);
lCount++;
if (lCount >= (SampleRate / 100)) // Increase to SampleRate/200 for smooth display.
{
HDC hdc = GetDC(hDebugDialog);
if(!hf)
{
hf = CreateFont( 12, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Lucida Console" );
}
if (!hf) {
hf = CreateFont(12, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Lucida Console");
}
SelectObject(hdc,hf);
SelectObject(hdc,GetStockObject(DC_BRUSH));
SelectObject(hdc,GetStockObject(DC_PEN));
SelectObject(hdc, hf);
SelectObject(hdc, GetStockObject(DC_BRUSH));
SelectObject(hdc, GetStockObject(DC_PEN));
for(int c=0;c<2;c++)
{
V_Core& cx(Cores[c]);
V_CoreDebug& cd(DebugCores[c]);
for (int c = 0; c < 2; c++) {
V_Core &cx(Cores[c]);
V_CoreDebug &cd(DebugCores[c]);
for(int v=0;v<24;v++)
{
int cc = c*2 + (v/12);
int vv = v % 12;
int IX = 8+128*cc;
int IY = 8+ 48*vv;
V_Voice& vc(cx.Voices[v]);
V_VoiceDebug& vcd(cd.Voices[v] );
for (int v = 0; v < 24; v++) {
int cc = c * 2 + (v / 12);
int vv = v % 12;
int IX = 8 + 128 * cc;
int IY = 8 + 48 * vv;
V_Voice &vc(cx.Voices[v]);
V_VoiceDebug &vcd(cd.Voices[v]);
SetDCBrushColor(hdc,RGB( 0, 0, 0));
if((vc.ADSR.Phase>0)&&(vc.ADSR.Phase<6))
{
SetDCBrushColor(hdc,RGB( 0, 0,128));
}
/*
SetDCBrushColor(hdc, RGB(0, 0, 0));
if ((vc.ADSR.Phase > 0) && (vc.ADSR.Phase < 6)) {
SetDCBrushColor(hdc, RGB(0, 0, 128));
}
/*
else
{
if(vcd.lastStopReason==1)
@ -99,181 +96,168 @@ void UpdateDebugDialog()
}
}*/
FillRectangle(hdc,IX,IY,124,46);
FillRectangle(hdc, IX, IY, 124, 46);
SetDCPenColor(hdc,RGB( 255, 128, 32));
SetDCPenColor(hdc, RGB(255, 128, 32));
DrawRectangle(hdc,IX,IY,124,46);
DrawRectangle(hdc, IX, IY, 124, 46);
SetDCBrushColor(hdc,RGB( 0,255, 0));
SetDCBrushColor(hdc, RGB(0, 255, 0));
int vl = abs(((vc.Volume.Left.Value >> 16) * 38) >> 15);
int vr = abs(((vc.Volume.Right.Value >> 16) * 38) >> 15);
int vl = abs(((vc.Volume.Left.Value >> 16) * 38) >> 15);
int vr = abs(((vc.Volume.Right.Value >> 16) * 38) >> 15);
FillRectangle(hdc,IX+58,IY+42 - vl, 4, vl);
FillRectangle(hdc,IX+62,IY+42 - vr, 4, vr);
FillRectangle(hdc, IX + 58, IY + 42 - vl, 4, vl);
FillRectangle(hdc, IX + 62, IY + 42 - vr, 4, vr);
int adsr = ((vc.ADSR.Value>>16) * 38) / 32768;
int adsr = ((vc.ADSR.Value >> 16) * 38) / 32768;
FillRectangle(hdc,IX+66,IY+42 - adsr, 4, adsr);
FillRectangle(hdc, IX + 66, IY + 42 - adsr, 4, adsr);
int peak = (vcd.displayPeak * 38) / 32768;
int peak = (vcd.displayPeak * 38) / 32768;
if(vcd.displayPeak >= 32700) // leave a little bit of margin
{
SetDCBrushColor(hdc,RGB( 255, 0, 0));
}
if (vcd.displayPeak >= 32700) // leave a little bit of margin
{
SetDCBrushColor(hdc, RGB(255, 0, 0));
}
FillRectangle(hdc,IX+70,IY+42 - peak, 4, peak);
FillRectangle(hdc, IX + 70, IY + 42 - peak, 4, peak);
if(vc.ADSR.Value>0)
{
if(vc.SBuffer)
for(int i=0;i<28;i++)
{
int val = ((int)vc.SBuffer[i] * 20) / 32768;
if (vc.ADSR.Value > 0) {
if (vc.SBuffer)
for (int i = 0; i < 28; i++) {
int val = ((int)vc.SBuffer[i] * 20) / 32768;
int y=0;
int y = 0;
if(val>0)
{
y=val;
}
else
val=-val;
if(val!=0)
{
FillRectangle(hdc,IX+90+i,IY+24-y, 1, val);
}
}
}
if (val > 0) {
y = val;
} else
val = -val;
SetTextColor(hdc,RGB( 0,255, 0));
SetBkColor (hdc,RGB( 0, 0, 0));
if (val != 0) {
FillRectangle(hdc, IX + 90 + i, IY + 24 - y, 1, val);
}
}
}
static wchar_t t[256];
SetTextColor(hdc, RGB(0, 255, 0));
SetBkColor(hdc, RGB(0, 0, 0));
swprintf_s(t,L"%06x",vc.StartA);
TextOut(hdc,IX+4,IY+4,t,6);
static wchar_t t[256];
swprintf_s(t,L"%06x",vc.NextA);
TextOut(hdc,IX+4,IY+18,t,6);
swprintf_s(t, L"%06x", vc.StartA);
TextOut(hdc, IX + 4, IY + 4, t, 6);
swprintf_s(t,L"%06x",vc.LoopStartA);
TextOut(hdc,IX+4,IY+32,t,6);
swprintf_s(t, L"%06x", vc.NextA);
TextOut(hdc, IX + 4, IY + 18, t, 6);
vcd.displayPeak = 0;
}
swprintf_s(t, L"%06x", vc.LoopStartA);
TextOut(hdc, IX + 4, IY + 32, t, 6);
// top now: 400
int JX = 8 + c * 256;
int JY = 584;
vcd.displayPeak = 0;
}
SetDCBrushColor(hdc,RGB( 0, 0, 0));
SetDCPenColor(hdc,RGB( 255, 128, 32));
// top now: 400
int JX = 8 + c * 256;
int JY = 584;
FillRectangle(hdc,JX,JY,252,60);
DrawRectangle(hdc,JX,JY,252,60);
SetDCBrushColor(hdc, RGB(0, 0, 0));
SetDCPenColor(hdc, RGB(255, 128, 32));
SetTextColor(hdc,RGB(255,255,255));
SetBkColor (hdc,RGB( 0, 0, 0));
FillRectangle(hdc, JX, JY, 252, 60);
DrawRectangle(hdc, JX, JY, 252, 60);
static wchar_t t[256];
TextOut(hdc,JX+4,JY+ 4,L"REVB",4);
TextOut(hdc,JX+4,JY+18,L"IRQE",4);
TextOut(hdc,JX+4,JY+32,L"ADMA",4);
swprintf_s(t,L"DMA%s",c==0 ? L"4" : L"7");
TextOut(hdc,JX+4,JY+46,t, 4);
SetTextColor(hdc,RGB( 0,255, 0));
memset(t, 0, sizeof(t));
swprintf_s(t,L"ESA %x",cx.EffectsStartA);
TextOut(hdc,JX+56,JY+ 4,t, 9);
memset(t, 0, sizeof(t));
swprintf_s(t,L"EEA %x",cx.EffectsEndA);
TextOut(hdc,JX+128,JY+ 4,t, 9);
SetTextColor(hdc, RGB(255, 255, 255));
SetBkColor(hdc, RGB(0, 0, 0));
static wchar_t t[256];
TextOut(hdc, JX + 4, JY + 4, L"REVB", 4);
TextOut(hdc, JX + 4, JY + 18, L"IRQE", 4);
TextOut(hdc, JX + 4, JY + 32, L"ADMA", 4);
swprintf_s(t, L"DMA%s", c == 0 ? L"4" : L"7");
TextOut(hdc, JX + 4, JY + 46, t, 4);
SetTextColor(hdc, RGB(0, 255, 0));
memset(t, 0, sizeof(t));
swprintf_s(t,L"(%x)",cx.EffectsBufferSize);
TextOut(hdc,JX+200,JY+ 4,t,7);
swprintf_s(t, L"ESA %x", cx.EffectsStartA);
TextOut(hdc, JX + 56, JY + 4, t, 9);
memset(t, 0, sizeof(t));
swprintf_s(t, L"EEA %x", cx.EffectsEndA);
TextOut(hdc, JX + 128, JY + 4, t, 9);
memset(t, 0, sizeof(t));
swprintf_s(t, L"(%x)", cx.EffectsBufferSize);
TextOut(hdc, JX + 200, JY + 4, t, 7);
memset(t, 0, sizeof(t));
swprintf_s(t,L"IRQA %x",cx.IRQA);
TextOut(hdc,JX+56,JY+18,t, 12);
swprintf_s(t, L"IRQA %x", cx.IRQA);
TextOut(hdc, JX + 56, JY + 18, t, 12);
SetTextColor(hdc,RGB(255,255,255));
SetDCBrushColor(hdc,RGB( 255,0, 0));
SetTextColor(hdc, RGB(255, 255, 255));
SetDCBrushColor(hdc, RGB(255, 0, 0));
if(cx.FxEnable)
{
FillRectangle(hdc,JX+40,JY+4,10,10);
}
if(cx.IRQEnable)
{
FillRectangle(hdc,JX+40,JY+18,10,10);
}
if(cx.AutoDMACtrl != 0)
{
FillRectangle(hdc,JX+40,JY+32,10,10);
if (cx.FxEnable) {
FillRectangle(hdc, JX + 40, JY + 4, 10, 10);
}
if (cx.IRQEnable) {
FillRectangle(hdc, JX + 40, JY + 18, 10, 10);
}
if (cx.AutoDMACtrl != 0) {
FillRectangle(hdc, JX + 40, JY + 32, 10, 10);
for(int j=0;j<64;j++)
{
int i=j*256/64;
int val = (cd.admaWaveformL[i] * 26) / 32768;
int y=0;
for (int j = 0; j < 64; j++) {
int i = j * 256 / 64;
int val = (cd.admaWaveformL[i] * 26) / 32768;
int y = 0;
if(val>0)
y=val;
else
val=-val;
if (val > 0)
y = val;
else
val = -val;
if(val!=0)
{
FillRectangle(hdc,JX+60+j,JY+30-y, 1, val);
}
}
if (val != 0) {
FillRectangle(hdc, JX + 60 + j, JY + 30 - y, 1, val);
}
}
for(int j=0;j<64;j++)
{
int i=j*256/64;
int val = (cd.admaWaveformR[i] * 26) / 32768;
int y=0;
for (int j = 0; j < 64; j++) {
int i = j * 256 / 64;
int val = (cd.admaWaveformR[i] * 26) / 32768;
int y = 0;
if(val>0)
y=val;
else
val=-val;
if (val > 0)
y = val;
else
val = -val;
if(val!=0)
{
FillRectangle(hdc,JX+136+j,JY+30-y, 1, val);
}
}
}
if(cd.dmaFlag > 0) // So it shows x times this is called, since dmas are so fast
{
swprintf_s(t,L"size = %d",cd.lastsize);
TextOut(hdc,JX+64,JY+46,t,wcslen(t));
FillRectangle(hdc,JX+40,JY+46,10,10);
cd.dmaFlag--;
}
}
if (val != 0) {
FillRectangle(hdc, JX + 136 + j, JY + 30 - y, 1, val);
}
}
}
if (cd.dmaFlag > 0) // So it shows x times this is called, since dmas are so fast
{
swprintf_s(t, L"size = %d", cd.lastsize);
ReleaseDC(hDebugDialog,hdc);
lCount=0;
}
TextOut(hdc, JX + 64, JY + 46, t, wcslen(t));
FillRectangle(hdc, JX + 40, JY + 46, 10, 10);
cd.dmaFlag--;
}
}
MSG msg;
while(PeekMessage(&msg,hDebugDialog,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
ReleaseDC(hDebugDialog, hdc);
lCount = 0;
}
MSG msg;
while (PeekMessage(&msg, hDebugDialog, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#else
void UpdateDebugDialog()
{
// Release mode. Nothing to do
// Release mode. Nothing to do
}
#endif

View File

@ -26,458 +26,431 @@
class DSound : public SndOutModule
{
private:
static const uint MAX_BUFFER_COUNT = 8;
static const int PacketsPerBuffer = 8;
static const int BufferSize = SndOutPacketSize * PacketsPerBuffer;
static const uint MAX_BUFFER_COUNT = 8;
static const int PacketsPerBuffer = 8;
static const int BufferSize = SndOutPacketSize * PacketsPerBuffer;
//////////////////////////////////////////////////////////////////////////////////////////
// Configuration Vars
//////////////////////////////////////////////////////////////////////////////////////////
// Configuration Vars
wxString m_Device;
u8 m_NumBuffers;
bool m_DisableGlobalFocus;
bool m_UseHardware;
wxString m_Device;
u8 m_NumBuffers;
bool m_DisableGlobalFocus;
bool m_UseHardware;
ds_device_data m_devices[32];
int ndevs;
GUID DevGuid; // currently employed GUID.
bool haveGuid;
ds_device_data m_devices[32];
int ndevs;
GUID DevGuid; // currently employed GUID.
bool haveGuid;
//////////////////////////////////////////////////////////////////////////////////////////
// Instance vars
//////////////////////////////////////////////////////////////////////////////////////////
// Instance vars
int channel;
int myLastWrite; // last write position, in bytes
int channel;
int myLastWrite; // last write position, in bytes
bool dsound_running;
HANDLE thread;
DWORD tid;
bool dsound_running;
HANDLE thread;
DWORD tid;
IDirectSound8* dsound;
IDirectSoundBuffer8* buffer;
IDirectSoundNotify8* buffer_notify;
HANDLE buffer_events[MAX_BUFFER_COUNT];
IDirectSound8 *dsound;
IDirectSoundBuffer8 *buffer;
IDirectSoundNotify8 *buffer_notify;
HANDLE buffer_events[MAX_BUFFER_COUNT];
WAVEFORMATEX wfx;
WAVEFORMATEX wfx;
HANDLE waitEvent;
HANDLE waitEvent;
template< typename T >
static DWORD CALLBACK RThread( DSound* obj )
{
return obj->Thread<T>();
}
template <typename T>
static DWORD CALLBACK RThread(DSound *obj)
{
return obj->Thread<T>();
}
template< typename T >
DWORD CALLBACK Thread()
{
static const int BufferSizeBytes = BufferSize * sizeof( T );
template <typename T>
DWORD CALLBACK Thread()
{
static const int BufferSizeBytes = BufferSize * sizeof(T);
while( dsound_running )
{
u32 rv = WaitForMultipleObjects(m_NumBuffers,buffer_events,FALSE,200);
while (dsound_running) {
u32 rv = WaitForMultipleObjects(m_NumBuffers, buffer_events, FALSE, 200);
T* p1, *oldp1;
LPVOID p2;
DWORD s1,s2;
T *p1, *oldp1;
LPVOID p2;
DWORD s1, s2;
u32 poffset = BufferSizeBytes * rv;
u32 poffset = BufferSizeBytes * rv;
if( FAILED(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0) ) )
{
assert( 0 );
fputs( "* SPU2-X: Directsound Warning > Buffer lock failure. You may need to increase\n\tyour configured DSound buffer count.\n", stderr );
continue;
}
oldp1 = p1;
if (FAILED(buffer->Lock(poffset, BufferSizeBytes, (LPVOID *)&p1, &s1, &p2, &s2, 0))) {
assert(0);
fputs("* SPU2-X: Directsound Warning > Buffer lock failure. You may need to increase\n\tyour configured DSound buffer count.\n", stderr);
continue;
}
oldp1 = p1;
for(int p=0; p<PacketsPerBuffer; p++, p1+=SndOutPacketSize )
SndBuffer::ReadSamples( p1 );
for (int p = 0; p < PacketsPerBuffer; p++, p1 += SndOutPacketSize)
SndBuffer::ReadSamples(p1);
buffer->Unlock( oldp1, s1, p2, s2 );
buffer->Unlock(oldp1, s1, p2, s2);
// Set the write pointer to the beginning of the next block.
myLastWrite = (poffset + BufferSizeBytes) & ~BufferSizeBytes;
}
return 0;
}
// Set the write pointer to the beginning of the next block.
myLastWrite = (poffset + BufferSizeBytes) & ~BufferSizeBytes;
}
return 0;
}
public:
s32 Init()
{
CoInitializeEx( NULL, COINIT_MULTITHREADED );
s32 Init()
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
//
// Initialize DSound
//
GUID cGuid;
//
// Initialize DSound
//
GUID cGuid;
try
{
if( m_Device.empty() )
throw std::runtime_error( "screw it" );
try {
if (m_Device.empty())
throw std::runtime_error("screw it");
if ((FAILED(GUIDFromString(m_Device, &cGuid))) ||
FAILED( DirectSoundCreate8(&cGuid,&dsound,NULL) ) )
throw std::runtime_error( "try again?" );
}
catch( std::runtime_error& )
{
// if the GUID failed, just open up the default dsound driver:
if( FAILED(DirectSoundCreate8(NULL,&dsound,NULL) ) )
throw std::runtime_error( "DirectSound failed to initialize!" );
}
if ((FAILED(GUIDFromString(m_Device, &cGuid))) ||
FAILED(DirectSoundCreate8(&cGuid, &dsound, NULL)))
throw std::runtime_error("try again?");
} catch (std::runtime_error &) {
// if the GUID failed, just open up the default dsound driver:
if (FAILED(DirectSoundCreate8(NULL, &dsound, NULL)))
throw std::runtime_error("DirectSound failed to initialize!");
}
if( FAILED(dsound->SetCooperativeLevel(GetDesktopWindow(),DSSCL_PRIORITY)) )
throw std::runtime_error( "DirectSound Error: Cooperative level could not be set." );
if (FAILED(dsound->SetCooperativeLevel(GetDesktopWindow(), DSSCL_PRIORITY)))
throw std::runtime_error("DirectSound Error: Cooperative level could not be set.");
// Determine the user's speaker configuration, and select an expansion option as needed.
// FAIL : Directsound doesn't appear to support audio expansion >_<
// Determine the user's speaker configuration, and select an expansion option as needed.
// FAIL : Directsound doesn't appear to support audio expansion >_<
DWORD speakerConfig = 2;
//dsound->GetSpeakerConfig( &speakerConfig );
DWORD speakerConfig = 2;
//dsound->GetSpeakerConfig( &speakerConfig );
IDirectSoundBuffer* buffer_;
DSBUFFERDESC desc;
IDirectSoundBuffer *buffer_;
DSBUFFERDESC desc;
// Set up WAV format structure.
// Set up WAV format structure.
memset(&wfx, 0, sizeof(WAVEFORMATEX));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nSamplesPerSec = SampleRate;
wfx.nChannels = (WORD)speakerConfig;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = 2*(WORD)speakerConfig;
wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign;
wfx.cbSize = 0;
memset(&wfx, 0, sizeof(WAVEFORMATEX));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nSamplesPerSec = SampleRate;
wfx.nChannels = (WORD)speakerConfig;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = 2 * (WORD)speakerConfig;
wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign;
wfx.cbSize = 0;
uint BufferSizeBytes = BufferSize * wfx.nBlockAlign;
uint BufferSizeBytes = BufferSize * wfx.nBlockAlign;
// Set up DSBUFFERDESC structure.
// Set up DSBUFFERDESC structure.
memset(&desc, 0, sizeof(DSBUFFERDESC));
desc.dwSize = sizeof(DSBUFFERDESC);
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;
desc.dwBufferBytes = BufferSizeBytes * m_NumBuffers;
desc.lpwfxFormat = &wfx;
memset(&desc, 0, sizeof(DSBUFFERDESC));
desc.dwSize = sizeof(DSBUFFERDESC);
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;
desc.dwBufferBytes = BufferSizeBytes * m_NumBuffers;
desc.lpwfxFormat = &wfx;
// Try a hardware buffer first, and then fall back on a software buffer if
// that one fails.
// Try a hardware buffer first, and then fall back on a software buffer if
// that one fails.
desc.dwFlags |= m_UseHardware ? DSBCAPS_LOCHARDWARE : DSBCAPS_LOCSOFTWARE;
desc.dwFlags |= m_DisableGlobalFocus ? DSBCAPS_STICKYFOCUS : DSBCAPS_GLOBALFOCUS;
desc.dwFlags |= m_UseHardware ? DSBCAPS_LOCHARDWARE : DSBCAPS_LOCSOFTWARE;
desc.dwFlags |= m_DisableGlobalFocus ? DSBCAPS_STICKYFOCUS : DSBCAPS_GLOBALFOCUS;
if( FAILED(dsound->CreateSoundBuffer(&desc, &buffer_, 0) ) )
{
if( m_UseHardware )
{
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_LOCSOFTWARE;
desc.dwFlags |= m_DisableGlobalFocus ? DSBCAPS_STICKYFOCUS : DSBCAPS_GLOBALFOCUS;
if (FAILED(dsound->CreateSoundBuffer(&desc, &buffer_, 0))) {
if (m_UseHardware) {
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_LOCSOFTWARE;
desc.dwFlags |= m_DisableGlobalFocus ? DSBCAPS_STICKYFOCUS : DSBCAPS_GLOBALFOCUS;
if( FAILED(dsound->CreateSoundBuffer(&desc, &buffer_, 0) ) )
throw std::runtime_error( "DirectSound Error: Buffer could not be created." );
}
if (FAILED(dsound->CreateSoundBuffer(&desc, &buffer_, 0)))
throw std::runtime_error("DirectSound Error: Buffer could not be created.");
}
throw std::runtime_error( "DirectSound Error: Buffer could not be created." );
}
if( FAILED(buffer_->QueryInterface(IID_IDirectSoundBuffer8,(void**)&buffer)) || buffer == NULL )
throw std::runtime_error( "DirectSound Error: Interface could not be queried." );
throw std::runtime_error("DirectSound Error: Buffer could not be created.");
}
if (FAILED(buffer_->QueryInterface(IID_IDirectSoundBuffer8, (void **)&buffer)) || buffer == NULL)
throw std::runtime_error("DirectSound Error: Interface could not be queried.");
buffer_->Release();
verifyc( buffer->QueryInterface(IID_IDirectSoundNotify8,(void**)&buffer_notify) );
buffer_->Release();
verifyc(buffer->QueryInterface(IID_IDirectSoundNotify8, (void **)&buffer_notify));
DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT];
DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT];
for(uint i=0;i<m_NumBuffers;i++)
{
buffer_events[i] = CreateEvent(NULL,FALSE,FALSE,NULL);
not[i].dwOffset = (wfx.nBlockAlign + BufferSizeBytes*(i+1)) % desc.dwBufferBytes;
not[i].hEventNotify = buffer_events[i];
}
for (uint i = 0; i < m_NumBuffers; i++) {
buffer_events[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
not[i].dwOffset = (wfx.nBlockAlign + BufferSizeBytes * (i + 1)) % desc.dwBufferBytes;
not[i].hEventNotify = buffer_events[i];
}
buffer_notify->SetNotificationPositions(m_NumBuffers,not);
buffer_notify->SetNotificationPositions(m_NumBuffers, not);
LPVOID p1=0,p2=0;
DWORD s1=0,s2=0;
LPVOID p1 = 0, p2 = 0;
DWORD s1 = 0, s2 = 0;
verifyc(buffer->Lock(0,desc.dwBufferBytes,&p1,&s1,&p2,&s2,0));
assert(p2==0);
memset(p1,0,s1);
verifyc(buffer->Unlock(p1,s1,p2,s2));
verifyc(buffer->Lock(0, desc.dwBufferBytes, &p1, &s1, &p2, &s2, 0));
assert(p2 == 0);
memset(p1, 0, s1);
verifyc(buffer->Unlock(p1, s1, p2, s2));
//Play the buffer !
verifyc(buffer->Play(0,0,DSBPLAY_LOOPING));
//Play the buffer !
verifyc(buffer->Play(0, 0, DSBPLAY_LOOPING));
// Start Thread
myLastWrite = 0;
dsound_running = true;
thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread<StereoOut16>,this,0,&tid);
SetThreadPriority(thread,THREAD_PRIORITY_ABOVE_NORMAL);
// Start Thread
myLastWrite = 0;
dsound_running = true;
thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RThread<StereoOut16>, this, 0, &tid);
SetThreadPriority(thread, THREAD_PRIORITY_ABOVE_NORMAL);
return 0;
}
return 0;
}
void Close()
{
// Stop Thread
fprintf(stderr,"* SPU2-X: Waiting for DSound thread to finish...");
dsound_running=false;
void Close()
{
// Stop Thread
fprintf(stderr, "* SPU2-X: Waiting for DSound thread to finish...");
dsound_running = false;
WaitForSingleObject(thread,INFINITE);
CloseHandle(thread);
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
fprintf(stderr," Done.\n");
fprintf(stderr, " Done.\n");
//
// Clean up
//
if( buffer != NULL )
{
buffer->Stop();
//
// Clean up
//
if (buffer != NULL) {
buffer->Stop();
for(u32 i=0;i<m_NumBuffers;i++)
{
if( buffer_events[i] != NULL )
CloseHandle(buffer_events[i]);
buffer_events[i] = NULL;
}
for (u32 i = 0; i < m_NumBuffers; i++) {
if (buffer_events[i] != NULL)
CloseHandle(buffer_events[i]);
buffer_events[i] = NULL;
}
safe_release( buffer_notify );
safe_release( buffer );
}
safe_release(buffer_notify);
safe_release(buffer);
}
safe_release( dsound );
CoUninitialize();
}
safe_release(dsound);
CoUninitialize();
}
private:
bool _DSEnumCallback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext)
{
m_devices[ndevs].name = lpcstrDescription;
bool _DSEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext )
{
m_devices[ndevs].name = lpcstrDescription;
if (lpGuid) {
m_devices[ndevs].guid = *lpGuid;
m_devices[ndevs].hasGuid = true;
} else {
m_devices[ndevs].hasGuid = false;
}
ndevs++;
if(lpGuid)
{
m_devices[ndevs].guid = *lpGuid;
m_devices[ndevs].hasGuid = true;
}
else
{
m_devices[ndevs].hasGuid = false;
}
ndevs++;
if (ndevs < 32)
return TRUE;
return FALSE;
}
if(ndevs<32) return TRUE;
return FALSE;
}
bool _ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
int tSel = 0;
bool _ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
int wmId,wmEvent;
int tSel = 0;
switch (uMsg) {
case WM_INITDIALOG: {
wchar_t temp[128];
switch(uMsg)
{
case WM_INITDIALOG:
{
wchar_t temp[128];
haveGuid = !FAILED(GUIDFromString(m_Device, &DevGuid));
SendMessage(GetDlgItem(hWnd, IDC_DS_DEVICE), CB_RESETCONTENT, 0, 0);
haveGuid = !FAILED(GUIDFromString(m_Device, &DevGuid));
SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_RESETCONTENT,0,0);
ndevs = 0;
DirectSoundEnumerate(DSEnumCallback, NULL);
ndevs=0;
DirectSoundEnumerate( DSEnumCallback, NULL );
tSel = -1;
for (int i = 0; i < ndevs; i++) {
SendMessage(GetDlgItem(hWnd, IDC_DS_DEVICE), CB_ADDSTRING, 0, (LPARAM)m_devices[i].name.wc_str());
if (haveGuid && IsEqualGUID(m_devices[i].guid, DevGuid) || tSel < 0 && !m_devices[i].hasGuid)
tSel = i;
}
tSel=-1;
for(int i=0;i<ndevs;i++)
{
SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_ADDSTRING,0,(LPARAM)m_devices[i].name.wc_str());
if(haveGuid && IsEqualGUID(m_devices[i].guid,DevGuid) || tSel < 0 && !m_devices[i].hasGuid)
tSel = i;
}
if (tSel >= 0)
SendMessage(GetDlgItem(hWnd, IDC_DS_DEVICE), CB_SETCURSEL, tSel, 0);
if(tSel>=0)
SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_SETCURSEL,tSel,0);
INIT_SLIDER(IDC_BUFFERS_SLIDER, 2, MAX_BUFFER_COUNT, 2, 1, 1);
SendMessage(GetDlgItem(hWnd, IDC_BUFFERS_SLIDER), TBM_SETPOS, TRUE, m_NumBuffers);
swprintf_s(temp, L"%d (%d ms latency)", m_NumBuffers, 1000 / (96000 / (m_NumBuffers * BufferSize)));
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
INIT_SLIDER( IDC_BUFFERS_SLIDER, 2, MAX_BUFFER_COUNT, 2, 1, 1 );
SendMessage(GetDlgItem(hWnd,IDC_BUFFERS_SLIDER),TBM_SETPOS,TRUE,m_NumBuffers);
swprintf_s(temp, L"%d (%d ms latency)",m_NumBuffers, 1000 / (96000 / (m_NumBuffers * BufferSize)));
SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp);
SET_CHECK(IDC_GLOBALFOCUS_DISABLE, m_DisableGlobalFocus);
SET_CHECK(IDC_USE_HARDWARE, m_UseHardware);
} break;
SET_CHECK( IDC_GLOBALFOCUS_DISABLE, m_DisableGlobalFocus );
SET_CHECK( IDC_USE_HARDWARE, m_UseHardware );
}
break;
case WM_COMMAND: {
wchar_t temp[128];
case WM_COMMAND:
{
wchar_t temp[128];
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId) {
case IDOK: {
int i = (int)SendMessage(GetDlgItem(hWnd, IDC_DS_DEVICE), CB_GETCURSEL, 0, 0);
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDOK:
{
int i = (int)SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_GETCURSEL,0,0);
if (!m_devices[i].hasGuid) {
m_Device[0] = 0; // clear device name to ""
} else {
swprintf_s(temp, L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
m_devices[i].guid.Data1,
m_devices[i].guid.Data2,
m_devices[i].guid.Data3,
m_devices[i].guid.Data4[0],
m_devices[i].guid.Data4[1],
m_devices[i].guid.Data4[2],
m_devices[i].guid.Data4[3],
m_devices[i].guid.Data4[4],
m_devices[i].guid.Data4[5],
m_devices[i].guid.Data4[6],
m_devices[i].guid.Data4[7]);
m_Device = temp;
}
if(!m_devices[i].hasGuid)
{
m_Device[0] = 0; // clear device name to ""
}
else
{
swprintf_s(temp, L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
m_devices[i].guid.Data1,
m_devices[i].guid.Data2,
m_devices[i].guid.Data3,
m_devices[i].guid.Data4[0],
m_devices[i].guid.Data4[1],
m_devices[i].guid.Data4[2],
m_devices[i].guid.Data4[3],
m_devices[i].guid.Data4[4],
m_devices[i].guid.Data4[5],
m_devices[i].guid.Data4[6],
m_devices[i].guid.Data4[7]
);
m_Device = temp;
}
m_NumBuffers = (int)SendMessage(GetDlgItem(hWnd, IDC_BUFFERS_SLIDER), TBM_GETPOS, 0, 0);
m_NumBuffers = (int)SendMessage( GetDlgItem( hWnd, IDC_BUFFERS_SLIDER ), TBM_GETPOS, 0, 0 );
if (m_NumBuffers < 2)
m_NumBuffers = 2;
if (m_NumBuffers > MAX_BUFFER_COUNT)
m_NumBuffers = MAX_BUFFER_COUNT;
if( m_NumBuffers < 2 ) m_NumBuffers = 2;
if( m_NumBuffers > MAX_BUFFER_COUNT ) m_NumBuffers = MAX_BUFFER_COUNT;
EndDialog(hWnd, 0);
} break;
EndDialog(hWnd,0);
}
break;
case IDCANCEL:
EndDialog(hWnd, 0);
break;
case IDCANCEL:
EndDialog(hWnd,0);
break;
HANDLE_CHECK(IDC_GLOBALFOCUS_DISABLE, m_DisableGlobalFocus);
HANDLE_CHECK(IDC_USE_HARDWARE, m_UseHardware);
HANDLE_CHECK( IDC_GLOBALFOCUS_DISABLE, m_DisableGlobalFocus );
HANDLE_CHECK( IDC_USE_HARDWARE, m_UseHardware );
default:
return FALSE;
}
} break;
default:
return FALSE;
}
}
break;
case WM_HSCROLL: {
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId) {
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
wmEvent = (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
case TB_THUMBTRACK: {
wchar_t temp[128];
if (wmEvent < 2)
wmEvent = 2;
if (wmEvent > MAX_BUFFER_COUNT)
wmEvent = MAX_BUFFER_COUNT;
SendMessage((HWND)lParam, TBM_SETPOS, TRUE, wmEvent);
swprintf_s(temp, L"%d (%d ms latency)", wmEvent, 1000 / (96000 / (wmEvent * BufferSize)));
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
break;
}
default:
return FALSE;
}
} break;
case WM_HSCROLL:
{
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch(wmId)
{
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
wmEvent = (int)SendMessage((HWND)lParam,TBM_GETPOS,0,0);
case TB_THUMBTRACK:
{
wchar_t temp[128];
if( wmEvent < 2 ) wmEvent = 2;
if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT;
SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent);
swprintf_s(temp,L"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize)));
SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp);
break;
}
default:
return FALSE;
}
}
break;
default:
return FALSE;
}
return TRUE;
}
default:
return FALSE;
}
return TRUE;
}
static BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
static BOOL CALLBACK DSEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext );
static BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK DSEnumCallback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext);
public:
virtual void Configure(uptr parent)
{
INT_PTR ret;
ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DSOUND),(HWND)parent,(DLGPROC)ConfigProc,1);
if(ret==-1)
{
MessageBox((HWND)parent,L"Error Opening the config dialog.",L"OMG ERROR!",MB_OK | MB_SETFOREGROUND);
return;
}
}
s32 Test() const
{
return 0;
}
virtual void Configure(uptr parent)
{
INT_PTR ret;
ret = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_DSOUND), (HWND)parent, (DLGPROC)ConfigProc, 1);
if (ret == -1) {
MessageBox((HWND)parent, L"Error Opening the config dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
}
int GetEmptySampleCount()
{
DWORD play, write;
buffer->GetCurrentPosition( &play, &write );
s32 Test() const
{
return 0;
}
// Note: Dsound's write cursor is bogus. Use our own instead:
int GetEmptySampleCount()
{
DWORD play, write;
buffer->GetCurrentPosition(&play, &write);
int empty = play - myLastWrite;
if( empty < 0 )
empty = -empty;
// Note: Dsound's write cursor is bogus. Use our own instead:
return empty / 2;
}
int empty = play - myLastWrite;
if (empty < 0)
empty = -empty;
const wchar_t* GetIdent() const
{
return L"dsound";
}
return empty / 2;
}
const wchar_t* GetLongName() const
{
return L"DirectSound (nice)";
}
const wchar_t *GetIdent() const
{
return L"dsound";
}
void ReadSettings()
{
CfgReadStr( L"DSOUNDOUT", L"Device", m_Device, L"default" );
m_NumBuffers = CfgReadInt( L"DSOUNDOUT", L"Buffer_Count", 5 );
m_DisableGlobalFocus = CfgReadBool( L"DSOUNDOUT", L"Disable_Global_Focus", false );
m_UseHardware = CfgReadBool( L"DSOUNDOUT", L"Use_Hardware", false );
const wchar_t *GetLongName() const
{
return L"DirectSound (nice)";
}
Clampify( m_NumBuffers, (u8)3, (u8)8 );
}
void ReadSettings()
{
CfgReadStr(L"DSOUNDOUT", L"Device", m_Device, L"default");
m_NumBuffers = CfgReadInt(L"DSOUNDOUT", L"Buffer_Count", 5);
m_DisableGlobalFocus = CfgReadBool(L"DSOUNDOUT", L"Disable_Global_Focus", false);
m_UseHardware = CfgReadBool(L"DSOUNDOUT", L"Use_Hardware", false);
void SetApiSettings(wxString api)
{
}
Clampify(m_NumBuffers, (u8)3, (u8)8);
}
void WriteSettings() const
{
CfgWriteStr( L"DSOUNDOUT", L"Device", m_Device.empty() ? L"default" : m_Device );
CfgWriteInt( L"DSOUNDOUT", L"Buffer_Count", m_NumBuffers );
CfgWriteBool( L"DSOUNDOUT", L"Disable_Global_Focus", m_DisableGlobalFocus );
CfgWriteBool( L"DSOUNDOUT", L"Use_Hardware", m_UseHardware );
}
void SetApiSettings(wxString api)
{
}
void WriteSettings() const
{
CfgWriteStr(L"DSOUNDOUT", L"Device", m_Device.empty() ? L"default" : m_Device);
CfgWriteInt(L"DSOUNDOUT", L"Buffer_Count", m_NumBuffers);
CfgWriteBool(L"DSOUNDOUT", L"Disable_Global_Focus", m_DisableGlobalFocus);
CfgWriteBool(L"DSOUNDOUT", L"Use_Hardware", m_UseHardware);
}
} static DS;
BOOL CALLBACK DSound::ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
BOOL CALLBACK DSound::ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DS._ConfigProc( hWnd, uMsg, wParam, lParam );
return DS._ConfigProc(hWnd, uMsg, wParam, lParam);
}
BOOL CALLBACK DSound::DSEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext )
BOOL CALLBACK DSound::DSEnumCallback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext)
{
pxAssume( DSoundOut != NULL );
return DS._DSEnumCallback( lpGuid, lpcstrDescription, lpcstrModule, lpContext );
pxAssume(DSoundOut != NULL);
return DS._DSEnumCallback(lpGuid, lpcstrDescription, lpcstrModule, lpContext);
}
SndOutModule *DSoundOut = &DS;

View File

@ -26,41 +26,41 @@
namespace Exception
{
class XAudio2Error : public std::runtime_error
{
protected:
static const char* SomeKindaErrorString(HRESULT hr)
{
switch (hr) {
case XAUDIO2_E_INVALID_CALL:
return "Invalid call for the XA2 object state.";
class XAudio2Error : public std::runtime_error
{
protected:
static const char *SomeKindaErrorString(HRESULT hr)
{
switch (hr) {
case XAUDIO2_E_INVALID_CALL:
return "Invalid call for the XA2 object state.";
case XAUDIO2_E_DEVICE_INVALIDATED:
return "Device is unavailable, unplugged, unsupported, or has been consumed by The Nothing.";
}
return "Unknown error code!";
}
case XAUDIO2_E_DEVICE_INVALIDATED:
return "Device is unavailable, unplugged, unsupported, or has been consumed by The Nothing.";
}
return "Unknown error code!";
}
public:
const HRESULT ErrorCode;
std::string m_Message;
public:
const HRESULT ErrorCode;
std::string m_Message;
const char* CMessage() const
{
return m_Message.c_str();
}
const char *CMessage() const
{
return m_Message.c_str();
}
virtual ~XAudio2Error() throw() {}
XAudio2Error(const HRESULT result, const std::string& msg) :
runtime_error(msg),
ErrorCode(result),
m_Message()
{
char omg[1024];
sprintf_s(omg, "%s (code 0x%x)\n\n%s", what(), ErrorCode, SomeKindaErrorString(ErrorCode));
m_Message = omg;
}
};
virtual ~XAudio2Error() throw() {}
XAudio2Error(const HRESULT result, const std::string &msg)
: runtime_error(msg)
, ErrorCode(result)
, m_Message()
{
char omg[1024];
sprintf_s(omg, "%s (code 0x%x)\n\n%s", what(), ErrorCode, SomeKindaErrorString(ErrorCode));
m_Message = omg;
}
};
}
static const double SndOutNormalizer = (double)(1UL << (SndOutVolumeShift + 16));
@ -68,334 +68,364 @@ static const double SndOutNormalizer = (double)(1UL << (SndOutVolumeShift + 16))
class XAudio2Mod : public SndOutModule
{
private:
static const int PacketsPerBuffer = 8;
static const int MAX_BUFFER_COUNT = 3;
static const int PacketsPerBuffer = 8;
static const int MAX_BUFFER_COUNT = 3;
class BaseStreamingVoice : public IXAudio2VoiceCallback
{
protected:
IXAudio2SourceVoice* pSourceVoice;
s16* qbuffer;
class BaseStreamingVoice : public IXAudio2VoiceCallback
{
protected:
IXAudio2SourceVoice *pSourceVoice;
s16 *qbuffer;
const uint m_nBuffers;
const uint m_nChannels;
const uint m_BufferSize;
const uint m_BufferSizeBytes;
const uint m_nBuffers;
const uint m_nChannels;
const uint m_BufferSize;
const uint m_BufferSizeBytes;
CRITICAL_SECTION cs;
CRITICAL_SECTION cs;
public:
int GetEmptySampleCount()
{
XAUDIO2_VOICE_STATE state;
pSourceVoice->GetState(&state);
return state.SamplesPlayed & (m_BufferSize - 1);
}
public:
int GetEmptySampleCount()
{
XAUDIO2_VOICE_STATE state;
pSourceVoice->GetState(&state);
return state.SamplesPlayed & (m_BufferSize - 1);
}
virtual ~BaseStreamingVoice()
{
}
virtual ~BaseStreamingVoice()
{
}
BaseStreamingVoice(uint numChannels) :
m_nBuffers(Config_XAudio2.NumBuffers),
m_nChannels(numChannels),
m_BufferSize(SndOutPacketSize * m_nChannels * PacketsPerBuffer),
m_BufferSizeBytes(m_BufferSize * sizeof(s16))
{
}
BaseStreamingVoice(uint numChannels)
: m_nBuffers(Config_XAudio2.NumBuffers)
, m_nChannels(numChannels)
, m_BufferSize(SndOutPacketSize * m_nChannels * PacketsPerBuffer)
, m_BufferSizeBytes(m_BufferSize * sizeof(s16))
{
}
virtual void Init(IXAudio2* pXAudio2) = 0;
virtual void Init(IXAudio2 *pXAudio2) = 0;
protected:
// Several things must be initialized separate of the constructor, due to the fact that
// virtual calls can't be made from the constructor's context.
void _init(IXAudio2* pXAudio2, uint chanConfig)
{
WAVEFORMATEXTENSIBLE wfx;
protected:
// Several things must be initialized separate of the constructor, due to the fact that
// virtual calls can't be made from the constructor's context.
void _init(IXAudio2 *pXAudio2, uint chanConfig)
{
WAVEFORMATEXTENSIBLE wfx;
memset(&wfx, 0, sizeof(WAVEFORMATEXTENSIBLE));
wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfx.Format.nSamplesPerSec = SampleRate;
wfx.Format.nChannels = m_nChannels;
wfx.Format.wBitsPerSample = 16;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = SampleRate * wfx.Format.nBlockAlign;
wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
wfx.Samples.wValidBitsPerSample = 16;
wfx.dwChannelMask = chanConfig;
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
memset(&wfx, 0, sizeof(WAVEFORMATEXTENSIBLE));
wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfx.Format.nSamplesPerSec = SampleRate;
wfx.Format.nChannels = m_nChannels;
wfx.Format.wBitsPerSample = 16;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = SampleRate * wfx.Format.nBlockAlign;
wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
wfx.Samples.wValidBitsPerSample = 16;
wfx.dwChannelMask = chanConfig;
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
//
// Create an XAudio2 voice to stream this wave
//
HRESULT hr;
if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx,
XAUDIO2_VOICE_NOSRC, 1.0f, this))) {
throw Exception::XAudio2Error(hr, "XAudio2 CreateSourceVoice failure.");
}
//
// Create an XAudio2 voice to stream this wave
//
HRESULT hr;
if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX *)&wfx,
XAUDIO2_VOICE_NOSRC, 1.0f, this))) {
throw Exception::XAudio2Error(hr, "XAudio2 CreateSourceVoice failure.");
}
InitializeCriticalSection(&cs);
EnterCriticalSection(&cs);
InitializeCriticalSection(&cs);
EnterCriticalSection(&cs);
pSourceVoice->FlushSourceBuffers();
pSourceVoice->Start(0, 0);
pSourceVoice->FlushSourceBuffers();
pSourceVoice->Start(0, 0);
qbuffer = new s16[m_nBuffers * m_BufferSize];
ZeroMemory(qbuffer, m_BufferSizeBytes * m_nBuffers);
qbuffer = new s16[m_nBuffers * m_BufferSize];
ZeroMemory(qbuffer, m_BufferSizeBytes * m_nBuffers);
// Start some buffers.
// Start some buffers.
for (uint i = 0; i < m_nBuffers; i++) {
XAUDIO2_BUFFER buf = { 0 };
buf.AudioBytes = m_BufferSizeBytes;
buf.pContext = &qbuffer[i*m_BufferSize];
buf.pAudioData = (BYTE*)buf.pContext;
pSourceVoice->SubmitSourceBuffer(&buf);
}
for (uint i = 0; i < m_nBuffers; i++) {
XAUDIO2_BUFFER buf = {0};
buf.AudioBytes = m_BufferSizeBytes;
buf.pContext = &qbuffer[i * m_BufferSize];
buf.pAudioData = (BYTE *)buf.pContext;
pSourceVoice->SubmitSourceBuffer(&buf);
}
LeaveCriticalSection(&cs);
}
LeaveCriticalSection(&cs);
}
STDMETHOD_(void, OnVoiceProcessingPassStart) () {}
STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) {}
STDMETHOD_(void, OnVoiceProcessingPassEnd) () {}
STDMETHOD_(void, OnStreamEnd) () {}
STDMETHOD_(void, OnBufferStart) (void*) {}
STDMETHOD_(void, OnLoopEnd) (void*) {}
STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) {}
};
STDMETHOD_(void, OnVoiceProcessingPassStart)
() {}
STDMETHOD_(void, OnVoiceProcessingPassStart)
(UINT32) {}
STDMETHOD_(void, OnVoiceProcessingPassEnd)
() {}
STDMETHOD_(void, OnStreamEnd)
() {}
STDMETHOD_(void, OnBufferStart)
(void *) {}
STDMETHOD_(void, OnLoopEnd)
(void *) {}
STDMETHOD_(void, OnVoiceError)
(THIS_ void *pBufferContext, HRESULT Error) {}
};
template< typename T >
class StreamingVoice : public BaseStreamingVoice
{
public:
StreamingVoice(IXAudio2* pXAudio2) :
BaseStreamingVoice(sizeof(T) / sizeof(s16))
{
}
template <typename T>
class StreamingVoice : public BaseStreamingVoice
{
public:
StreamingVoice(IXAudio2 *pXAudio2)
: BaseStreamingVoice(sizeof(T) / sizeof(s16))
{
}
virtual ~StreamingVoice()
{
IXAudio2SourceVoice* killMe = pSourceVoice;
pSourceVoice = NULL;
killMe->FlushSourceBuffers();
killMe->DestroyVoice();
virtual ~StreamingVoice()
{
IXAudio2SourceVoice *killMe = pSourceVoice;
pSourceVoice = NULL;
killMe->FlushSourceBuffers();
killMe->DestroyVoice();
EnterCriticalSection(&cs);
safe_delete_array(qbuffer);
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
}
EnterCriticalSection(&cs);
safe_delete_array(qbuffer);
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
}
void Init(IXAudio2* pXAudio2)
{
int chanMask = 0;
switch (m_nChannels) {
case 1: chanMask |= SPEAKER_FRONT_CENTER; break;
case 2: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break;
case 3: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY; break;
case 4: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break;
case 5: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break;
case 6: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY; break;
case 8: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT | SPEAKER_LOW_FREQUENCY; break;
}
_init(pXAudio2, chanMask);
}
void Init(IXAudio2 *pXAudio2)
{
int chanMask = 0;
switch (m_nChannels) {
case 1:
chanMask |= SPEAKER_FRONT_CENTER;
break;
case 2:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
break;
case 3:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY;
break;
case 4:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
break;
case 5:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
break;
case 6:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
break;
case 8:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT | SPEAKER_LOW_FREQUENCY;
break;
}
_init(pXAudio2, chanMask);
}
protected:
STDMETHOD_(void, OnBufferEnd) (void* context)
{
EnterCriticalSection(&cs);
protected:
STDMETHOD_(void, OnBufferEnd)
(void *context)
{
EnterCriticalSection(&cs);
// All of these checks are necessary because XAudio2 is wonky shizat.
if (pSourceVoice == NULL || context == NULL) {
LeaveCriticalSection(&cs);
return;
}
// All of these checks are necessary because XAudio2 is wonky shizat.
if (pSourceVoice == NULL || context == NULL) {
LeaveCriticalSection(&cs);
return;
}
T* qb = (T*)context;
T *qb = (T *)context;
for (int p = 0; p < PacketsPerBuffer; p++, qb += SndOutPacketSize)
SndBuffer::ReadSamples(qb);
for (int p = 0; p < PacketsPerBuffer; p++, qb += SndOutPacketSize)
SndBuffer::ReadSamples(qb);
XAUDIO2_BUFFER buf = { 0 };
buf.AudioBytes = m_BufferSizeBytes;
buf.pAudioData = (BYTE*)context;
buf.pContext = context;
XAUDIO2_BUFFER buf = {0};
buf.AudioBytes = m_BufferSizeBytes;
buf.pAudioData = (BYTE *)context;
buf.pContext = context;
pSourceVoice->SubmitSourceBuffer(&buf);
LeaveCriticalSection(&cs);
}
pSourceVoice->SubmitSourceBuffer(&buf);
LeaveCriticalSection(&cs);
}
};
};
HMODULE xAudio2DLL;
decltype(&XAudio2Create) pXAudio2Create;
CComPtr<IXAudio2> pXAudio2;
IXAudio2MasteringVoice* pMasteringVoice;
BaseStreamingVoice* voiceContext;
HMODULE xAudio2DLL;
decltype(&XAudio2Create) pXAudio2Create;
CComPtr<IXAudio2> pXAudio2;
IXAudio2MasteringVoice *pMasteringVoice;
BaseStreamingVoice *voiceContext;
public:
s32 Init()
{
HRESULT hr;
s32 Init()
{
HRESULT hr;
pxAssume(pXAudio2 == NULL);
pxAssume(pXAudio2 == NULL);
xAudio2DLL = LoadLibraryEx(XAUDIO2_DLL, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (xAudio2DLL == nullptr)
throw std::runtime_error("Could not load " XAUDIO2_DLL_A ". Error code:" + std::to_string(GetLastError()));
xAudio2DLL = LoadLibraryEx(XAUDIO2_DLL, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (xAudio2DLL == nullptr)
throw std::runtime_error("Could not load " XAUDIO2_DLL_A ". Error code:" + std::to_string(GetLastError()));
pXAudio2Create = reinterpret_cast<decltype(&XAudio2Create)>(GetProcAddress(xAudio2DLL, "XAudio2Create"));
if (pXAudio2Create == nullptr)
throw std::runtime_error("XAudio2Create not found. Error code: " + std::to_string(GetLastError()));
pXAudio2Create = reinterpret_cast<decltype(&XAudio2Create)>(GetProcAddress(xAudio2DLL, "XAudio2Create"));
if (pXAudio2Create == nullptr)
throw std::runtime_error("XAudio2Create not found. Error code: " + std::to_string(GetLastError()));
//
// Initialize XAudio2
//
CoInitializeEx(NULL, COINIT_MULTITHREADED);
//
// Initialize XAudio2
//
CoInitializeEx(NULL, COINIT_MULTITHREADED);
try {
if (FAILED(hr = pXAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)))
throw Exception::XAudio2Error(hr, "Failed to init XAudio2 engine. Error Details:");
try {
if (FAILED(hr = pXAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)))
throw Exception::XAudio2Error(hr, "Failed to init XAudio2 engine. Error Details:");
// Stereo Expansion was planned to grab the currently configured number of
// Speakers from Windows's audio config.
// This doesn't always work though, so let it be a user configurable option.
// Stereo Expansion was planned to grab the currently configured number of
// Speakers from Windows's audio config.
// This doesn't always work though, so let it be a user configurable option.
int speakers;
switch (numSpeakers) // speakers = (numSpeakers + 1) *2; ?
{
case 0:
speakers = 2;
break; // Stereo
case 1:
speakers = 4;
break; // Quadrafonic
case 2:
speakers = 6;
break; // Surround 5.1
case 3:
speakers = 8;
break; // Surround 7.1
default:
speakers = 2;
}
int speakers;
switch (numSpeakers) // speakers = (numSpeakers + 1) *2; ?
{
case 0: speakers = 2; break; // Stereo
case 1: speakers = 4; break; // Quadrafonic
case 2: speakers = 6; break; // Surround 5.1
case 3: speakers = 8; break; // Surround 7.1
default: speakers = 2;
}
//
// Create a mastering voice
//
if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice, speakers, SampleRate))) {
SysMessage("Failed creating mastering voice: %#X\n", hr);
CoUninitialize();
return -1;
}
//
// Create a mastering voice
//
if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice, speakers, SampleRate))) {
SysMessage("Failed creating mastering voice: %#X\n", hr);
CoUninitialize();
return -1;
}
switch (speakers) {
case 2:
ConLog("* SPU2 > Using normal 2 speaker stereo output.\n");
voiceContext = new StreamingVoice<StereoOut16>(pXAudio2);
break;
switch (speakers) {
case 2:
ConLog("* SPU2 > Using normal 2 speaker stereo output.\n");
voiceContext = new StreamingVoice<StereoOut16>(pXAudio2);
break;
case 3:
ConLog("* SPU2 > 2.1 speaker expansion enabled.\n");
voiceContext = new StreamingVoice<Stereo21Out16>(pXAudio2);
break;
case 3:
ConLog("* SPU2 > 2.1 speaker expansion enabled.\n");
voiceContext = new StreamingVoice<Stereo21Out16>(pXAudio2);
break;
case 4:
ConLog("* SPU2 > 4 speaker expansion enabled [quadraphenia]\n");
voiceContext = new StreamingVoice<Stereo40Out16>(pXAudio2);
break;
case 4:
ConLog("* SPU2 > 4 speaker expansion enabled [quadraphenia]\n");
voiceContext = new StreamingVoice<Stereo40Out16>(pXAudio2);
break;
case 5:
ConLog("* SPU2 > 4.1 speaker expansion enabled.\n");
voiceContext = new StreamingVoice<Stereo41Out16>(pXAudio2);
break;
case 5:
ConLog("* SPU2 > 4.1 speaker expansion enabled.\n");
voiceContext = new StreamingVoice<Stereo41Out16>(pXAudio2);
break;
case 6:
case 7:
switch (dplLevel) {
case 0:
ConLog("* SPU2 > 5.1 speaker expansion enabled.\n");
voiceContext = new StreamingVoice<Stereo51Out16>(pXAudio2); //"normal" stereo upmix
break;
case 1:
ConLog("* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n");
voiceContext = new StreamingVoice<Stereo51Out16Dpl>(pXAudio2); // basic Dpl decoder without rear stereo balancing
break;
case 2:
ConLog("* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n");
voiceContext = new StreamingVoice<Stereo51Out16DplII>(pXAudio2); //gigas PLII
break;
}
break;
case 6:
case 7:
switch (dplLevel) {
case 0:
ConLog("* SPU2 > 5.1 speaker expansion enabled.\n");
voiceContext = new StreamingVoice<Stereo51Out16>(pXAudio2); //"normal" stereo upmix
break;
case 1:
ConLog("* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n");
voiceContext = new StreamingVoice<Stereo51Out16Dpl>(pXAudio2); // basic Dpl decoder without rear stereo balancing
break;
case 2:
ConLog("* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n");
voiceContext = new StreamingVoice<Stereo51Out16DplII>(pXAudio2); //gigas PLII
break;
}
break;
default: // anything 8 or more gets the 7.1 treatment!
ConLog("* SPU2 > 7.1 speaker expansion enabled.\n");
voiceContext = new StreamingVoice<Stereo51Out16>(pXAudio2);
break;
}
default: // anything 8 or more gets the 7.1 treatment!
ConLog("* SPU2 > 7.1 speaker expansion enabled.\n");
voiceContext = new StreamingVoice<Stereo51Out16>(pXAudio2);
break;
}
voiceContext->Init(pXAudio2);
} catch (Exception::XAudio2Error &ex) {
SysMessage(ex.CMessage());
pXAudio2.Release();
CoUninitialize();
return -1;
}
voiceContext->Init(pXAudio2);
} catch (Exception::XAudio2Error& ex) {
SysMessage(ex.CMessage());
pXAudio2.Release();
CoUninitialize();
return -1;
}
return 0;
}
return 0;
}
void Close()
{
safe_delete(voiceContext);
void Close()
{
safe_delete(voiceContext);
voiceContext = NULL;
voiceContext = NULL;
if (pMasteringVoice != NULL)
pMasteringVoice->DestroyVoice();
if (pMasteringVoice != NULL)
pMasteringVoice->DestroyVoice();
pMasteringVoice = NULL;
pMasteringVoice = NULL;
pXAudio2.Release();
CoUninitialize();
pXAudio2.Release();
CoUninitialize();
if (xAudio2DLL) {
FreeLibrary(xAudio2DLL);
xAudio2DLL = nullptr;
pXAudio2Create = nullptr;
}
}
if (xAudio2DLL) {
FreeLibrary(xAudio2DLL);
xAudio2DLL = nullptr;
pXAudio2Create = nullptr;
}
}
virtual void Configure(uptr parent)
{
}
virtual void Configure(uptr parent)
{
}
s32 Test() const
{
return 0;
}
s32 Test() const
{
return 0;
}
int GetEmptySampleCount()
{
if (voiceContext == NULL)
return 0;
return voiceContext->GetEmptySampleCount();
}
int GetEmptySampleCount()
{
if (voiceContext == NULL) return 0;
return voiceContext->GetEmptySampleCount();
}
const wchar_t *GetIdent() const
{
return L"xaudio2";
}
const wchar_t* GetIdent() const
{
return L"xaudio2";
}
const wchar_t *GetLongName() const
{
return L"XAudio 2 (Recommended)";
}
const wchar_t* GetLongName() const
{
return L"XAudio 2 (Recommended)";
}
void ReadSettings()
{
}
void ReadSettings()
{
}
void SetApiSettings(wxString api)
{
}
void SetApiSettings(wxString api)
{
}
void WriteSettings() const
{
}
void WriteSettings() const
{
}
} static XA2;

View File

@ -24,410 +24,428 @@
namespace Exception
{
class XAudio2_27Error : public std::runtime_error
{
protected:
static const char* SomeKindaErrorString( HRESULT hr )
{
switch( hr )
{
case XAUDIO2_E_INVALID_CALL:
return "Invalid call for the XA2 object state.";
case XAUDIO2_E_DEVICE_INVALIDATED:
return "Device is unavailable, unplugged, unsupported, or has been consumed by The Nothing.";
}
return "Unknown error code!";
}
public:
const HRESULT ErrorCode;
std::string m_Message;
const char* CMessage() const
{
return m_Message.c_str();
}
virtual ~XAudio2_27Error() throw() {}
XAudio2_27Error( const HRESULT result, const std::string& msg ) :
runtime_error( msg ),
ErrorCode( result ),
m_Message()
{
char omg[1024];
sprintf_s( omg, "%s (code 0x%x)\n\n%s", what(), ErrorCode, SomeKindaErrorString( ErrorCode ) );
m_Message = omg;
}
};
}
static const double SndOutNormalizer = (double)(1UL<<(SndOutVolumeShift+16));
class XAudio2_27_Mod: public SndOutModule
class XAudio2_27Error : public std::runtime_error
{
private:
static const int PacketsPerBuffer = 8;
static const int MAX_BUFFER_COUNT = 3;
protected:
static const char *SomeKindaErrorString(HRESULT hr)
{
switch (hr) {
case XAUDIO2_E_INVALID_CALL:
return "Invalid call for the XA2 object state.";
class BaseStreamingVoice : public IXAudio2VoiceCallback
{
protected:
IXAudio2SourceVoice* pSourceVoice;
s16* qbuffer;
const uint m_nBuffers;
const uint m_nChannels;
const uint m_BufferSize;
const uint m_BufferSizeBytes;
CRITICAL_SECTION cs;
public:
int GetEmptySampleCount()
{
XAUDIO2_VOICE_STATE state;
pSourceVoice->GetState( &state );
return state.SamplesPlayed & (m_BufferSize-1);
}
virtual ~BaseStreamingVoice()
{
}
BaseStreamingVoice( uint numChannels ) :
m_nBuffers( Config_XAudio2.NumBuffers ),
m_nChannels( numChannels ),
m_BufferSize( SndOutPacketSize * m_nChannels * PacketsPerBuffer ),
m_BufferSizeBytes( m_BufferSize * sizeof(s16) )
{
}
virtual void Init( IXAudio2* pXAudio2 ) = 0;
protected:
// Several things must be initialized separate of the constructor, due to the fact that
// virtual calls can't be made from the constructor's context.
void _init( IXAudio2* pXAudio2, uint chanConfig )
{
WAVEFORMATEXTENSIBLE wfx;
memset(&wfx, 0, sizeof(WAVEFORMATEXTENSIBLE));
wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfx.Format.nSamplesPerSec = SampleRate;
wfx.Format.nChannels = m_nChannels;
wfx.Format.wBitsPerSample = 16;
wfx.Format.nBlockAlign = wfx.Format.nChannels*wfx.Format.wBitsPerSample/8;
wfx.Format.nAvgBytesPerSec = SampleRate * wfx.Format.nBlockAlign;
wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
wfx.Samples.wValidBitsPerSample = 16;
wfx.dwChannelMask = chanConfig;
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
//
// Create an XAudio2 voice to stream this wave
//
HRESULT hr;
if( FAILED(hr = pXAudio2->CreateSourceVoice( &pSourceVoice, (WAVEFORMATEX*)&wfx,
XAUDIO2_VOICE_NOSRC, 1.0f, this ) ) )
{
throw Exception::XAudio2_27Error( hr, "XAudio2 CreateSourceVoice failure." );
}
InitializeCriticalSection( &cs );
EnterCriticalSection( &cs );
pSourceVoice->FlushSourceBuffers();
pSourceVoice->Start( 0, 0 );
qbuffer = new s16[m_nBuffers * m_BufferSize];
ZeroMemory( qbuffer, m_BufferSizeBytes * m_nBuffers );
// Start some buffers.
for( uint i=0; i<m_nBuffers; i++ )
{
XAUDIO2_BUFFER buf = {0};
buf.AudioBytes = m_BufferSizeBytes;
buf.pContext = &qbuffer[i*m_BufferSize];
buf.pAudioData = (BYTE*)buf.pContext;
pSourceVoice->SubmitSourceBuffer( &buf );
}
LeaveCriticalSection( &cs );
}
STDMETHOD_(void, OnVoiceProcessingPassStart) () {}
STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) { };
STDMETHOD_(void, OnVoiceProcessingPassEnd) () {}
STDMETHOD_(void, OnStreamEnd) () {}
STDMETHOD_(void, OnBufferStart) ( void* ) {}
STDMETHOD_(void, OnLoopEnd) ( void* ) {}
STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) { };
};
template< typename T >
class StreamingVoice : public BaseStreamingVoice
{
public:
StreamingVoice( IXAudio2* pXAudio2 ) :
BaseStreamingVoice( sizeof(T) / sizeof( s16 ) )
{
}
virtual ~StreamingVoice()
{
IXAudio2SourceVoice* killMe = pSourceVoice;
pSourceVoice = NULL;
killMe->FlushSourceBuffers();
killMe->DestroyVoice();
EnterCriticalSection( &cs );
safe_delete_array( qbuffer );
LeaveCriticalSection( &cs );
DeleteCriticalSection( &cs );
}
void Init( IXAudio2* pXAudio2 )
{
int chanMask = 0;
switch(m_nChannels)
{
case 1: chanMask |= SPEAKER_FRONT_CENTER; break;
case 2: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break;
case 3: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY; break;
case 4: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break;
case 5: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break;
case 6: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY; break;
case 8: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT | SPEAKER_LOW_FREQUENCY; break;
}
_init( pXAudio2, chanMask );
}
protected:
STDMETHOD_(void, OnBufferEnd) ( void* context )
{
EnterCriticalSection( &cs );
// All of these checks are necessary because XAudio2 is wonky shizat.
if( pSourceVoice == NULL || context == NULL )
{
LeaveCriticalSection( &cs );
return;
}
T* qb = (T*)context;
for(int p=0; p<PacketsPerBuffer; p++, qb+=SndOutPacketSize )
SndBuffer::ReadSamples( qb );
XAUDIO2_BUFFER buf = {0};
buf.AudioBytes = m_BufferSizeBytes;
buf.pAudioData = (BYTE*)context;
buf.pContext = context;
pSourceVoice->SubmitSourceBuffer( &buf );
LeaveCriticalSection( &cs );
}
};
HMODULE xAudio2DLL;
CComPtr<IXAudio2> pXAudio2;
IXAudio2MasteringVoice* pMasteringVoice;
BaseStreamingVoice* voiceContext;
case XAUDIO2_E_DEVICE_INVALIDATED:
return "Device is unavailable, unplugged, unsupported, or has been consumed by The Nothing.";
}
return "Unknown error code!";
}
public:
const HRESULT ErrorCode;
std::string m_Message;
s32 Init()
{
HRESULT hr;
const char *CMessage() const
{
return m_Message.c_str();
}
pxAssume( pXAudio2 == NULL );
virtual ~XAudio2_27Error() throw() {}
XAudio2_27Error(const HRESULT result, const std::string &msg)
: runtime_error(msg)
, ErrorCode(result)
, m_Message()
{
char omg[1024];
sprintf_s(omg, "%s (code 0x%x)\n\n%s", what(), ErrorCode, SomeKindaErrorString(ErrorCode));
m_Message = omg;
}
};
}
// On some systems XAudio2.7 can unload itself and cause PCSX2 to crash.
// Maintain an extra library reference so it can't do so. Does not
// affect XAudio 2.8+, but that's Win8+. See
// http://blogs.msdn.com/b/chuckw/archive/2015/10/09/known-issues-xaudio-2-7.aspx
static const double SndOutNormalizer = (double)(1UL << (SndOutVolumeShift + 16));
class XAudio2_27_Mod : public SndOutModule
{
private:
static const int PacketsPerBuffer = 8;
static const int MAX_BUFFER_COUNT = 3;
class BaseStreamingVoice : public IXAudio2VoiceCallback
{
protected:
IXAudio2SourceVoice *pSourceVoice;
s16 *qbuffer;
const uint m_nBuffers;
const uint m_nChannels;
const uint m_BufferSize;
const uint m_BufferSizeBytes;
CRITICAL_SECTION cs;
public:
int GetEmptySampleCount()
{
XAUDIO2_VOICE_STATE state;
pSourceVoice->GetState(&state);
return state.SamplesPlayed & (m_BufferSize - 1);
}
virtual ~BaseStreamingVoice()
{
}
BaseStreamingVoice(uint numChannels)
: m_nBuffers(Config_XAudio2.NumBuffers)
, m_nChannels(numChannels)
, m_BufferSize(SndOutPacketSize * m_nChannels * PacketsPerBuffer)
, m_BufferSizeBytes(m_BufferSize * sizeof(s16))
{
}
virtual void Init(IXAudio2 *pXAudio2) = 0;
protected:
// Several things must be initialized separate of the constructor, due to the fact that
// virtual calls can't be made from the constructor's context.
void _init(IXAudio2 *pXAudio2, uint chanConfig)
{
WAVEFORMATEXTENSIBLE wfx;
memset(&wfx, 0, sizeof(WAVEFORMATEXTENSIBLE));
wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfx.Format.nSamplesPerSec = SampleRate;
wfx.Format.nChannels = m_nChannels;
wfx.Format.wBitsPerSample = 16;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = SampleRate * wfx.Format.nBlockAlign;
wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
wfx.Samples.wValidBitsPerSample = 16;
wfx.dwChannelMask = chanConfig;
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
//
// Create an XAudio2 voice to stream this wave
//
HRESULT hr;
if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX *)&wfx,
XAUDIO2_VOICE_NOSRC, 1.0f, this))) {
throw Exception::XAudio2_27Error(hr, "XAudio2 CreateSourceVoice failure.");
}
InitializeCriticalSection(&cs);
EnterCriticalSection(&cs);
pSourceVoice->FlushSourceBuffers();
pSourceVoice->Start(0, 0);
qbuffer = new s16[m_nBuffers * m_BufferSize];
ZeroMemory(qbuffer, m_BufferSizeBytes * m_nBuffers);
// Start some buffers.
for (uint i = 0; i < m_nBuffers; i++) {
XAUDIO2_BUFFER buf = {0};
buf.AudioBytes = m_BufferSizeBytes;
buf.pContext = &qbuffer[i * m_BufferSize];
buf.pAudioData = (BYTE *)buf.pContext;
pSourceVoice->SubmitSourceBuffer(&buf);
}
LeaveCriticalSection(&cs);
}
STDMETHOD_(void, OnVoiceProcessingPassStart)
() {}
STDMETHOD_(void, OnVoiceProcessingPassStart)
(UINT32){};
STDMETHOD_(void, OnVoiceProcessingPassEnd)
() {}
STDMETHOD_(void, OnStreamEnd)
() {}
STDMETHOD_(void, OnBufferStart)
(void *) {}
STDMETHOD_(void, OnLoopEnd)
(void *) {}
STDMETHOD_(void, OnVoiceError)
(THIS_ void *pBufferContext, HRESULT Error){};
};
template <typename T>
class StreamingVoice : public BaseStreamingVoice
{
public:
StreamingVoice(IXAudio2 *pXAudio2)
: BaseStreamingVoice(sizeof(T) / sizeof(s16))
{
}
virtual ~StreamingVoice()
{
IXAudio2SourceVoice *killMe = pSourceVoice;
pSourceVoice = NULL;
killMe->FlushSourceBuffers();
killMe->DestroyVoice();
EnterCriticalSection(&cs);
safe_delete_array(qbuffer);
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
}
void Init(IXAudio2 *pXAudio2)
{
int chanMask = 0;
switch (m_nChannels) {
case 1:
chanMask |= SPEAKER_FRONT_CENTER;
break;
case 2:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
break;
case 3:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY;
break;
case 4:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
break;
case 5:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
break;
case 6:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
break;
case 8:
chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT | SPEAKER_LOW_FREQUENCY;
break;
}
_init(pXAudio2, chanMask);
}
protected:
STDMETHOD_(void, OnBufferEnd)
(void *context)
{
EnterCriticalSection(&cs);
// All of these checks are necessary because XAudio2 is wonky shizat.
if (pSourceVoice == NULL || context == NULL) {
LeaveCriticalSection(&cs);
return;
}
T *qb = (T *)context;
for (int p = 0; p < PacketsPerBuffer; p++, qb += SndOutPacketSize)
SndBuffer::ReadSamples(qb);
XAUDIO2_BUFFER buf = {0};
buf.AudioBytes = m_BufferSizeBytes;
buf.pAudioData = (BYTE *)context;
buf.pContext = context;
pSourceVoice->SubmitSourceBuffer(&buf);
LeaveCriticalSection(&cs);
}
};
HMODULE xAudio2DLL;
CComPtr<IXAudio2> pXAudio2;
IXAudio2MasteringVoice *pMasteringVoice;
BaseStreamingVoice *voiceContext;
public:
s32 Init()
{
HRESULT hr;
pxAssume(pXAudio2 == NULL);
// On some systems XAudio2.7 can unload itself and cause PCSX2 to crash.
// Maintain an extra library reference so it can't do so. Does not
// affect XAudio 2.8+, but that's Win8+. See
// http://blogs.msdn.com/b/chuckw/archive/2015/10/09/known-issues-xaudio-2-7.aspx
#ifdef _DEBUG
xAudio2DLL = LoadLibrary(L"XAudioD2_7.dll");
xAudio2DLL = LoadLibrary(L"XAudioD2_7.dll");
#else
xAudio2DLL = LoadLibrary(L"XAudio2_7.dll");
xAudio2DLL = LoadLibrary(L"XAudio2_7.dll");
#endif
//
// Initialize XAudio2
//
CoInitializeEx( NULL, COINIT_MULTITHREADED );
//
// Initialize XAudio2
//
CoInitializeEx(NULL, COINIT_MULTITHREADED);
UINT32 flags = 0;
if( IsDebugBuild )
flags |= XAUDIO2_DEBUG_ENGINE;
UINT32 flags = 0;
if (IsDebugBuild)
flags |= XAUDIO2_DEBUG_ENGINE;
try
{
if ( FAILED(hr = XAudio2Create( &pXAudio2, flags ) ) )
throw Exception::XAudio2_27Error( hr,
"Failed to init XAudio2 engine. XA2 may not be available on your system.\n"
"Ensure that you have the latest DirectX runtimes installed, or use \n"
"DirectX / WaveOut drivers instead. Error Details:"
);
try {
if (FAILED(hr = XAudio2Create(&pXAudio2, flags)))
throw Exception::XAudio2_27Error(hr,
"Failed to init XAudio2 engine. XA2 may not be available on your system.\n"
"Ensure that you have the latest DirectX runtimes installed, or use \n"
"DirectX / WaveOut drivers instead. Error Details:");
XAUDIO2_DEVICE_DETAILS deviceDetails;
pXAudio2->GetDeviceDetails( 0, &deviceDetails );
XAUDIO2_DEVICE_DETAILS deviceDetails;
pXAudio2->GetDeviceDetails(0, &deviceDetails);
// Stereo Expansion was planned to grab the currently configured number of
// Speakers from Windows's audio config.
// This doesn't always work though, so let it be a user configurable option.
// Stereo Expansion was planned to grab the currently configured number of
// Speakers from Windows's audio config.
// This doesn't always work though, so let it be a user configurable option.
int speakers;
switch(numSpeakers) // speakers = (numSpeakers + 1) *2; ?
{
case 0: speakers = 2; break; // Stereo
case 1: speakers = 4; break; // Quadrafonic
case 2: speakers = 6; break; // Surround 5.1
case 3: speakers = 8; break; // Surround 7.1
default: speakers = 2;
}
int speakers;
switch (numSpeakers) // speakers = (numSpeakers + 1) *2; ?
{
case 0:
speakers = 2;
break; // Stereo
case 1:
speakers = 4;
break; // Quadrafonic
case 2:
speakers = 6;
break; // Surround 5.1
case 3:
speakers = 8;
break; // Surround 7.1
default:
speakers = 2;
}
// Any windows driver should support stereo at the software level, I should think!
pxAssume( deviceDetails.OutputFormat.Format.nChannels > 1 );
// Any windows driver should support stereo at the software level, I should think!
pxAssume(deviceDetails.OutputFormat.Format.nChannels > 1);
//
// Create a mastering voice
//
if ( FAILED(hr = pXAudio2->CreateMasteringVoice( &pMasteringVoice, speakers, SampleRate ) ) )
{
SysMessage( "Failed creating mastering voice: %#X\n", hr );
CoUninitialize();
return -1;
}
//
// Create a mastering voice
//
if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice, speakers, SampleRate))) {
SysMessage("Failed creating mastering voice: %#X\n", hr);
CoUninitialize();
return -1;
}
switch( speakers )
{
case 2:
ConLog( "* SPU2 > Using normal 2 speaker stereo output.\n" );
voiceContext = new StreamingVoice<StereoOut16>( pXAudio2 );
break;
switch (speakers) {
case 2:
ConLog("* SPU2 > Using normal 2 speaker stereo output.\n");
voiceContext = new StreamingVoice<StereoOut16>(pXAudio2);
break;
case 3:
ConLog( "* SPU2 > 2.1 speaker expansion enabled.\n" );
voiceContext = new StreamingVoice<Stereo21Out16>( pXAudio2 );
break;
case 3:
ConLog("* SPU2 > 2.1 speaker expansion enabled.\n");
voiceContext = new StreamingVoice<Stereo21Out16>(pXAudio2);
break;
case 4:
ConLog( "* SPU2 > 4 speaker expansion enabled [quadraphenia]\n" );
voiceContext = new StreamingVoice<Stereo40Out16>( pXAudio2 );
break;
case 4:
ConLog("* SPU2 > 4 speaker expansion enabled [quadraphenia]\n");
voiceContext = new StreamingVoice<Stereo40Out16>(pXAudio2);
break;
case 5:
ConLog( "* SPU2 > 4.1 speaker expansion enabled.\n" );
voiceContext = new StreamingVoice<Stereo41Out16>( pXAudio2 );
break;
case 5:
ConLog("* SPU2 > 4.1 speaker expansion enabled.\n");
voiceContext = new StreamingVoice<Stereo41Out16>(pXAudio2);
break;
case 6:
case 7:
switch(dplLevel)
{
case 0:
ConLog( "* SPU2 > 5.1 speaker expansion enabled.\n" );
voiceContext = new StreamingVoice<Stereo51Out16>( pXAudio2 ); //"normal" stereo upmix
break;
case 1:
ConLog( "* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n" );
voiceContext = new StreamingVoice<Stereo51Out16Dpl>( pXAudio2 ); // basic Dpl decoder without rear stereo balancing
break;
case 2:
ConLog( "* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n" );
voiceContext = new StreamingVoice<Stereo51Out16DplII>( pXAudio2 ); //gigas PLII
break;
}
break;
case 6:
case 7:
switch (dplLevel) {
case 0:
ConLog("* SPU2 > 5.1 speaker expansion enabled.\n");
voiceContext = new StreamingVoice<Stereo51Out16>(pXAudio2); //"normal" stereo upmix
break;
case 1:
ConLog("* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n");
voiceContext = new StreamingVoice<Stereo51Out16Dpl>(pXAudio2); // basic Dpl decoder without rear stereo balancing
break;
case 2:
ConLog("* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n");
voiceContext = new StreamingVoice<Stereo51Out16DplII>(pXAudio2); //gigas PLII
break;
}
break;
default: // anything 8 or more gets the 7.1 treatment!
ConLog( "* SPU2 > 7.1 speaker expansion enabled.\n" );
voiceContext = new StreamingVoice<Stereo51Out16>( pXAudio2 );
break;
}
default: // anything 8 or more gets the 7.1 treatment!
ConLog("* SPU2 > 7.1 speaker expansion enabled.\n");
voiceContext = new StreamingVoice<Stereo51Out16>(pXAudio2);
break;
}
voiceContext->Init( pXAudio2 );
}
catch( Exception::XAudio2_27Error& ex )
{
SysMessage( ex.CMessage() );
pXAudio2.Release();
CoUninitialize();
return -1;
}
voiceContext->Init(pXAudio2);
} catch (Exception::XAudio2_27Error &ex) {
SysMessage(ex.CMessage());
pXAudio2.Release();
CoUninitialize();
return -1;
}
return 0;
}
return 0;
}
void Close()
{
// Clean up?
// All XAudio2 interfaces are released when the engine is destroyed,
// but being tidy never hurt.
void Close()
{
// Clean up?
// All XAudio2 interfaces are released when the engine is destroyed,
// but being tidy never hurt.
// Actually it can hurt. As of DXSDK Aug 2008, doing a full cleanup causes
// XA2 on Vista to crash. Even if you copy/paste code directly from Microsoft.
// But doing no cleanup at all causes XA2 under XP to crash. So after much trial
// and error we found a happy compromise as follows:
// Actually it can hurt. As of DXSDK Aug 2008, doing a full cleanup causes
// XA2 on Vista to crash. Even if you copy/paste code directly from Microsoft.
// But doing no cleanup at all causes XA2 under XP to crash. So after much trial
// and error we found a happy compromise as follows:
safe_delete( voiceContext );
safe_delete(voiceContext);
voiceContext = NULL;
voiceContext = NULL;
if( pMasteringVoice != NULL )
pMasteringVoice->DestroyVoice();
if (pMasteringVoice != NULL)
pMasteringVoice->DestroyVoice();
pMasteringVoice = NULL;
pMasteringVoice = NULL;
pXAudio2.Release();
CoUninitialize();
pXAudio2.Release();
CoUninitialize();
if (xAudio2DLL) {
FreeLibrary(xAudio2DLL);
xAudio2DLL = nullptr;
}
}
if (xAudio2DLL) {
FreeLibrary(xAudio2DLL);
xAudio2DLL = nullptr;
}
}
virtual void Configure(uptr parent)
{
}
virtual void Configure(uptr parent)
{
}
s32 Test() const
{
return 0;
}
s32 Test() const
{
return 0;
}
int GetEmptySampleCount()
{
if( voiceContext == NULL ) return 0;
return voiceContext->GetEmptySampleCount();
}
int GetEmptySampleCount()
{
if (voiceContext == NULL)
return 0;
return voiceContext->GetEmptySampleCount();
}
const wchar_t* GetIdent() const
{
return L"xaudio2";
}
const wchar_t *GetIdent() const
{
return L"xaudio2";
}
const wchar_t* GetLongName() const
{
return L"XAudio 2.7 (Recommended)";
}
const wchar_t *GetLongName() const
{
return L"XAudio 2.7 (Recommended)";
}
void ReadSettings()
{
}
void ReadSettings()
{
}
void SetApiSettings(wxString api)
{
}
void SetApiSettings(wxString api)
{
}
void WriteSettings() const
{
}
void WriteSettings() const
{
}
} static XA2;

View File

@ -19,80 +19,80 @@
#include "Dialogs.h"
class WaveOutModule: public SndOutModule
class WaveOutModule : public SndOutModule
{
private:
static const uint MAX_BUFFER_COUNT = 8;
static const uint MAX_BUFFER_COUNT = 8;
static const int PacketsPerBuffer = (1024 / SndOutPacketSize);
static const int BufferSize = SndOutPacketSize*PacketsPerBuffer;
static const int PacketsPerBuffer = (1024 / SndOutPacketSize);
static const int BufferSize = SndOutPacketSize * PacketsPerBuffer;
u32 numBuffers;
HWAVEOUT hwodevice;
WAVEFORMATEX wformat;
WAVEHDR whbuffer[MAX_BUFFER_COUNT];
u32 numBuffers;
HWAVEOUT hwodevice;
WAVEFORMATEX wformat;
WAVEHDR whbuffer[MAX_BUFFER_COUNT];
StereoOut16* qbuffer;
StereoOut16 *qbuffer;
#define QBUFFER(x) (qbuffer + BufferSize * (x))
#define QBUFFER(x) (qbuffer + BufferSize * (x))
bool waveout_running;
HANDLE thread;
DWORD tid;
bool waveout_running;
HANDLE thread;
DWORD tid;
wchar_t ErrText[256];
wchar_t ErrText[256];
template< typename T >
DWORD CALLBACK Thread()
{
static const int BufferSizeBytes = BufferSize * sizeof( T );
template <typename T>
DWORD CALLBACK Thread()
{
static const int BufferSizeBytes = BufferSize * sizeof(T);
while( waveout_running )
{
bool didsomething = false;
for(u32 i=0;i<numBuffers;i++)
{
if(!(whbuffer[i].dwFlags & WHDR_DONE) ) continue;
while (waveout_running) {
bool didsomething = false;
for (u32 i = 0; i < numBuffers; i++) {
if (!(whbuffer[i].dwFlags & WHDR_DONE))
continue;
WAVEHDR *buf = whbuffer+i;
WAVEHDR *buf = whbuffer + i;
buf->dwBytesRecorded = buf->dwBufferLength;
buf->dwBytesRecorded = buf->dwBufferLength;
T* t = (T*)buf->lpData;
for(int p=0; p<PacketsPerBuffer; p++, t+=SndOutPacketSize )
SndBuffer::ReadSamples( t );
T *t = (T *)buf->lpData;
for (int p = 0; p < PacketsPerBuffer; p++, t += SndOutPacketSize)
SndBuffer::ReadSamples(t);
whbuffer[i].dwFlags &= ~WHDR_DONE;
waveOutWrite( hwodevice, buf, sizeof(WAVEHDR) );
didsomething = true;
}
whbuffer[i].dwFlags &= ~WHDR_DONE;
waveOutWrite(hwodevice, buf, sizeof(WAVEHDR));
didsomething = true;
}
if( didsomething )
Sleep(1);
else
Sleep(0);
}
return 0;
}
if (didsomething)
Sleep(1);
else
Sleep(0);
}
return 0;
}
template< typename T >
static DWORD CALLBACK RThread(WaveOutModule*obj)
{
return obj->Thread<T>();
}
template <typename T>
static DWORD CALLBACK RThread(WaveOutModule *obj)
{
return obj->Thread<T>();
}
public:
s32 Init()
{
numBuffers = Config_WaveOut.NumBuffers;
s32 Init()
{
numBuffers = Config_WaveOut.NumBuffers;
MMRESULT woores;
MMRESULT woores;
if (Test()) return -1;
if (Test())
return -1;
// TODO : Use dsound to determine the speaker configuration, and expand audio from there.
// TODO : Use dsound to determine the speaker configuration, and expand audio from there.
#if 0
#if 0
int speakerConfig;
//if( StereoExpansionEnabled )
@ -129,197 +129,193 @@ public:
speakerConfig = 8;
break;
}
#endif
#endif
wformat.wFormatTag = WAVE_FORMAT_PCM;
wformat.nSamplesPerSec = SampleRate;
wformat.wBitsPerSample = 16;
wformat.nChannels = 2;
wformat.nBlockAlign = ((wformat.wBitsPerSample * wformat.nChannels) / 8);
wformat.nAvgBytesPerSec = (wformat.nSamplesPerSec * wformat.nBlockAlign);
wformat.cbSize = 0;
wformat.wFormatTag = WAVE_FORMAT_PCM;
wformat.nSamplesPerSec = SampleRate;
wformat.wBitsPerSample = 16;
wformat.nChannels = 2;
wformat.nBlockAlign = ((wformat.wBitsPerSample * wformat.nChannels) / 8);
wformat.nAvgBytesPerSec = (wformat.nSamplesPerSec * wformat.nBlockAlign);
wformat.cbSize = 0;
qbuffer = new StereoOut16[BufferSize*numBuffers];
qbuffer = new StereoOut16[BufferSize * numBuffers];
woores = waveOutOpen(&hwodevice,WAVE_MAPPER,&wformat,0,0,0);
if (woores != MMSYSERR_NOERROR)
{
waveOutGetErrorText(woores,(wchar_t *)&ErrText,255);
SysMessage("WaveOut Error: %s",ErrText);
return -1;
}
woores = waveOutOpen(&hwodevice, WAVE_MAPPER, &wformat, 0, 0, 0);
if (woores != MMSYSERR_NOERROR) {
waveOutGetErrorText(woores, (wchar_t *)&ErrText, 255);
SysMessage("WaveOut Error: %s", ErrText);
return -1;
}
const int BufferSizeBytes = wformat.nBlockAlign * BufferSize;
const int BufferSizeBytes = wformat.nBlockAlign * BufferSize;
for(u32 i=0;i<numBuffers;i++)
{
whbuffer[i].dwBufferLength=BufferSizeBytes;
whbuffer[i].dwBytesRecorded=BufferSizeBytes;
whbuffer[i].dwFlags=0;
whbuffer[i].dwLoops=0;
whbuffer[i].dwUser=0;
whbuffer[i].lpData=(LPSTR)QBUFFER(i);
whbuffer[i].lpNext=0;
whbuffer[i].reserved=0;
waveOutPrepareHeader(hwodevice,whbuffer+i,sizeof(WAVEHDR));
whbuffer[i].dwFlags|=WHDR_DONE; //avoid deadlock
}
for (u32 i = 0; i < numBuffers; i++) {
whbuffer[i].dwBufferLength = BufferSizeBytes;
whbuffer[i].dwBytesRecorded = BufferSizeBytes;
whbuffer[i].dwFlags = 0;
whbuffer[i].dwLoops = 0;
whbuffer[i].dwUser = 0;
whbuffer[i].lpData = (LPSTR)QBUFFER(i);
whbuffer[i].lpNext = 0;
whbuffer[i].reserved = 0;
waveOutPrepareHeader(hwodevice, whbuffer + i, sizeof(WAVEHDR));
whbuffer[i].dwFlags |= WHDR_DONE; //avoid deadlock
}
// Start Thread
// [Air]: The waveout code does not use wait objects, so setting a time critical
// priority level is a bad idea. Standard priority will do fine. The buffer will get the
// love it needs and won't suck resources idling pointlessly. Just don't try to
// run it in uber-low-latency mode.
waveout_running = true;
thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread<StereoOut16>,this,0,&tid);
// Start Thread
// [Air]: The waveout code does not use wait objects, so setting a time critical
// priority level is a bad idea. Standard priority will do fine. The buffer will get the
// love it needs and won't suck resources idling pointlessly. Just don't try to
// run it in uber-low-latency mode.
waveout_running = true;
thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RThread<StereoOut16>, this, 0, &tid);
return 0;
}
return 0;
}
void Close()
{
// Stop Thread
fprintf(stderr,"* SPU2-X: Waiting for waveOut thread to finish...");
waveout_running=false;
void Close()
{
// Stop Thread
fprintf(stderr, "* SPU2-X: Waiting for waveOut thread to finish...");
waveout_running = false;
WaitForSingleObject(thread,INFINITE);
CloseHandle(thread);
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
fprintf(stderr," Done.\n");
fprintf(stderr, " Done.\n");
//
// Clean up
//
waveOutReset(hwodevice);
for(u32 i=0;i<numBuffers;i++)
{
waveOutUnprepareHeader(hwodevice,&whbuffer[i],sizeof(WAVEHDR));
}
waveOutClose(hwodevice);
//
// Clean up
//
waveOutReset(hwodevice);
for (u32 i = 0; i < numBuffers; i++) {
waveOutUnprepareHeader(hwodevice, &whbuffer[i], sizeof(WAVEHDR));
}
waveOutClose(hwodevice);
safe_delete_array( qbuffer );
}
safe_delete_array(qbuffer);
}
private:
static BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
static BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
int wmId,wmEvent;
switch (uMsg) {
case WM_INITDIALOG:
switch(uMsg)
{
case WM_INITDIALOG:
wchar_t temp[128];
INIT_SLIDER(IDC_BUFFERS_SLIDER, 3, MAX_BUFFER_COUNT, 2, 1, 1);
SendMessage(GetDlgItem(hWnd, IDC_BUFFERS_SLIDER), TBM_SETPOS, TRUE, Config_WaveOut.NumBuffers);
swprintf_s(temp, 128, L"%d (%d ms latency)", Config_WaveOut.NumBuffers, 1000 / (96000 / (Config_WaveOut.NumBuffers * BufferSize)));
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
break;
wchar_t temp[128];
INIT_SLIDER( IDC_BUFFERS_SLIDER, 3, MAX_BUFFER_COUNT, 2, 1, 1 );
SendMessage(GetDlgItem(hWnd,IDC_BUFFERS_SLIDER),TBM_SETPOS,TRUE,Config_WaveOut.NumBuffers);
swprintf_s(temp, 128, L"%d (%d ms latency)",Config_WaveOut.NumBuffers, 1000 / (96000 / (Config_WaveOut.NumBuffers * BufferSize)));
SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId) {
case IDOK: {
Config_WaveOut.NumBuffers = (int)SendMessage(GetDlgItem(hWnd, IDC_BUFFERS_SLIDER), TBM_GETPOS, 0, 0);
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDOK:
{
Config_WaveOut.NumBuffers = (int)SendMessage( GetDlgItem( hWnd, IDC_BUFFERS_SLIDER ), TBM_GETPOS, 0, 0 );
if (Config_WaveOut.NumBuffers < 3)
Config_WaveOut.NumBuffers = 3;
if (Config_WaveOut.NumBuffers > MAX_BUFFER_COUNT)
Config_WaveOut.NumBuffers = MAX_BUFFER_COUNT;
}
EndDialog(hWnd, 0);
break;
case IDCANCEL:
EndDialog(hWnd, 0);
break;
default:
return FALSE;
}
break;
if( Config_WaveOut.NumBuffers < 3 ) Config_WaveOut.NumBuffers = 3;
if( Config_WaveOut.NumBuffers > MAX_BUFFER_COUNT ) Config_WaveOut.NumBuffers = MAX_BUFFER_COUNT;
}
EndDialog(hWnd,0);
break;
case IDCANCEL:
EndDialog(hWnd,0);
break;
default:
return FALSE;
}
break;
case WM_HSCROLL:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId) {
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
wmEvent = (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
case TB_THUMBTRACK:
if (wmEvent < 3)
wmEvent = 3;
if (wmEvent > MAX_BUFFER_COUNT)
wmEvent = MAX_BUFFER_COUNT;
SendMessage((HWND)lParam, TBM_SETPOS, TRUE, wmEvent);
swprintf_s(temp, L"%d (%d ms latency)", wmEvent, 1000 / (96000 / (wmEvent * BufferSize)));
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
break;
default:
return FALSE;
}
break;
case WM_HSCROLL:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch(wmId) {
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0);
case TB_THUMBTRACK:
if( wmEvent < 3 ) wmEvent = 3;
if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT;
SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent);
swprintf_s(temp, L"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize)));
SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp);
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
default:
return FALSE;
}
return TRUE;
}
public:
virtual void Configure(uptr parent)
{
INT_PTR ret;
ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_WAVEOUT), (HWND)parent, (DLGPROC)ConfigProc,1);
if(ret==-1)
{
MessageBox((HWND)parent, L"Error Opening the config dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
}
s32 Test() const
{
if (waveOutGetNumDevs() == 0) {
SysMessage("No waveOut Devices Present\n"); return -1;
}
return 0;
}
virtual void Configure(uptr parent)
{
INT_PTR ret;
ret = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_WAVEOUT), (HWND)parent, (DLGPROC)ConfigProc, 1);
if (ret == -1) {
MessageBox((HWND)parent, L"Error Opening the config dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
}
int GetEmptySampleCount()
{
int result = 0;
for(int i=0;i<MAX_BUFFER_COUNT;i++)
{
result += (whbuffer[i].dwFlags & WHDR_DONE) ? BufferSize : 0;
}
return result;
}
s32 Test() const
{
if (waveOutGetNumDevs() == 0) {
SysMessage("No waveOut Devices Present\n");
return -1;
}
return 0;
}
const wchar_t* GetIdent() const
{
return L"waveout";
}
int GetEmptySampleCount()
{
int result = 0;
for (int i = 0; i < MAX_BUFFER_COUNT; i++) {
result += (whbuffer[i].dwFlags & WHDR_DONE) ? BufferSize : 0;
}
return result;
}
const wchar_t* GetLongName() const
{
return L"waveOut (Laggy)";
}
const wchar_t *GetIdent() const
{
return L"waveout";
}
void ReadSettings()
{
}
const wchar_t *GetLongName() const
{
return L"waveOut (Laggy)";
}
void SetApiSettings(wxString api)
{
}
void ReadSettings()
{
}
void WriteSettings() const
{
}
void SetApiSettings(wxString api)
{
}
void WriteSettings() const
{
}
} static WO;

View File

@ -18,105 +18,102 @@
#include "Global.h"
#include "Dialogs.h"
int SendDialogMsg( HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam)
int SendDialogMsg(HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam)
{
return SendMessage( GetDlgItem(hwnd,dlgId), code, wParam, lParam );
return SendMessage(GetDlgItem(hwnd, dlgId), code, wParam, lParam);
}
HRESULT GUIDFromString(const wchar_t *str, LPGUID guid)
{
// "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
// "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
// VS2015 supports the hh format specifier (finally). VS2013 doesn't though,
// so this will do for now.
u32 guid_u32;
u16 guid_u16[2];
u16 guid_u8[8];
// VS2015 supports the hh format specifier (finally). VS2013 doesn't though,
// so this will do for now.
u32 guid_u32;
u16 guid_u16[2];
u16 guid_u8[8];
int r = swscanf_s(str,L"{%08x-%04hx-%04hx-%02hx%02hx-%02hx%02hx%02hx%02hx%02hx%02hx}",
&guid_u32,
&guid_u16[0],
&guid_u16[1],
&guid_u8[0],
&guid_u8[1],
&guid_u8[2],
&guid_u8[3],
&guid_u8[4],
&guid_u8[5],
&guid_u8[6],
&guid_u8[7]
);
int r = swscanf_s(str, L"{%08x-%04hx-%04hx-%02hx%02hx-%02hx%02hx%02hx%02hx%02hx%02hx}",
&guid_u32,
&guid_u16[0],
&guid_u16[1],
&guid_u8[0],
&guid_u8[1],
&guid_u8[2],
&guid_u8[3],
&guid_u8[4],
&guid_u8[5],
&guid_u8[6],
&guid_u8[7]);
if(r!=11) return -1;
if (r != 11)
return -1;
guid->Data1 = guid_u32;
guid->Data2 = guid_u16[0];
guid->Data3 = guid_u16[1];
guid->Data4[0] = (u8)guid_u8[0];
guid->Data4[1] = (u8)guid_u8[1];
guid->Data4[2] = (u8)guid_u8[2];
guid->Data4[3] = (u8)guid_u8[3];
guid->Data4[4] = (u8)guid_u8[4];
guid->Data4[5] = (u8)guid_u8[5];
guid->Data4[6] = (u8)guid_u8[6];
guid->Data4[7] = (u8)guid_u8[7];
return 0;
guid->Data1 = guid_u32;
guid->Data2 = guid_u16[0];
guid->Data3 = guid_u16[1];
guid->Data4[0] = (u8)guid_u8[0];
guid->Data4[1] = (u8)guid_u8[1];
guid->Data4[2] = (u8)guid_u8[2];
guid->Data4[3] = (u8)guid_u8[3];
guid->Data4[4] = (u8)guid_u8[4];
guid->Data4[5] = (u8)guid_u8[5];
guid->Data4[6] = (u8)guid_u8[6];
guid->Data4[7] = (u8)guid_u8[7];
return 0;
}
__forceinline void Verifyc(HRESULT hr, const char* fn)
__forceinline void Verifyc(HRESULT hr, const char *fn)
{
if(FAILED(hr))
{
assert( 0 );
throw std::runtime_error( "DirectSound returned an error from %s" );
}
if (FAILED(hr)) {
assert(0);
throw std::runtime_error("DirectSound returned an error from %s");
}
}
void AssignSliderValue( HWND idcwnd, HWND hwndDisplay, int value )
void AssignSliderValue(HWND idcwnd, HWND hwndDisplay, int value)
{
value = std::min( std::max( value, 0 ), 512 );
SendMessage(idcwnd,TBM_SETPOS,TRUE,value);
value = std::min(std::max(value, 0), 512);
SendMessage(idcwnd, TBM_SETPOS, TRUE, value);
wchar_t tbox[32];
swprintf_s( tbox, L"%d", value );
SetWindowText( hwndDisplay, tbox );
wchar_t tbox[32];
swprintf_s(tbox, L"%d", value);
SetWindowText(hwndDisplay, tbox);
}
void AssignSliderValue( HWND hWnd, int idc, int editbox, int value )
void AssignSliderValue(HWND hWnd, int idc, int editbox, int value)
{
AssignSliderValue( GetDlgItem( hWnd, idc ), GetDlgItem( hWnd, editbox ), value );
AssignSliderValue(GetDlgItem(hWnd, idc), GetDlgItem(hWnd, editbox), value);
}
// Generic slider/scroller message handler. This is succient so long as you
// don't need some kind of secondary event handling functionality, such as
// updating a custom label.
BOOL DoHandleScrollMessage( HWND hwndDisplay, WPARAM wParam, LPARAM lParam )
BOOL DoHandleScrollMessage(HWND hwndDisplay, WPARAM wParam, LPARAM lParam)
{
int wmId = LOWORD(wParam);
int wmEvent = HIWORD(wParam);
switch(wmId)
{
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
wmEvent = (int)SendMessage((HWND)lParam,TBM_GETPOS,0,0);
case TB_THUMBTRACK:
AssignSliderValue( (HWND)lParam, hwndDisplay, wmEvent );
break;
int wmId = LOWORD(wParam);
int wmEvent = HIWORD(wParam);
default:
return FALSE;
}
return TRUE;
switch (wmId) {
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
wmEvent = (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
case TB_THUMBTRACK:
AssignSliderValue((HWND)lParam, hwndDisplay, wmEvent);
break;
default:
return FALSE;
}
return TRUE;
}
int GetSliderValue( HWND hWnd, int idc )
int GetSliderValue(HWND hWnd, int idc)
{
int retval = (int)SendMessage( GetDlgItem( hWnd, idc ), TBM_GETPOS, 0, 0 );
return GetClamped( retval, 0, 512 );
int retval = (int)SendMessage(GetDlgItem(hWnd, idc), TBM_GETPOS, 0, 0);
return GetClamped(retval, 0, 512);
}

View File

@ -31,20 +31,28 @@
extern HINSTANCE hInstance;
#define SET_CHECK(idc,value) SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,((value)==0)?BST_UNCHECKED:BST_CHECKED,0)
#define HANDLE_CHECK(idc,hvar) case idc: (hvar) = !(hvar); SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,(hvar)?BST_CHECKED:BST_UNCHECKED,0); break
#define HANDLE_CHECKNB(idc,hvar)case idc: (hvar) = !(hvar); SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,(hvar)?BST_CHECKED:BST_UNCHECKED,0)
#define ENABLE_CONTROL(idc,value) EnableWindow(GetDlgItem(hWnd,idc),value)
#define SET_CHECK(idc, value) SendMessage(GetDlgItem(hWnd, idc), BM_SETCHECK, ((value) == 0) ? BST_UNCHECKED : BST_CHECKED, 0)
#define HANDLE_CHECK(idc, hvar) \
case idc: \
(hvar) = !(hvar); \
SendMessage(GetDlgItem(hWnd, idc), BM_SETCHECK, (hvar) ? BST_CHECKED : BST_UNCHECKED, 0); \
break
#define HANDLE_CHECKNB(idc, hvar) \
case idc: \
(hvar) = !(hvar); \
SendMessage(GetDlgItem(hWnd, idc), BM_SETCHECK, (hvar) ? BST_CHECKED : BST_UNCHECKED, 0)
#define ENABLE_CONTROL(idc, value) EnableWindow(GetDlgItem(hWnd, idc), value)
#define INIT_SLIDER(idc,minrange,maxrange,tickfreq,pagesize,linesize) \
SendMessage(GetDlgItem(hWnd,idc),TBM_SETRANGEMIN,FALSE,minrange); \
SendMessage(GetDlgItem(hWnd,idc),TBM_SETRANGEMAX,FALSE,maxrange); \
SendMessage(GetDlgItem(hWnd,idc),TBM_SETTICFREQ,tickfreq,0); \
SendMessage(GetDlgItem(hWnd,idc),TBM_SETPAGESIZE,0,pagesize); \
SendMessage(GetDlgItem(hWnd,idc),TBM_SETLINESIZE,0,linesize)
#define INIT_SLIDER(idc, minrange, maxrange, tickfreq, pagesize, linesize) \
SendMessage(GetDlgItem(hWnd, idc), TBM_SETRANGEMIN, FALSE, minrange); \
SendMessage(GetDlgItem(hWnd, idc), TBM_SETRANGEMAX, FALSE, maxrange); \
SendMessage(GetDlgItem(hWnd, idc), TBM_SETTICFREQ, tickfreq, 0); \
SendMessage(GetDlgItem(hWnd, idc), TBM_SETPAGESIZE, 0, pagesize); \
SendMessage(GetDlgItem(hWnd, idc), TBM_SETLINESIZE, 0, linesize)
#define HANDLE_SCROLL_MESSAGE(idc,idcDisplay) \
if((HWND)lParam == GetDlgItem(hWnd,idc)) return DoHandleScrollMessage( GetDlgItem(hWnd,idcDisplay), wParam, lParam )
#define HANDLE_SCROLL_MESSAGE(idc, idcDisplay) \
if ((HWND)lParam == GetDlgItem(hWnd, idc)) \
return DoHandleScrollMessage(GetDlgItem(hWnd, idcDisplay), wParam, lParam)
// *** BEGIN DRIVER-SPECIFIC CONFIGURATION ***
@ -52,26 +60,26 @@ extern HINSTANCE hInstance;
struct CONFIG_XAUDIO2
{
wxString Device;
s8 NumBuffers;
wxString Device;
s8 NumBuffers;
CONFIG_XAUDIO2() :
Device(),
NumBuffers( 2 )
{
}
CONFIG_XAUDIO2()
: Device()
, NumBuffers(2)
{
}
};
struct CONFIG_WAVEOUT
{
wxString Device;
s8 NumBuffers;
wxString Device;
s8 NumBuffers;
CONFIG_WAVEOUT() :
Device(),
NumBuffers( 4 )
{
}
CONFIG_WAVEOUT()
: Device()
, NumBuffers(4)
{
}
};
extern CONFIG_WAVEOUT Config_WaveOut;

View File

@ -26,14 +26,14 @@
extern "C" {
#include "dsp.h"
typedef winampDSPHeader* (*pWinampDSPGetHeader2)();
typedef winampDSPHeader *(*pWinampDSPGetHeader2)();
}
HMODULE hLib = NULL;
pWinampDSPGetHeader2 pGetHeader = NULL;
winampDSPHeader* pHeader = NULL;
winampDSPHeader *pHeader = NULL;
winampDSPModule* pModule = NULL;
winampDSPModule *pModule = NULL;
HWND hTemp;
@ -50,92 +50,91 @@ DWORD WINAPI DspUpdateThread(PVOID param);
s32 DspLoadLibrary(wchar_t *fileName, int modNum)
#ifdef USE_A_THREAD
{
if(!dspPluginEnabled) return -1;
if (!dspPluginEnabled)
return -1;
running=true;
hUpdateThread = CreateThread(NULL,0,DspUpdateThread,NULL,0,&UpdateThreadId);
return (hUpdateThread==INVALID_HANDLE_VALUE);
running = true;
hUpdateThread = CreateThread(NULL, 0, DspUpdateThread, NULL, 0, &UpdateThreadId);
return (hUpdateThread == INVALID_HANDLE_VALUE);
}
s32 DspLoadLibrary2( wchar_t *fileName, int modNum )
s32 DspLoadLibrary2(wchar_t *fileName, int modNum)
#endif
{
if( !dspPluginEnabled ) return -1;
if (!dspPluginEnabled)
return -1;
hLib = LoadLibraryW( fileName );
if(!hLib)
{
return 1;
}
hLib = LoadLibraryW(fileName);
if (!hLib) {
return 1;
}
pGetHeader = (pWinampDSPGetHeader2)GetProcAddress(hLib,"winampDSPGetHeader2");
pGetHeader = (pWinampDSPGetHeader2)GetProcAddress(hLib, "winampDSPGetHeader2");
if(!pGetHeader)
{
FreeLibrary(hLib);
hLib=NULL;
return 1;
}
if (!pGetHeader) {
FreeLibrary(hLib);
hLib = NULL;
return 1;
}
pHeader = pGetHeader();
pHeader = pGetHeader();
pModule = pHeader->getModule(modNum);
pModule = pHeader->getModule(modNum);
if(!pModule)
{
pGetHeader=NULL;
pHeader=NULL;
FreeLibrary(hLib);
hLib=NULL;
return -1;
}
if (!pModule) {
pGetHeader = NULL;
pHeader = NULL;
FreeLibrary(hLib);
hLib = NULL;
return -1;
}
pModule->hDllInstance = hLib;
pModule->hwndParent=0;
pModule->Init(pModule);
pModule->hDllInstance = hLib;
pModule->hwndParent = 0;
pModule->Init(pModule);
return 0;
return 0;
}
void DspCloseLibrary()
#ifdef USE_A_THREAD
{
if(!dspPluginEnabled) return ;
if (!dspPluginEnabled)
return;
PostThreadMessage(UpdateThreadId,WM_QUIT,0,0);
running=false;
if(WaitForSingleObject(hUpdateThread,1000)==WAIT_TIMEOUT)
{
ConLog("SPU2-X: WARNING: DSP Thread did not close itself in time. Assuming hung. Terminating.\n");
TerminateThread(hUpdateThread,1);
}
PostThreadMessage(UpdateThreadId, WM_QUIT, 0, 0);
running = false;
if (WaitForSingleObject(hUpdateThread, 1000) == WAIT_TIMEOUT) {
ConLog("SPU2-X: WARNING: DSP Thread did not close itself in time. Assuming hung. Terminating.\n");
TerminateThread(hUpdateThread, 1);
}
}
void DspCloseLibrary2()
#endif
{
if(!dspPluginEnabled) return ;
if (!dspPluginEnabled)
return;
if(hLib)
{
pModule->Quit(pModule);
FreeLibrary(hLib);
}
pModule=NULL;
pHeader=NULL;
pGetHeader=NULL;
hLib=NULL;
if (hLib) {
pModule->Quit(pModule);
FreeLibrary(hLib);
}
pModule = NULL;
pHeader = NULL;
pGetHeader = NULL;
hLib = NULL;
}
int DspProcess(s16 *buffer, int samples)
{
if(!dspPluginEnabled) return samples;
if (!dspPluginEnabled)
return samples;
if(hLib)
{
return pModule->ModifySamples(pModule,buffer,samples,16,2,SampleRate);
}
return samples;
if (hLib) {
return pModule->ModifySamples(pModule, buffer, samples, 16, 2, SampleRate);
}
return samples;
}
void DspUpdate()
@ -145,37 +144,36 @@ void DspUpdate()
DWORD WINAPI DspUpdateThread(PVOID param)
{
if( !dspPluginEnabled ) return -1;
if (!dspPluginEnabled)
return -1;
if( DspLoadLibrary2( dspPlugin, dspPluginModule ) )
return -1;
if (DspLoadLibrary2(dspPlugin, dspPluginModule))
return -1;
MSG msg;
while(running)
{
GetMessage(&msg,0,0,0);
if((msg.hwnd==NULL)&&(msg.message==WM_QUIT))
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
MSG msg;
while (running) {
GetMessage(&msg, 0, 0, 0);
if ((msg.hwnd == NULL) && (msg.message == WM_QUIT)) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DspCloseLibrary2();
return 0;
DspCloseLibrary2();
return 0;
}
#else
{
if(!dspPluginEnabled) return;
if (!dspPluginEnabled)
return;
MSG msg;
while(PeekMessage(&msg,0,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#endif

View File

@ -27,32 +27,34 @@
#pragma once
typedef struct winampDSPModule {
char *description; // description
HWND hwndParent; // parent window (filled in by calling app)
HINSTANCE hDllInstance; // instance handle to this DLL (filled in by calling app)
typedef struct winampDSPModule
{
char *description; // description
HWND hwndParent; // parent window (filled in by calling app)
HINSTANCE hDllInstance; // instance handle to this DLL (filled in by calling app)
void (*Config)(struct winampDSPModule *this_mod); // configuration dialog (if needed)
int (*Init)(struct winampDSPModule *this_mod); // 0 on success, creates window, etc (if needed)
void (*Config)(struct winampDSPModule *this_mod); // configuration dialog (if needed)
int (*Init)(struct winampDSPModule *this_mod); // 0 on success, creates window, etc (if needed)
// modify waveform samples: returns number of samples to actually write
// (typically numsamples, but no more than twice numsamples, and no less than half numsamples)
// numsamples should always be at least 128. should, but I'm not sure
int (*ModifySamples)(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate);
// modify waveform samples: returns number of samples to actually write
// (typically numsamples, but no more than twice numsamples, and no less than half numsamples)
// numsamples should always be at least 128. should, but I'm not sure
int (*ModifySamples)(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate);
void (*Quit)(struct winampDSPModule *this_mod); // called when unloading
void (*Quit)(struct winampDSPModule *this_mod); // called when unloading
void *userData; // user data, optional
void *userData; // user data, optional
} winampDSPModule;
typedef struct {
int version; // DSP_HDRVER
char *description; // description of library
winampDSPModule* (*getModule)(int); // module retrieval function
typedef struct
{
int version; // DSP_HDRVER
char *description; // description of library
winampDSPModule *(*getModule)(int); // module retrieval function
} winampDSPHeader;
// exported symbols
typedef winampDSPHeader* (*winampDSPGetHeaderType)();
typedef winampDSPHeader *(*winampDSPGetHeaderType)();
// header version: 0x20 == 0.20 == winamp 2.0
#define DSP_HDRVER 0x20

View File

@ -23,176 +23,176 @@
// SPU2 Memory Indexers
// --------------------------------------------------------------------------------------
#define spu2Rs16(mmem) (*(s16 *)((s8 *)spu2regs + ((mmem) & 0x1fff)))
#define spu2Ru16(mmem) (*(u16 *)((s8 *)spu2regs + ((mmem) & 0x1fff)))
#define spu2Rs16(mmem) (*(s16 *)((s8 *)spu2regs + ((mmem)&0x1fff)))
#define spu2Ru16(mmem) (*(u16 *)((s8 *)spu2regs + ((mmem)&0x1fff)))
extern s16* GetMemPtr(u32 addr);
extern s16 spu2M_Read( u32 addr );
extern void spu2M_Write( u32 addr, s16 value );
extern void spu2M_Write( u32 addr, u16 value );
extern s16 *GetMemPtr(u32 addr);
extern s16 spu2M_Read(u32 addr);
extern void spu2M_Write(u32 addr, s16 value);
extern void spu2M_Write(u32 addr, u16 value);
struct V_VolumeLR
{
static V_VolumeLR Max;
static V_VolumeLR Max;
s32 Left;
s32 Right;
s32 Left;
s32 Right;
V_VolumeLR() {}
V_VolumeLR( s32 both ) :
Left( both ),
Right( both )
{
}
V_VolumeLR() {}
V_VolumeLR(s32 both)
: Left(both)
, Right(both)
{
}
void DebugDump( FILE* dump, const char* title );
void DebugDump(FILE *dump, const char *title);
};
struct V_VolumeSlide
{
// Holds the "original" value of the volume for this voice, prior to slides.
// (ie, the volume as written to the register)
// Holds the "original" value of the volume for this voice, prior to slides.
// (ie, the volume as written to the register)
s16 Reg_VOL;
s32 Value;
s8 Increment;
s8 Mode;
s16 Reg_VOL;
s32 Value;
s8 Increment;
s8 Mode;
public:
V_VolumeSlide() {}
V_VolumeSlide( s16 regval, s32 fullvol ) :
Reg_VOL( regval ),
Value( fullvol ),
Increment( 0 ),
Mode( 0 )
{
}
V_VolumeSlide() {}
V_VolumeSlide(s16 regval, s32 fullvol)
: Reg_VOL(regval)
, Value(fullvol)
, Increment(0)
, Mode(0)
{
}
void Update();
void RegSet( u16 src ); // used to set the volume from a register source (16 bit signed)
void DebugDump( FILE* dump, const char* title, const char* nameLR );
void Update();
void RegSet(u16 src); // used to set the volume from a register source (16 bit signed)
void DebugDump(FILE *dump, const char *title, const char *nameLR);
};
struct V_VolumeSlideLR
{
static V_VolumeSlideLR Max;
static V_VolumeSlideLR Max;
V_VolumeSlide Left;
V_VolumeSlide Right;
V_VolumeSlide Left;
V_VolumeSlide Right;
public:
V_VolumeSlideLR() {}
V_VolumeSlideLR() {}
V_VolumeSlideLR( s16 regval, s32 bothval ) :
Left( regval, bothval ),
Right( regval, bothval )
{
}
V_VolumeSlideLR(s16 regval, s32 bothval)
: Left(regval, bothval)
, Right(regval, bothval)
{
}
void Update()
{
Left.Update();
Right.Update();
}
void Update()
{
Left.Update();
Right.Update();
}
void DebugDump( FILE* dump, const char* title );
void DebugDump(FILE *dump, const char *title);
};
struct V_ADSR
{
union
{
u32 reg32;
union
{
u32 reg32;
struct
{
u16 regADSR1;
u16 regADSR2;
};
struct
{
u16 regADSR1;
u16 regADSR2;
};
struct
{
u32 SustainLevel:4,
DecayRate:4,
AttackRate:7,
AttackMode:1, // 0 for linear (+lin), 1 for pseudo exponential (+exp)
struct
{
u32 SustainLevel : 4,
DecayRate : 4,
AttackRate : 7,
AttackMode : 1, // 0 for linear (+lin), 1 for pseudo exponential (+exp)
ReleaseRate:5,
ReleaseMode:1, // 0 for linear (-lin), 1 for exponential (-exp)
SustainRate:7,
SustainMode:3; // 0 = +lin, 1 = -lin, 2 = +exp, 3 = -exp
};
};
ReleaseRate : 5,
ReleaseMode : 1, // 0 for linear (-lin), 1 for exponential (-exp)
SustainRate : 7,
SustainMode : 3; // 0 = +lin, 1 = -lin, 2 = +exp, 3 = -exp
};
};
s32 Value; // Ranges from 0 to 0x7fffffff (signed values are clamped to 0) [Reg_ENVX]
u8 Phase; // monitors current phase of ADSR envelope
bool Releasing; // Ready To Release, triggered by Voice.Stop();
s32 Value; // Ranges from 0 to 0x7fffffff (signed values are clamped to 0) [Reg_ENVX]
u8 Phase; // monitors current phase of ADSR envelope
bool Releasing; // Ready To Release, triggered by Voice.Stop();
public:
bool Calculate();
bool Calculate();
};
struct V_Voice
{
u32 PlayCycle; // SPU2 cycle where the Playing started
u32 PlayCycle; // SPU2 cycle where the Playing started
V_VolumeSlideLR Volume;
V_VolumeSlideLR Volume;
// Envelope
V_ADSR ADSR;
// Pitch (also Reg_PITCH)
u16 Pitch;
// Loop Start address (also Reg_LSAH/L)
u32 LoopStartA;
// Sound Start address (also Reg_SSAH/L)
u32 StartA;
// Next Read Data address (also Reg_NAXH/L)
u32 NextA;
// Voice Decoding State
s32 Prev1;
s32 Prev2;
// Envelope
V_ADSR ADSR;
// Pitch (also Reg_PITCH)
u16 Pitch;
// Loop Start address (also Reg_LSAH/L)
u32 LoopStartA;
// Sound Start address (also Reg_SSAH/L)
u32 StartA;
// Next Read Data address (also Reg_NAXH/L)
u32 NextA;
// Voice Decoding State
s32 Prev1;
s32 Prev2;
// Pitch Modulated by previous voice
bool Modulated;
// Source (Wave/Noise)
bool Noise;
// Pitch Modulated by previous voice
bool Modulated;
// Source (Wave/Noise)
bool Noise;
s8 LoopMode;
s8 LoopFlags;
s8 LoopMode;
s8 LoopFlags;
// Sample pointer (19:12 bit fixed point)
s32 SP;
// Sample pointer (19:12 bit fixed point)
s32 SP;
// Sample pointer for Cubic Interpolation
// Cubic interpolation mixes a sample behind Linear, so that it
// can have sample data to either side of the end points from which
// to extrapolate. This SP represents that late sample position.
s32 SPc;
// Sample pointer for Cubic Interpolation
// Cubic interpolation mixes a sample behind Linear, so that it
// can have sample data to either side of the end points from which
// to extrapolate. This SP represents that late sample position.
s32 SPc;
// Previous sample values - used for interpolation
// Inverted order of these members to match the access order in the
// code (might improve cache hits).
s32 PV4;
s32 PV3;
s32 PV2;
s32 PV1;
// Previous sample values - used for interpolation
// Inverted order of these members to match the access order in the
// code (might improve cache hits).
s32 PV4;
s32 PV3;
s32 PV2;
s32 PV1;
// Last outputted audio value, used for voice modulation.
s32 OutX;
s32 NextCrest; // temp value for Crest calculation
// Last outputted audio value, used for voice modulation.
s32 OutX;
s32 NextCrest; // temp value for Crest calculation
// SBuffer now points directly to an ADPCM cache entry.
s16 *SBuffer;
// SBuffer now points directly to an ADPCM cache entry.
s16 *SBuffer;
// sample position within the current decoded packet.
s32 SCurrent;
// sample position within the current decoded packet.
s32 SCurrent;
// it takes a few ticks for voices to start on the real SPU2?
void QueueStart();
bool Start();
void Stop();
// it takes a few ticks for voices to start on the real SPU2?
void QueueStart();
bool Start();
void Stop();
};
// ** Begin Debug-only variables section **
@ -200,25 +200,25 @@ struct V_Voice
// the Public Release build.
struct V_VoiceDebug
{
s8 FirstBlock;
s32 SampleData;
s32 PeakX;
s32 displayPeak;
s32 lastSetStartA;
s8 FirstBlock;
s32 SampleData;
s32 PeakX;
s32 displayPeak;
s32 lastSetStartA;
};
struct V_CoreDebug
{
V_VoiceDebug Voices[24];
// Last Transfer Size
u32 lastsize;
V_VoiceDebug Voices[24];
// Last Transfer Size
u32 lastsize;
// draw adma waveform in the visual debugger
s32 admaWaveformL[0x100];
s32 admaWaveformR[0x100];
// draw adma waveform in the visual debugger
s32 admaWaveformL[0x100];
s32 admaWaveformR[0x100];
// Enabled when a dma write starts, disabled when the visual debugger showed it once
s32 dmaFlag;
// Enabled when a dma write starts, disabled when the visual debugger showed it once
s32 dmaFlag;
};
// Debug tracking information - 24 voices and 2 cores.
@ -226,338 +226,343 @@ extern V_CoreDebug DebugCores[2];
struct V_Reverb
{
s16 IN_COEF_L;
s16 IN_COEF_R;
s16 IN_COEF_L;
s16 IN_COEF_R;
u32 FB_SRC_A;
u32 FB_SRC_B;
u32 FB_SRC_A;
u32 FB_SRC_B;
s16 FB_ALPHA;
s16 FB_X;
s16 FB_ALPHA;
s16 FB_X;
u32 IIR_SRC_A0;
u32 IIR_SRC_A1;
u32 IIR_SRC_B1;
u32 IIR_SRC_B0;
u32 IIR_DEST_A0;
u32 IIR_DEST_A1;
u32 IIR_DEST_B0;
u32 IIR_DEST_B1;
u32 IIR_SRC_A0;
u32 IIR_SRC_A1;
u32 IIR_SRC_B1;
u32 IIR_SRC_B0;
u32 IIR_DEST_A0;
u32 IIR_DEST_A1;
u32 IIR_DEST_B0;
u32 IIR_DEST_B1;
s16 IIR_ALPHA;
s16 IIR_COEF;
s16 IIR_ALPHA;
s16 IIR_COEF;
u32 ACC_SRC_A0;
u32 ACC_SRC_A1;
u32 ACC_SRC_B0;
u32 ACC_SRC_B1;
u32 ACC_SRC_C0;
u32 ACC_SRC_C1;
u32 ACC_SRC_D0;
u32 ACC_SRC_D1;
u32 ACC_SRC_A0;
u32 ACC_SRC_A1;
u32 ACC_SRC_B0;
u32 ACC_SRC_B1;
u32 ACC_SRC_C0;
u32 ACC_SRC_C1;
u32 ACC_SRC_D0;
u32 ACC_SRC_D1;
s16 ACC_COEF_A;
s16 ACC_COEF_B;
s16 ACC_COEF_C;
s16 ACC_COEF_D;
s16 ACC_COEF_A;
s16 ACC_COEF_B;
s16 ACC_COEF_C;
s16 ACC_COEF_D;
u32 MIX_DEST_A0;
u32 MIX_DEST_A1;
u32 MIX_DEST_B0;
u32 MIX_DEST_B1;
u32 MIX_DEST_A0;
u32 MIX_DEST_A1;
u32 MIX_DEST_B0;
u32 MIX_DEST_B1;
};
struct V_ReverbBuffers
{
s32 FB_SRC_A0;
s32 FB_SRC_B0;
s32 FB_SRC_A1;
s32 FB_SRC_B1;
s32 FB_SRC_A0;
s32 FB_SRC_B0;
s32 FB_SRC_A1;
s32 FB_SRC_B1;
s32 IIR_SRC_A0;
s32 IIR_SRC_A1;
s32 IIR_SRC_B0;
s32 IIR_SRC_B1;
s32 IIR_DEST_A0;
s32 IIR_DEST_A1;
s32 IIR_DEST_B0;
s32 IIR_DEST_B1;
s32 IIR_SRC_A0;
s32 IIR_SRC_A1;
s32 IIR_SRC_B0;
s32 IIR_SRC_B1;
s32 IIR_DEST_A0;
s32 IIR_DEST_A1;
s32 IIR_DEST_B0;
s32 IIR_DEST_B1;
s32 ACC_SRC_A0;
s32 ACC_SRC_A1;
s32 ACC_SRC_B0;
s32 ACC_SRC_B1;
s32 ACC_SRC_C0;
s32 ACC_SRC_C1;
s32 ACC_SRC_D0;
s32 ACC_SRC_D1;
s32 ACC_SRC_A0;
s32 ACC_SRC_A1;
s32 ACC_SRC_B0;
s32 ACC_SRC_B1;
s32 ACC_SRC_C0;
s32 ACC_SRC_C1;
s32 ACC_SRC_D0;
s32 ACC_SRC_D1;
s32 MIX_DEST_A0;
s32 MIX_DEST_A1;
s32 MIX_DEST_B0;
s32 MIX_DEST_B1;
s32 MIX_DEST_A0;
s32 MIX_DEST_A1;
s32 MIX_DEST_B0;
s32 MIX_DEST_B1;
bool NeedsUpdated;
bool NeedsUpdated;
};
struct V_SPDIF
{
u16 Out;
u16 Info;
u16 Unknown1;
u16 Mode;
u16 Media;
u16 Unknown2;
u16 Protection;
u16 Out;
u16 Info;
u16 Unknown1;
u16 Mode;
u16 Media;
u16 Unknown2;
u16 Protection;
};
struct V_CoreRegs
{
u32 PMON;
u32 NON;
u32 VMIXL;
u32 VMIXR;
u32 VMIXEL;
u32 VMIXER;
u32 ENDX;
u32 PMON;
u32 NON;
u32 VMIXL;
u32 VMIXR;
u32 VMIXEL;
u32 VMIXER;
u32 ENDX;
u16 MMIX;
u16 STATX;
u16 ATTR;
u16 _1AC;
u16 MMIX;
u16 STATX;
u16 ATTR;
u16 _1AC;
};
struct V_VoiceGates
{
s16 DryL; // 'AND Gate' for Direct Output to Left Channel
s16 DryR; // 'AND Gate' for Direct Output for Right Channel
s16 WetL; // 'AND Gate' for Effect Output for Left Channel
s16 WetR; // 'AND Gate' for Effect Output for Right Channel
s16 DryL; // 'AND Gate' for Direct Output to Left Channel
s16 DryR; // 'AND Gate' for Direct Output for Right Channel
s16 WetL; // 'AND Gate' for Effect Output for Left Channel
s16 WetR; // 'AND Gate' for Effect Output for Right Channel
};
struct V_CoreGates
{
union
{
u128 v128;
struct
{
s16 InpL; // Sound Data Input to Direct Output (Left)
s16 InpR; // Sound Data Input to Direct Output (Right)
s16 SndL; // Voice Data to Direct Output (Left)
s16 SndR; // Voice Data to Direct Output (Right)
s16 ExtL; // External Input to Direct Output (Left)
s16 ExtR; // External Input to Direct Output (Right)
};
};
union
{
u128 v128;
struct
{
s16 InpL; // Sound Data Input to Direct Output (Left)
s16 InpR; // Sound Data Input to Direct Output (Right)
s16 SndL; // Voice Data to Direct Output (Left)
s16 SndR; // Voice Data to Direct Output (Right)
s16 ExtL; // External Input to Direct Output (Left)
s16 ExtR; // External Input to Direct Output (Right)
};
};
};
struct VoiceMixSet
{
static const VoiceMixSet Empty;
StereoOut32 Dry, Wet;
static const VoiceMixSet Empty;
StereoOut32 Dry, Wet;
VoiceMixSet() {}
VoiceMixSet( const StereoOut32& dry, const StereoOut32& wet ) :
Dry( dry ),
Wet( wet )
{
}
VoiceMixSet() {}
VoiceMixSet(const StereoOut32 &dry, const StereoOut32 &wet)
: Dry(dry)
, Wet(wet)
{
}
};
struct V_Core
{
static const uint NumVoices = 24;
static const uint NumVoices = 24;
int Index; // Core index identifier.
int Index; // Core index identifier.
// Voice Gates -- These are SSE-related values, and must always be
// first to ensure 16 byte alignment
// Voice Gates -- These are SSE-related values, and must always be
// first to ensure 16 byte alignment
V_VoiceGates VoiceGates[NumVoices];
V_CoreGates DryGate;
V_CoreGates WetGate;
V_VoiceGates VoiceGates[NumVoices];
V_CoreGates DryGate;
V_CoreGates WetGate;
V_VolumeSlideLR MasterVol; // Master Volume
V_VolumeLR ExtVol; // Volume for External Data Input
V_VolumeLR InpVol; // Volume for Sound Data Input
V_VolumeLR FxVol; // Volume for Output from Effects
V_VolumeSlideLR MasterVol; // Master Volume
V_VolumeLR ExtVol; // Volume for External Data Input
V_VolumeLR InpVol; // Volume for Sound Data Input
V_VolumeLR FxVol; // Volume for Output from Effects
V_Voice Voices[NumVoices];
V_Voice Voices[NumVoices];
u32 IRQA; // Interrupt Address
u32 TSA; // DMA Transfer Start Address
u32 IRQA; // Interrupt Address
u32 TSA; // DMA Transfer Start Address
bool IRQEnable; // Interrupt Enable
bool FxEnable; // Effect Enable
bool Mute; // Mute
bool AdmaInProgress;
bool IRQEnable; // Interrupt Enable
bool FxEnable; // Effect Enable
bool Mute; // Mute
bool AdmaInProgress;
s8 DMABits; // DMA related?
s8 NoiseClk; // Noise Clock
u16 AutoDMACtrl; // AutoDMA Status
s32 DMAICounter; // DMA Interrupt Counter
u32 InputDataLeft; // Input Buffer
u32 InputPosRead;
u32 InputPosWrite;
u32 InputDataProgress;
s8 DMABits; // DMA related?
s8 NoiseClk; // Noise Clock
u16 AutoDMACtrl; // AutoDMA Status
s32 DMAICounter; // DMA Interrupt Counter
u32 InputDataLeft; // Input Buffer
u32 InputPosRead;
u32 InputPosWrite;
u32 InputDataProgress;
V_Reverb Revb; // Reverb Registers
V_ReverbBuffers RevBuffers; // buffer pointers for reverb, pre-calculated and pre-clipped.
u32 EffectsStartA;
u32 EffectsEndA;
u32 ExtEffectsStartA;
u32 ExtEffectsEndA;
u32 ReverbX;
V_Reverb Revb; // Reverb Registers
V_ReverbBuffers RevBuffers; // buffer pointers for reverb, pre-calculated and pre-clipped.
u32 EffectsStartA;
u32 EffectsEndA;
u32 ExtEffectsStartA;
u32 ExtEffectsEndA;
u32 ReverbX;
// Current size of and position of the effects buffer. Pre-caculated when the effects start
// or end position registers are written. CAN BE NEGATIVE OR ZERO, in which
// case reverb should be disabled.
s32 EffectsBufferSize;
u32 EffectsBufferStart;
// Current size of and position of the effects buffer. Pre-caculated when the effects start
// or end position registers are written. CAN BE NEGATIVE OR ZERO, in which
// case reverb should be disabled.
s32 EffectsBufferSize;
u32 EffectsBufferStart;
V_CoreRegs Regs; // Registers
V_CoreRegs Regs; // Registers
// Last samples to pass through the effects processor.
// Used because the effects processor works at 24khz and just pulls
// from this for the odd Ts.
StereoOut32 LastEffect;
// Last samples to pass through the effects processor.
// Used because the effects processor works at 24khz and just pulls
// from this for the odd Ts.
StereoOut32 LastEffect;
u8 CoreEnabled;
u8 CoreEnabled;
u8 AttrBit0;
u8 DmaMode;
u8 AttrBit0;
u8 DmaMode;
// new dma only
bool DmaStarted;
u32 AutoDmaFree;
// new dma only
bool DmaStarted;
u32 AutoDmaFree;
// old dma only
u16* DMAPtr;
u32 MADR;
u32 TADR;
// old dma only
u16 *DMAPtr;
u32 MADR;
u32 TADR;
u32 KeyOn; // not the KON register (though maybe it is)
u32 KeyOn; // not the KON register (though maybe it is)
// psxmode caches
u16 psxSoundDataTransferControl;
u16 psxSPUSTAT;
// psxmode caches
u16 psxSoundDataTransferControl;
u16 psxSPUSTAT;
StereoOut32 downbuf[8];
StereoOut32 upbuf[8];
int dbpos, ubpos;
StereoOut32 downbuf[8];
StereoOut32 upbuf[8];
int dbpos, ubpos;
// HACK -- This is a temp buffer which is (or isn't?) used to circumvent some memory
// corruption that originates elsewhere in the plugin. >_< The actual ADMA buffer
// is an area mapped to SPU2 main memory.
//s16 ADMATempBuffer[0x1000];
// HACK -- This is a temp buffer which is (or isn't?) used to circumvent some memory
// corruption that originates elsewhere in the plugin. >_< The actual ADMA buffer
// is an area mapped to SPU2 main memory.
//s16 ADMATempBuffer[0x1000];
// ----------------------------------------------------------------------------------
// V_Core Methods
// ----------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------
// V_Core Methods
// ----------------------------------------------------------------------------------
// uninitialized constructor
V_Core() : Index( -1 ), DMAPtr( NULL ) {}
V_Core( int idx ); // our badass constructor
~V_Core() throw();
// uninitialized constructor
V_Core()
: Index(-1)
, DMAPtr(NULL)
{
}
V_Core(int idx); // our badass constructor
~V_Core() throw();
void Init( int index );
void UpdateEffectsBufferSize();
void AnalyzeReverbPreset();
void Init(int index);
void UpdateEffectsBufferSize();
void AnalyzeReverbPreset();
s32 EffectsBufferIndexer( s32 offset ) const;
void UpdateFeedbackBuffersA();
void UpdateFeedbackBuffersB();
s32 EffectsBufferIndexer(s32 offset) const;
void UpdateFeedbackBuffersA();
void UpdateFeedbackBuffersB();
void WriteRegPS1( u32 mem, u16 value );
u16 ReadRegPS1( u32 mem );
void WriteRegPS1(u32 mem, u16 value);
u16 ReadRegPS1(u32 mem);
// --------------------------------------------------------------------------------------
// Mixer Section
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
// Mixer Section
// --------------------------------------------------------------------------------------
StereoOut32 Mix( const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext );
void Reverb_AdvanceBuffer();
StereoOut32 DoReverb( const StereoOut32& Input );
s32 RevbGetIndexer( s32 offset );
StereoOut32 Mix(const VoiceMixSet &inVoices, const StereoOut32 &Input, const StereoOut32 &Ext);
void Reverb_AdvanceBuffer();
StereoOut32 DoReverb(const StereoOut32 &Input);
s32 RevbGetIndexer(s32 offset);
StereoOut32 ReadInput();
StereoOut32 ReadInput_HiFi();
StereoOut32 ReadInput();
StereoOut32 ReadInput_HiFi();
// --------------------------------------------------------------------------
// DMA Section
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// DMA Section
// --------------------------------------------------------------------------
// Returns the index of the DMA channel (4 for Core 0, or 7 for Core 1)
int GetDmaIndex() const
{
return (Index == 0) ? 4 : 7;
}
// Returns the index of the DMA channel (4 for Core 0, or 7 for Core 1)
int GetDmaIndex() const
{
return (Index == 0) ? 4 : 7;
}
// returns either '4' or '7'
char GetDmaIndexChar() const
{
return 0x30 + GetDmaIndex();
}
// returns either '4' or '7'
char GetDmaIndexChar() const
{
return 0x30 + GetDmaIndex();
}
__forceinline u16 DmaRead()
{
const u16 ret = (u16)spu2M_Read(TSA);
++TSA; TSA &= 0xfffff;
return ret;
}
__forceinline u16 DmaRead()
{
const u16 ret = (u16)spu2M_Read(TSA);
++TSA;
TSA &= 0xfffff;
return ret;
}
__forceinline void DmaWrite(u16 value)
{
spu2M_Write( TSA, value );
++TSA; TSA &= 0xfffff;
}
__forceinline void DmaWrite(u16 value)
{
spu2M_Write(TSA, value);
++TSA;
TSA &= 0xfffff;
}
void LogAutoDMA( FILE* fp );
void LogAutoDMA(FILE *fp);
s32 NewDmaRead(u32* data, u32 bytesLeft, u32* bytesProcessed);
s32 NewDmaWrite(u32* data, u32 bytesLeft, u32* bytesProcessed);
void NewDmaInterrupt();
s32 NewDmaRead(u32 *data, u32 bytesLeft, u32 *bytesProcessed);
s32 NewDmaWrite(u32 *data, u32 bytesLeft, u32 *bytesProcessed);
void NewDmaInterrupt();
// old dma only
void DoDMAwrite(u16* pMem, u32 size);
void DoDMAread(u16* pMem, u32 size);
// old dma only
void DoDMAwrite(u16 *pMem, u32 size);
void DoDMAread(u16 *pMem, u32 size);
void AutoDMAReadBuffer(int mode);
void StartADMAWrite(u16 *pMem, u32 sz);
void PlainDMAWrite(u16 *pMem, u32 sz);
void AutoDMAReadBuffer(int mode);
void StartADMAWrite(u16 *pMem, u32 sz);
void PlainDMAWrite(u16 *pMem, u32 sz);
};
extern V_Core Cores[2];
extern V_SPDIF Spdif;
extern V_Core Cores[2];
extern V_SPDIF Spdif;
// Output Buffer Writing Position (the same for all data);
extern s16 OutPos;
extern s16 OutPos;
// Input Buffer Reading Position (the same for all data);
extern s16 InputPos;
extern s16 InputPos;
// SPU Mixing Cycles ("Ticks mixed" counter)
extern u32 Cycles;
extern u32 Cycles;
extern s16* spu2regs;
extern s16* _spu2mem;
extern int PlayMode;
extern s16 *spu2regs;
extern s16 *_spu2mem;
extern int PlayMode;
extern void SetIrqCall(int core);
extern void StartVoices(int core, u32 value);
extern void StopVoices(int core, u32 value);
extern void InitADSR();
extern void CalculateADSR( V_Voice& vc );
extern void CalculateADSR(V_Voice &vc);
extern void UpdateSpdifMode();
namespace Savestate
{
struct DataBlock;
struct DataBlock;
extern s32 __fastcall FreezeIt( DataBlock& spud );
extern s32 __fastcall ThawIt( DataBlock& spud );
extern s32 __fastcall SizeIt();
extern s32 __fastcall FreezeIt(DataBlock &spud);
extern s32 __fastcall ThawIt(DataBlock &spud);
extern s32 __fastcall SizeIt();
}
// --------------------------------------------------------------------------------------
@ -580,8 +585,8 @@ static const int pcm_DecodedSamplesPerBlock = 28;
struct PcmCacheEntry
{
bool Validated;
s16 Sampledata[pcm_DecodedSamplesPerBlock];
bool Validated;
s16 Sampledata[pcm_DecodedSamplesPerBlock];
};
extern PcmCacheEntry* pcm_cache_data;
extern PcmCacheEntry *pcm_cache_data;

View File

@ -17,78 +17,78 @@
#pragma once
#define SPU2_CORE0 0x00000000
#define SPU2_CORE1 0x00000400
#define SPU2_CORE0 0x00000000
#define SPU2_CORE1 0x00000400
#define SPU2_VP(voice) ((voice) * 16)
#define SPU2_VA(voice) ((voice) * 12)
#define SPU2_VP(voice) ((voice)*16)
#define SPU2_VA(voice) ((voice)*12)
#define REG_VP_VOLL 0x0000 // Voice Volume Left
#define REG_VP_VOLR 0x0002 // Voice Volume Right
#define REG_VP_PITCH 0x0004 // Pitch
#define REG_VP_ADSR1 0x0006 // Envelope 1 (Attack-Decay-Sustain-Release)
#define REG_VP_ADSR2 0x0008 // Envelope 2 (Attack-Decay-Sustain-Release)
#define REG_VP_ENVX 0x000A // Current Envelope
#define REG_VP_VOLXL 0x000C // Current Voice Volume Left
#define REG_VP_VOLXR 0x000E // Current Voice Volume Right
#define REG_VP_VOLL 0x0000 // Voice Volume Left
#define REG_VP_VOLR 0x0002 // Voice Volume Right
#define REG_VP_PITCH 0x0004 // Pitch
#define REG_VP_ADSR1 0x0006 // Envelope 1 (Attack-Decay-Sustain-Release)
#define REG_VP_ADSR2 0x0008 // Envelope 2 (Attack-Decay-Sustain-Release)
#define REG_VP_ENVX 0x000A // Current Envelope
#define REG_VP_VOLXL 0x000C // Current Voice Volume Left
#define REG_VP_VOLXR 0x000E // Current Voice Volume Right
// .. repeated for each voice ..
#define REG_S_PMON 0x0180 // Pitch Modulation Spec.
#define REG_S_NON 0x0184 // Alloc Noise Generator
#define REG_S_VMIXL 0x0188 // Voice Output Mix Left (Dry)
#define REG_S_VMIXEL 0x018C // Voice Output Mix Left (Wet)
#define REG_S_VMIXR 0x0190 // Voice Output Mix Right (Dry)
#define REG_S_VMIXER 0x0194 // Voice Output Mix Right (Wet)
#define REG_S_PMON 0x0180 // Pitch Modulation Spec.
#define REG_S_NON 0x0184 // Alloc Noise Generator
#define REG_S_VMIXL 0x0188 // Voice Output Mix Left (Dry)
#define REG_S_VMIXEL 0x018C // Voice Output Mix Left (Wet)
#define REG_S_VMIXR 0x0190 // Voice Output Mix Right (Dry)
#define REG_S_VMIXER 0x0194 // Voice Output Mix Right (Wet)
#define REG_P_MMIX 0x0198 // Output Spec. After Voice Mix
#define REG_C_ATTR 0x019A // Core X Attrib
#define REG_A_IRQA 0x019C // Interrupt Address Spec.
#define REG_P_MMIX 0x0198 // Output Spec. After Voice Mix
#define REG_C_ATTR 0x019A // Core X Attrib
#define REG_A_IRQA 0x019C // Interrupt Address Spec.
#define REG_S_KON 0x01A0 // Key On 0/1
#define REG_S_KOFF 0x01A4 // Key Off 0/1
#define REG_S_KON 0x01A0 // Key On 0/1
#define REG_S_KOFF 0x01A4 // Key Off 0/1
#define REG_A_TSA 0x01A8 // Transfer starting address
#define REG__1AC 0x01AC // Transfer data
#define REG__1AE 0x01AE
#define REG_S_ADMAS 0x01B0 // AutoDMA Status
#define REG_A_TSA 0x01A8 // Transfer starting address
#define REG__1AC 0x01AC // Transfer data
#define REG__1AE 0x01AE
#define REG_S_ADMAS 0x01B0 // AutoDMA Status
// 1b2, 1b4, 1b6, 1b8, 1ba, 1bc, 1be are unknown
#define REG_VA_SSA 0x01C0 // Waveform data starting address
#define REG_VA_LSAX 0x01C4 // Loop point address
#define REG_VA_NAX 0x01C8 // Waveform data that should be read next
#define REG_VA_SSA 0x01C0 // Waveform data starting address
#define REG_VA_LSAX 0x01C4 // Loop point address
#define REG_VA_NAX 0x01C8 // Waveform data that should be read next
// .. repeated for each voice ..
#define REG_A_ESA 0x02E0 //Address: Top address of working area for effects processing
#define R_FB_SRC_A 0x02E4 // Feedback Source A
#define R_FB_SRC_B 0x02E8 // Feedback Source B
#define R_IIR_DEST_A0 0x02EC
#define R_IIR_DEST_A1 0x02F0
#define R_ACC_SRC_A0 0x02F4
#define R_ACC_SRC_A1 0x02F8
#define R_ACC_SRC_B0 0x02FC
#define R_ACC_SRC_B1 0x0300
#define R_IIR_SRC_A0 0x0304
#define R_IIR_SRC_A1 0x0308
#define R_IIR_DEST_B0 0x030C
#define R_IIR_DEST_B1 0x0310
#define R_ACC_SRC_C0 0x0314
#define R_ACC_SRC_C1 0x0318
#define R_ACC_SRC_D0 0x031C
#define R_ACC_SRC_D1 0x0320
#define R_IIR_SRC_B0 0x0324 // Some sources have R_IIR_SRC_B0 and R_IIR_SRC_B1 swapped ><
#define R_IIR_SRC_B1 0x0328 // Assume a typo in the docs and B0 is actually at 324, B1 at 328 in the HW.
#define R_MIX_DEST_A0 0x032C
#define R_MIX_DEST_A1 0x0330
#define R_MIX_DEST_B0 0x0334
#define R_MIX_DEST_B1 0x0338
#define REG_A_EEA 0x033C // Address: End address of working area for effects processing (upper part of address only!)
#define REG_A_ESA 0x02E0 //Address: Top address of working area for effects processing
#define R_FB_SRC_A 0x02E4 // Feedback Source A
#define R_FB_SRC_B 0x02E8 // Feedback Source B
#define R_IIR_DEST_A0 0x02EC
#define R_IIR_DEST_A1 0x02F0
#define R_ACC_SRC_A0 0x02F4
#define R_ACC_SRC_A1 0x02F8
#define R_ACC_SRC_B0 0x02FC
#define R_ACC_SRC_B1 0x0300
#define R_IIR_SRC_A0 0x0304
#define R_IIR_SRC_A1 0x0308
#define R_IIR_DEST_B0 0x030C
#define R_IIR_DEST_B1 0x0310
#define R_ACC_SRC_C0 0x0314
#define R_ACC_SRC_C1 0x0318
#define R_ACC_SRC_D0 0x031C
#define R_ACC_SRC_D1 0x0320
#define R_IIR_SRC_B0 0x0324 // Some sources have R_IIR_SRC_B0 and R_IIR_SRC_B1 swapped ><
#define R_IIR_SRC_B1 0x0328 // Assume a typo in the docs and B0 is actually at 324, B1 at 328 in the HW.
#define R_MIX_DEST_A0 0x032C
#define R_MIX_DEST_A1 0x0330
#define R_MIX_DEST_B0 0x0334
#define R_MIX_DEST_B1 0x0338
#define REG_A_EEA 0x033C // Address: End address of working area for effects processing (upper part of address only!)
#define REG_S_ENDX 0x0340 // End Point passed flag
#define REG_S_ENDX 0x0340 // End Point passed flag
#define REG_P_STATX 0x0344 // Status register?
#define REG_P_STATX 0x0344 // Status register?
// 0x346 .. 0x3fe are unknown (unused?)
@ -99,38 +99,38 @@
// "Different" register area
#define REG_P_MVOLL 0x0760 // Master Volume Left
#define REG_P_MVOLR 0x0762 // Master Volume Right
#define REG_P_EVOLL 0x0764 // Effect Volume Left
#define REG_P_EVOLR 0x0766 // Effect Volume Right
#define REG_P_AVOLL 0x0768 // Core External Input Volume Left (Only Core 1)
#define REG_P_AVOLR 0x076A // Core External Input Volume Right (Only Core 1)
#define REG_P_BVOLL 0x076C // Sound Data Volume Left
#define REG_P_BVOLR 0x076E // Sound Data Volume Right
#define REG_P_MVOLXL 0x0770 // Current Master Volume Left
#define REG_P_MVOLXR 0x0772 // Current Master Volume Right
#define REG_P_MVOLL 0x0760 // Master Volume Left
#define REG_P_MVOLR 0x0762 // Master Volume Right
#define REG_P_EVOLL 0x0764 // Effect Volume Left
#define REG_P_EVOLR 0x0766 // Effect Volume Right
#define REG_P_AVOLL 0x0768 // Core External Input Volume Left (Only Core 1)
#define REG_P_AVOLR 0x076A // Core External Input Volume Right (Only Core 1)
#define REG_P_BVOLL 0x076C // Sound Data Volume Left
#define REG_P_BVOLR 0x076E // Sound Data Volume Right
#define REG_P_MVOLXL 0x0770 // Current Master Volume Left
#define REG_P_MVOLXR 0x0772 // Current Master Volume Right
#define R_IIR_ALPHA 0x0774 //IIR alpha (% used)
#define R_ACC_COEF_A 0x0776
#define R_ACC_COEF_B 0x0778
#define R_ACC_COEF_C 0x077A
#define R_ACC_COEF_D 0x077C
#define R_IIR_COEF 0x077E
#define R_FB_ALPHA 0x0780 //feedback alpha (% used)
#define R_FB_X 0x0782 //feedback
#define R_IN_COEF_L 0x0784
#define R_IN_COEF_R 0x0786
#define R_IIR_ALPHA 0x0774 //IIR alpha (% used)
#define R_ACC_COEF_A 0x0776
#define R_ACC_COEF_B 0x0778
#define R_ACC_COEF_C 0x077A
#define R_ACC_COEF_D 0x077C
#define R_IIR_COEF 0x077E
#define R_FB_ALPHA 0x0780 //feedback alpha (% used)
#define R_FB_X 0x0782 //feedback
#define R_IN_COEF_L 0x0784
#define R_IN_COEF_R 0x0786
// values repeat for core1
// End OF "Different" register area
// SPDIF interface
#define SPDIF_OUT 0x07C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass
#define SPDIF_IRQINFO 0x07C2
#define SPDIF_MODE 0x07C6
#define SPDIF_MEDIA 0x07C8 // SPDIF Media: 'CD'/DVD
#define SPDIF_PROTECT 0x07CC // SPDIF Copy Protection
#define SPDIF_OUT 0x07C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass
#define SPDIF_IRQINFO 0x07C2
#define SPDIF_MODE 0x07C6
#define SPDIF_MEDIA 0x07C8 // SPDIF Media: 'CD'/DVD
#define SPDIF_PROTECT 0x07CC // SPDIF Copy Protection
/*********************************************************************
@ -147,38 +147,38 @@ Core attributes (SD_C)
*********************************************************************/
#define SPDIF_OUT_OFF 0x0000 // no spdif output
#define SPDIF_OUT_PCM 0x0020 // encode spdif from spu2 pcm output
#define SPDIF_OUT_BYPASS 0x0100 // bypass spu2 processing
#define SPDIF_OUT_OFF 0x0000 // no spdif output
#define SPDIF_OUT_PCM 0x0020 // encode spdif from spu2 pcm output
#define SPDIF_OUT_BYPASS 0x0100 // bypass spu2 processing
#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 // bypass mode for digital bitstream data
#define SPDIF_MODE_BYPASS_PCM 0x0000 // bypass mode for pcm data (using analog output)
#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 // bypass mode for digital bitstream data
#define SPDIF_MODE_BYPASS_PCM 0x0000 // bypass mode for pcm data (using analog output)
#define SPDIF_MODE_MEDIA_CD 0x0800 // source media is a CD
#define SPDIF_MODE_MEDIA_DVD 0x0000 // source media is a DVD
#define SPDIF_MODE_MEDIA_CD 0x0800 // source media is a CD
#define SPDIF_MODE_MEDIA_DVD 0x0000 // source media is a DVD
#define SPDIF_MEDIA_CDVD 0x0200
#define SPDIF_MEDIA_400 0x0000
#define SPDIF_MEDIA_CDVD 0x0200
#define SPDIF_MEDIA_400 0x0000
#define SPDIF_PROTECT_NORMAL 0x0000 // spdif stream is not protected
#define SPDIF_PROTECT_PROHIBIT 0x8000 // spdif stream can't be copied
#define SPDIF_PROTECT_NORMAL 0x0000 // spdif stream is not protected
#define SPDIF_PROTECT_PROHIBIT 0x8000 // spdif stream can't be copied
/********************************************************************/
#define VOICE_PARAM_VOLL 0x0 // Voice Volume Left
#define VOICE_PARAM_VOLR 0x2 // Voice Volume Right
#define VOICE_PARAM_PITCH 0x4 // Pitch
#define VOICE_PARAM_ADSR1 0x6 // Envelope 1 (Attack-Delay-Sustain-Release)
#define VOICE_PARAM_ADSR2 0x8 // Envelope 2 (Attack-Delay-Sustain-Release)
#define VOICE_PARAM_ENVX 0xA // Current Envelope
#define VOICE_PARAM_VOLXL 0xC // Current Voice Volume Left
#define VOICE_PARAM_VOLXR 0xE // Current Voice Volume Right
#define VOICE_PARAM_VOLL 0x0 // Voice Volume Left
#define VOICE_PARAM_VOLR 0x2 // Voice Volume Right
#define VOICE_PARAM_PITCH 0x4 // Pitch
#define VOICE_PARAM_ADSR1 0x6 // Envelope 1 (Attack-Delay-Sustain-Release)
#define VOICE_PARAM_ADSR2 0x8 // Envelope 2 (Attack-Delay-Sustain-Release)
#define VOICE_PARAM_ENVX 0xA // Current Envelope
#define VOICE_PARAM_VOLXL 0xC // Current Voice Volume Left
#define VOICE_PARAM_VOLXR 0xE // Current Voice Volume Right
/********************************************************************/
#define VOICE_ADDR_SSA 0x0 // Waveform data starting address
#define VOICE_ADDR_LSAX 0x4 // Loop point address
#define VOICE_ADDR_NAX 0x8 // Waveform data that should be read next
#define VOICE_ADDR_SSA 0x0 // Waveform data starting address
#define VOICE_ADDR_LSAX 0x4 // Loop point address
#define VOICE_ADDR_NAX 0x8 // Waveform data that should be read next
@ -186,11 +186,10 @@ Core attributes (SD_C)
// SPU2-X Register Table LUT
// --------------------------------------------------------------------------------------
#define U16P(x) ( (u16*)&(x) )
#define U16P(x) ((u16 *)&(x))
// Returns the hiword of a 32 bit integer.
#define U16P_HI(x) ( ((u16*)&(x))+1 )
extern u16* regtable[0x401];
extern u16 const* const regtable_original[0x401];
#define U16P_HI(x) (((u16 *)&(x)) + 1)
extern u16 *regtable[0x401];
extern u16 const *const regtable_original[0x401];

View File

@ -70,13 +70,13 @@ Preamble W: Marks a word containing data for channel B.
typedef struct _subframe
{
u32 preamble:4;
u32 aux_data:4;
u32 snd_data:20;
u32 validity:1;
u32 subcode:1;
u32 chstatus:1;
u32 parity:1;
u32 preamble : 4;
u32 aux_data : 4;
u32 snd_data : 20;
u32 validity : 1;
u32 subcode : 1;
u32 chstatus : 1;
u32 parity : 1;
} subframe;
/*
@ -103,9 +103,8 @@ typedef struct _subframe
typedef struct _chstatus
{
u8 ctrlbits:4;
u8 reservd1:4;
u8 category;
u8 reservd2[22];
u8 ctrlbits : 4;
u8 reservd1 : 4;
u8 category;
u8 reservd2[22];
} chstatus:

View File

@ -16,134 +16,132 @@
*/
#include "Global.h"
#include "PS2E-spu2.h" // hopefully temporary, until I resolve lClocks depdendency
#include "PS2E-spu2.h" // hopefully temporary, until I resolve lClocks depdendency
namespace Savestate
{
// Arbitrary ID to identify SPU2-X saves.
static const u32 SAVE_ID = 0x1227521;
// Arbitrary ID to identify SPU2-X saves.
static const u32 SAVE_ID = 0x1227521;
// versioning for saves.
// Increment this when changes to the savestate system are made.
static const u32 SAVE_VERSION = 0x000d;
// versioning for saves.
// Increment this when changes to the savestate system are made.
static const u32 SAVE_VERSION = 0x000d;
static void wipe_the_cache()
{
memset( pcm_cache_data, 0, pcm_BlockCount * sizeof(PcmCacheEntry) );
}
static void wipe_the_cache()
{
memset(pcm_cache_data, 0, pcm_BlockCount * sizeof(PcmCacheEntry));
}
}
struct Savestate::DataBlock
{
u32 spu2id; // SPU2-X state identifier lets ZeroGS/PeopsSPU2 know this isn't their state)
u8 unkregs[0x10000]; // SPU2 raw register memory
u8 mem[0x200000]; // SPU2 raw sample memory
u32 spu2id; // SPU2-X state identifier lets ZeroGS/PeopsSPU2 know this isn't their state)
u8 unkregs[0x10000]; // SPU2 raw register memory
u8 mem[0x200000]; // SPU2 raw sample memory
u32 version; // SPU2-X version identifier
V_Core Cores[2];
V_SPDIF Spdif;
s16 OutPos;
s16 InputPos;
u32 Cycles;
u32 lClocks;
int PlayMode;
u32 version; // SPU2-X version identifier
V_Core Cores[2];
V_SPDIF Spdif;
s16 OutPos;
s16 InputPos;
u32 Cycles;
u32 lClocks;
int PlayMode;
};
s32 __fastcall Savestate::FreezeIt( DataBlock& spud )
s32 __fastcall Savestate::FreezeIt(DataBlock &spud)
{
spud.spu2id = SAVE_ID;
spud.version = SAVE_VERSION;
spud.spu2id = SAVE_ID;
spud.version = SAVE_VERSION;
pxAssertMsg( spu2regs && _spu2mem, "Looks like PCSX2 is trying to savestate while pluigns are shut down. That's a no-no! It shouldn't crash, but the savestate will probably be corrupted." );
pxAssertMsg(spu2regs && _spu2mem, "Looks like PCSX2 is trying to savestate while pluigns are shut down. That's a no-no! It shouldn't crash, but the savestate will probably be corrupted.");
if( spu2regs != NULL ) memcpy(spud.unkregs, spu2regs, sizeof(spud.unkregs));
if( _spu2mem != NULL ) memcpy(spud.mem, _spu2mem, sizeof(spud.mem));
if (spu2regs != NULL)
memcpy(spud.unkregs, spu2regs, sizeof(spud.unkregs));
if (_spu2mem != NULL)
memcpy(spud.mem, _spu2mem, sizeof(spud.mem));
memcpy(spud.Cores, Cores, sizeof(Cores));
memcpy(&spud.Spdif, &Spdif, sizeof(Spdif));
memcpy(spud.Cores, Cores, sizeof(Cores));
memcpy(&spud.Spdif, &Spdif, sizeof(Spdif));
spud.OutPos = OutPos;
spud.InputPos = InputPos;
spud.Cycles = Cycles;
spud.lClocks = lClocks;
spud.PlayMode = PlayMode;
spud.OutPos = OutPos;
spud.InputPos = InputPos;
spud.Cycles = Cycles;
spud.lClocks = lClocks;
spud.PlayMode = PlayMode;
// note: Don't save the cache. PCSX2 doesn't offer a safe method of predicting
// the required size of the savestate prior to saving, plus this is just too
// "implementation specific" for the intended spec of a savestate. Let's just
// force the user to rebuild their cache instead.
// note: Don't save the cache. PCSX2 doesn't offer a safe method of predicting
// the required size of the savestate prior to saving, plus this is just too
// "implementation specific" for the intended spec of a savestate. Let's just
// force the user to rebuild their cache instead.
return 0;
return 0;
}
s32 __fastcall Savestate::ThawIt( DataBlock& spud )
s32 __fastcall Savestate::ThawIt(DataBlock &spud)
{
if( spud.spu2id != SAVE_ID || spud.version < SAVE_VERSION )
{
fprintf(stderr, "\n*** SPU2-X Warning:\n");
if( spud.spu2id == SAVE_ID )
fprintf(stderr, "\tSavestate version is from an older version of this plugin.\n");
else
fprintf(stderr, "\tThe savestate you are trying to load was not made with this plugin.\n");
if (spud.spu2id != SAVE_ID || spud.version < SAVE_VERSION) {
fprintf(stderr, "\n*** SPU2-X Warning:\n");
if (spud.spu2id == SAVE_ID)
fprintf(stderr, "\tSavestate version is from an older version of this plugin.\n");
else
fprintf(stderr, "\tThe savestate you are trying to load was not made with this plugin.\n");
fprintf(stderr,
"\tAudio may not recover correctly. Save your game to memorycard, reset,\n\n"
"\tand then continue from there.\n\n"
);
fprintf(stderr,
"\tAudio may not recover correctly. Save your game to memorycard, reset,\n\n"
"\tand then continue from there.\n\n");
// Do *not* reset the cores.
// We'll need some "hints" as to how the cores should be initialized, and the
// only way to get that is to use the game's existing core settings and hope
// they kinda match the settings for the savestate (IRQ enables and such).
// Do *not* reset the cores.
// We'll need some "hints" as to how the cores should be initialized, and the
// only way to get that is to use the game's existing core settings and hope
// they kinda match the settings for the savestate (IRQ enables and such).
// adpcm cache : Clear all the cache flags and buffers.
// adpcm cache : Clear all the cache flags and buffers.
wipe_the_cache();
}
else
{
SndBuffer::ClearContents();
wipe_the_cache();
} else {
SndBuffer::ClearContents();
pxAssertMsg( spu2regs && _spu2mem, "Looks like PCSX2 is trying to loadstate while pluigns are shut down. That's a no-no! It shouldn't crash, but the savestate will probably be corrupted." );
pxAssertMsg(spu2regs && _spu2mem, "Looks like PCSX2 is trying to loadstate while pluigns are shut down. That's a no-no! It shouldn't crash, but the savestate will probably be corrupted.");
// base stuff
if( spu2regs ) memcpy(spu2regs, spud.unkregs, sizeof(spud.unkregs));
if( _spu2mem ) memcpy(_spu2mem, spud.mem, sizeof(spud.mem));
// base stuff
if (spu2regs)
memcpy(spu2regs, spud.unkregs, sizeof(spud.unkregs));
if (_spu2mem)
memcpy(_spu2mem, spud.mem, sizeof(spud.mem));
memcpy(Cores, spud.Cores, sizeof(Cores));
memcpy(&Spdif, &spud.Spdif, sizeof(Spdif));
memcpy(Cores, spud.Cores, sizeof(Cores));
memcpy(&Spdif, &spud.Spdif, sizeof(Spdif));
OutPos = spud.OutPos;
InputPos = spud.InputPos;
Cycles = spud.Cycles;
lClocks = spud.lClocks;
PlayMode = spud.PlayMode;
OutPos = spud.OutPos;
InputPos = spud.InputPos;
Cycles = spud.Cycles;
lClocks = spud.lClocks;
PlayMode = spud.PlayMode;
wipe_the_cache();
wipe_the_cache();
// Go through the V_Voice structs and recalculate SBuffer pointer from
// the NextA setting.
// Go through the V_Voice structs and recalculate SBuffer pointer from
// the NextA setting.
for( int c=0; c<2; c++ )
{
for( int v=0; v<24; v++ )
{
const int cacheIdx = Cores[c].Voices[v].NextA / pcm_WordsPerBlock;
Cores[c].Voices[v].SBuffer = pcm_cache_data[cacheIdx].Sampledata;
}
}
for (int c = 0; c < 2; c++) {
for (int v = 0; v < 24; v++) {
const int cacheIdx = Cores[c].Voices[v].NextA / pcm_WordsPerBlock;
Cores[c].Voices[v].SBuffer = pcm_cache_data[cacheIdx].Sampledata;
}
}
// HACKFIX!! DMAPtr can be invalid after a savestate load, so force it to NULL and
// ignore it on any pending ADMA writes. (the DMAPtr concept used to work in old VM
// editions of PCSX2 with fixed addressing, but new PCSX2s have dynamic memory
// addressing).
// HACKFIX!! DMAPtr can be invalid after a savestate load, so force it to NULL and
// ignore it on any pending ADMA writes. (the DMAPtr concept used to work in old VM
// editions of PCSX2 with fixed addressing, but new PCSX2s have dynamic memory
// addressing).
Cores[0].DMAPtr = Cores[1].DMAPtr = NULL;
}
return 0;
Cores[0].DMAPtr = Cores[1].DMAPtr = NULL;
}
return 0;
}
s32 __fastcall Savestate::SizeIt()
{
return sizeof(DataBlock);
return sizeof(DataBlock);
}

File diff suppressed because it is too large Load Diff