SPU2: clang-format

This commit is contained in:
Gauvain 'GovanifY' Roussel-Tarbouriech 2020-09-25 14:42:06 +02:00 committed by refractionpcsx2
parent b0b4adea75
commit 6dc3966be9
57 changed files with 9163 additions and 8630 deletions

View File

@ -23,129 +23,144 @@ static u32 PsxRates[160];
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);
}
}
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;
}
/////////////////////////////////////////////////////////////////////////////////////////
@ -159,47 +174,53 @@ bool V_ADSR::Calculate()
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
}
}
if (value < 0) // wrapped around the "top"?
{
value = 0x7fffffff;
Mode = 0; // disable slide
}
}
Value = (Value < 0) ? -value : value;
Value = (Value < 0) ? -value : value;
}

View File

@ -92,7 +92,7 @@ extern bool dspPluginEnabled;
namespace SoundtouchCfg
{
extern void ApplySettings(soundtouch::SoundTouch &sndtouch);
extern void ApplySettings(soundtouch::SoundTouch& sndtouch);
}
//////

View File

@ -19,24 +19,24 @@ int crazy_debug = 0;
char s[4096];
FILE *spu2Log = NULL;
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)
@ -52,205 +52,215 @@ 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, ...)
void ConLog(const char* fmt, ...)
{
if (!MsgToConsole())
return;
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);
}
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);
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, " - 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, " - 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, " - APF1_VOL: %x\n", Cores[c].Revb.APF1_VOL);
fprintf(dump, " - APF2_VOL: %x\n", Cores[c].Revb.APF2_VOL);
fprintf(dump, " - APF1_SIZE: %x\n", Cores[c].Revb.APF1_SIZE);
fprintf(dump, " - APF2_SIZE: %x\n", Cores[c].Revb.APF2_SIZE);
fprintf(dump, " - APF1_VOL: %x\n", Cores[c].Revb.APF1_VOL);
fprintf(dump, " - APF2_VOL: %x\n", Cores[c].Revb.APF2_VOL);
fprintf(dump, " - APF1_SIZE: %x\n", Cores[c].Revb.APF1_SIZE);
fprintf(dump, " - APF2_SIZE: %x\n", Cores[c].Revb.APF2_SIZE);
fprintf(dump, " - IIR_VOL: %x\n", Cores[c].Revb.IIR_VOL);
fprintf(dump, " - WALL_VOL: %x\n", Cores[c].Revb.WALL_VOL);
fprintf(dump, " - SAME_L_SRC: %x\n", Cores[c].Revb.SAME_L_SRC);
fprintf(dump, " - SAME_R_SRC: %x\n", Cores[c].Revb.SAME_R_SRC);
fprintf(dump, " - DIFF_L_SRC: %x\n", Cores[c].Revb.DIFF_L_SRC);
fprintf(dump, " - DIFF_R_SRC: %x\n", Cores[c].Revb.DIFF_R_SRC);
fprintf(dump, " - SAME_L_DST: %x\n", Cores[c].Revb.SAME_L_DST);
fprintf(dump, " - SAME_R_DST: %x\n", Cores[c].Revb.SAME_R_DST);
fprintf(dump, " - DIFF_L_DST: %x\n", Cores[c].Revb.DIFF_L_DST);
fprintf(dump, " - DIFF_R_DST: %x\n", Cores[c].Revb.DIFF_R_DST);
fprintf(dump, " - IIR_VOL: %x\n", Cores[c].Revb.IIR_VOL);
fprintf(dump, " - WALL_VOL: %x\n", Cores[c].Revb.WALL_VOL);
fprintf(dump, " - SAME_L_SRC: %x\n", Cores[c].Revb.SAME_L_SRC);
fprintf(dump, " - SAME_R_SRC: %x\n", Cores[c].Revb.SAME_R_SRC);
fprintf(dump, " - DIFF_L_SRC: %x\n", Cores[c].Revb.DIFF_L_SRC);
fprintf(dump, " - DIFF_R_SRC: %x\n", Cores[c].Revb.DIFF_R_SRC);
fprintf(dump, " - SAME_L_DST: %x\n", Cores[c].Revb.SAME_L_DST);
fprintf(dump, " - SAME_R_DST: %x\n", Cores[c].Revb.SAME_R_DST);
fprintf(dump, " - DIFF_L_DST: %x\n", Cores[c].Revb.DIFF_L_DST);
fprintf(dump, " - DIFF_R_DST: %x\n", Cores[c].Revb.DIFF_R_DST);
fprintf(dump, " - COMB1_VOL: %x\n", Cores[c].Revb.COMB1_VOL);
fprintf(dump, " - COMB2_VOL: %x\n", Cores[c].Revb.COMB2_VOL);
fprintf(dump, " - COMB3_VOL: %x\n", Cores[c].Revb.COMB3_VOL);
fprintf(dump, " - COMB4_VOL: %x\n", Cores[c].Revb.COMB4_VOL);
fprintf(dump, " - COMB1_L_SRC: %x\n", Cores[c].Revb.COMB1_L_SRC);
fprintf(dump, " - COMB1_R_SRC: %x\n", Cores[c].Revb.COMB1_R_SRC);
fprintf(dump, " - COMB2_L_SRC: %x\n", Cores[c].Revb.COMB2_L_SRC);
fprintf(dump, " - COMB2_R_SRC: %x\n", Cores[c].Revb.COMB2_R_SRC);
fprintf(dump, " - COMB3_L_SRC: %x\n", Cores[c].Revb.COMB3_L_SRC);
fprintf(dump, " - COMB3_R_SRC: %x\n", Cores[c].Revb.COMB3_R_SRC);
fprintf(dump, " - COMB4_L_SRC: %x\n", Cores[c].Revb.COMB4_L_SRC);
fprintf(dump, " - COMB4_R_SRC: %x\n", Cores[c].Revb.COMB4_R_SRC);
fprintf(dump, " - COMB1_VOL: %x\n", Cores[c].Revb.COMB1_VOL);
fprintf(dump, " - COMB2_VOL: %x\n", Cores[c].Revb.COMB2_VOL);
fprintf(dump, " - COMB3_VOL: %x\n", Cores[c].Revb.COMB3_VOL);
fprintf(dump, " - COMB4_VOL: %x\n", Cores[c].Revb.COMB4_VOL);
fprintf(dump, " - COMB1_L_SRC: %x\n", Cores[c].Revb.COMB1_L_SRC);
fprintf(dump, " - COMB1_R_SRC: %x\n", Cores[c].Revb.COMB1_R_SRC);
fprintf(dump, " - COMB2_L_SRC: %x\n", Cores[c].Revb.COMB2_L_SRC);
fprintf(dump, " - COMB2_R_SRC: %x\n", Cores[c].Revb.COMB2_R_SRC);
fprintf(dump, " - COMB3_L_SRC: %x\n", Cores[c].Revb.COMB3_L_SRC);
fprintf(dump, " - COMB3_R_SRC: %x\n", Cores[c].Revb.COMB3_R_SRC);
fprintf(dump, " - COMB4_L_SRC: %x\n", Cores[c].Revb.COMB4_L_SRC);
fprintf(dump, " - COMB4_R_SRC: %x\n", Cores[c].Revb.COMB4_R_SRC);
fprintf(dump, " - APF1_L_DST: %x\n", Cores[c].Revb.APF1_L_DST);
fprintf(dump, " - APF1_R_DST: %x\n", Cores[c].Revb.APF1_R_DST);
fprintf(dump, " - APF2_L_DST: %x\n", Cores[c].Revb.APF2_L_DST);
fprintf(dump, " - APF2_R_DST: %x\n", Cores[c].Revb.APF2_R_DST);
fprintf(dump, "#### END OF DUMP.\n\n");
}
fclose(dump);
}
fprintf(dump, " - APF1_L_DST: %x\n", Cores[c].Revb.APF1_L_DST);
fprintf(dump, " - APF1_R_DST: %x\n", Cores[c].Revb.APF1_R_DST);
fprintf(dump, " - APF2_L_DST: %x\n", Cores[c].Revb.APF2_L_DST);
fprintf(dump, " - APF2_R_DST: %x\n", Cores[c].Revb.APF2_R_DST);
fprintf(dump, "#### END OF DUMP.\n\n");
}
fclose(dump);
}
#endif
#endif
}

View File

@ -16,53 +16,54 @@
#ifndef DEBUG_H_INCLUDED
#define DEBUG_H_INCLUDED
extern FILE *spu2Log;
extern FILE* spu2Log;
extern void FileLog(const char *fmt, ...);
extern void ConLog(const char *fmt, ...);
extern void FileLog(const char* fmt, ...);
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);
} // namespace WaveDump
using WaveDump::CoreSrc_Input;
using WaveDump::CoreSrc_DryVoiceMix;
using WaveDump::CoreSrc_WetVoiceMix;
using WaveDump::CoreSrc_PreReverb;
using WaveDump::CoreSrc_PostReverb;
using WaveDump::CoreSrc_External;
using WaveDump::CoreSrc_Input;
using WaveDump::CoreSrc_PostReverb;
using WaveDump::CoreSrc_PreReverb;
using WaveDump::CoreSrc_WetVoiceMix;
#endif // DEBUG_H_INCLUDED //

View File

@ -20,153 +20,165 @@
extern u8 callirq;
static FILE *DMA4LogFile = NULL;
static FILE *DMA7LogFile = NULL;
static FILE *ADMA4LogFile = NULL;
static FILE *ADMA7LogFile = NULL;
static FILE *ADMAOutLogFile = NULL;
static FILE* DMA4LogFile = NULL;
static FILE* DMA7LogFile = NULL;
static FILE* ADMA4LogFile = NULL;
static FILE* ADMA7LogFile = NULL;
static FILE* ADMAOutLogFile = NULL;
static FILE *REGWRTLogFile[2] = {0, 0};
static FILE* REGWRTLogFile[2] = {0, 0};
void DMALogOpen()
{
if (!DMALog())
return;
DMA4LogFile = OpenBinaryLog(DMA4LogFileName);
DMA7LogFile = OpenBinaryLog(DMA7LogFileName);
ADMA4LogFile = OpenBinaryLog(L"adma4.raw");
ADMA7LogFile = OpenBinaryLog(L"adma7.raw");
ADMAOutLogFile = OpenBinaryLog(L"admaOut.raw");
if (!DMALog())
return;
DMA4LogFile = OpenBinaryLog(DMA4LogFileName);
DMA7LogFile = OpenBinaryLog(DMA7LogFileName);
ADMA4LogFile = OpenBinaryLog(L"adma4.raw");
ADMA7LogFile = OpenBinaryLog(L"adma7.raw");
ADMAOutLogFile = OpenBinaryLog(L"admaOut.raw");
}
void DMA4LogWrite(void *lpData, u32 ulSize)
void DMA4LogWrite(void* lpData, u32 ulSize)
{
if (!DMALog())
return;
if (!DMA4LogFile)
return;
fwrite(lpData, ulSize, 1, DMA4LogFile);
if (!DMALog())
return;
if (!DMA4LogFile)
return;
fwrite(lpData, ulSize, 1, DMA4LogFile);
}
void DMA7LogWrite(void *lpData, u32 ulSize)
void DMA7LogWrite(void* lpData, u32 ulSize)
{
if (!DMALog())
return;
if (!DMA7LogFile)
return;
fwrite(lpData, ulSize, 1, DMA7LogFile);
if (!DMALog())
return;
if (!DMA7LogFile)
return;
fwrite(lpData, ulSize, 1, DMA7LogFile);
}
void ADMAOutLogWrite(void *lpData, u32 ulSize)
void ADMAOutLogWrite(void* lpData, u32 ulSize)
{
if (!DMALog())
return;
if (!ADMAOutLogFile)
return;
fwrite(lpData, ulSize, 1, ADMAOutLogFile);
if (!DMALog())
return;
if (!ADMAOutLogFile)
return;
fwrite(lpData, ulSize, 1, ADMAOutLogFile);
}
void RegWriteLog(u32 core, u16 value)
{
if (!DMALog())
return;
if (!REGWRTLogFile[core])
return;
fwrite(&value, 2, 1, REGWRTLogFile[core]);
if (!DMALog())
return;
if (!REGWRTLogFile[core])
return;
fwrite(&value, 2, 1, REGWRTLogFile[core]);
}
void DMALogClose()
{
safe_fclose(DMA4LogFile);
safe_fclose(DMA7LogFile);
safe_fclose(REGWRTLogFile[0]);
safe_fclose(REGWRTLogFile[1]);
safe_fclose(ADMA4LogFile);
safe_fclose(ADMA7LogFile);
safe_fclose(ADMAOutLogFile);
safe_fclose(DMA4LogFile);
safe_fclose(DMA7LogFile);
safe_fclose(REGWRTLogFile[0]);
safe_fclose(REGWRTLogFile[1]);
safe_fclose(ADMA4LogFile);
safe_fclose(ADMA7LogFile);
safe_fclose(ADMAOutLogFile);
}
void V_Core::LogAutoDMA(FILE *fp)
void V_Core::LogAutoDMA(FILE* fp)
{
if (!DMALog() || !fp || !DMAPtr)
return;
fwrite(DMAPtr + InputDataProgress, 0x400, 1, fp);
if (!DMALog() || !fp || !DMAPtr)
return;
fwrite(DMAPtr + InputDataProgress, 0x400, 1, fp);
}
void V_Core::AutoDMAReadBuffer(int mode) //mode: 0= split stereo; 1 = do not split stereo
{
int spos = ((InputPosRead + 0xff) & 0x100); //starting position of the free buffer
int spos = ((InputPosRead + 0xff) & 0x100); //starting position of the free buffer
LogAutoDMA(Index ? ADMA7LogFile : ADMA4LogFile);
LogAutoDMA(Index ? ADMA7LogFile : ADMA4LogFile);
// HACKFIX!! DMAPtr can be invalid after a savestate load, so the savestate just forces it
// to NULL and we ignore it here. (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 the savestate just forces it
// to NULL and we ignore it here. (used to work in old VM editions of PCSX2 with fixed
// addressing, but new PCSX2s have dynamic memory addressing).
if (mode) {
if (DMAPtr != NULL)
//memcpy((ADMATempBuffer+(spos<<1)),DMAPtr+InputDataProgress,0x400);
memcpy(GetMemPtr(0x2000 + (Index << 10) + spos), DMAPtr + InputDataProgress, 0x400);
MADR += 0x400;
InputDataLeft -= 0x200;
InputDataProgress += 0x200;
} else {
if (DMAPtr != NULL)
//memcpy((ADMATempBuffer+spos),DMAPtr+InputDataProgress,0x200);
memcpy(GetMemPtr(0x2000 + (Index << 10) + spos), DMAPtr + InputDataProgress, 0x200);
MADR += 0x200;
InputDataLeft -= 0x100;
InputDataProgress += 0x100;
if (mode)
{
if (DMAPtr != NULL)
//memcpy((ADMATempBuffer+(spos<<1)),DMAPtr+InputDataProgress,0x400);
memcpy(GetMemPtr(0x2000 + (Index << 10) + spos), DMAPtr + InputDataProgress, 0x400);
MADR += 0x400;
InputDataLeft -= 0x200;
InputDataProgress += 0x200;
}
else
{
if (DMAPtr != NULL)
//memcpy((ADMATempBuffer+spos),DMAPtr+InputDataProgress,0x200);
memcpy(GetMemPtr(0x2000 + (Index << 10) + spos), DMAPtr + InputDataProgress, 0x200);
MADR += 0x200;
InputDataLeft -= 0x100;
InputDataProgress += 0x100;
if (DMAPtr != NULL)
//memcpy((ADMATempBuffer+spos+0x200),DMAPtr+InputDataProgress,0x200);
memcpy(GetMemPtr(0x2200 + (Index << 10) + spos), DMAPtr + InputDataProgress, 0x200);
MADR += 0x200;
InputDataLeft -= 0x100;
InputDataProgress += 0x100;
}
// See ReadInput at mixer.cpp for explanation on the commented out lines
//
if (DMAPtr != NULL)
//memcpy((ADMATempBuffer+spos+0x200),DMAPtr+InputDataProgress,0x200);
memcpy(GetMemPtr(0x2200 + (Index << 10) + spos), DMAPtr + InputDataProgress, 0x200);
MADR += 0x200;
InputDataLeft -= 0x100;
InputDataProgress += 0x100;
}
// See ReadInput at mixer.cpp for explanation on the commented out lines
//
}
void V_Core::StartADMAWrite(u16 *pMem, u32 sz)
void V_Core::StartADMAWrite(u16* pMem, u32 sz)
{
int size = (sz) & (~511);
int size = (sz) & (~511);
if (MsgAutoDMA())
ConLog("* SPU2-X: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n",
GetDmaIndexChar(), size << 1, TSA, DMABits, AutoDMACtrl, (~Regs.ATTR) & 0x7fff);
if (MsgAutoDMA())
ConLog("* SPU2-X: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n",
GetDmaIndexChar(), size << 1, TSA, DMABits, AutoDMACtrl, (~Regs.ATTR) & 0x7fff);
InputDataProgress = 0;
if ((AutoDMACtrl & (Index + 1)) == 0) {
TSA = 0x2000 + (Index << 10);
DMAICounter = size;
} else if (size >= 512) {
InputDataLeft = size;
if (AdmaInProgress == 0) {
InputDataProgress = 0;
if ((AutoDMACtrl & (Index + 1)) == 0)
{
TSA = 0x2000 + (Index << 10);
DMAICounter = size;
}
else if (size >= 512)
{
InputDataLeft = size;
if (AdmaInProgress == 0)
{
#ifdef PCM24_S1_INTERLEAVE
if ((Index == 1) && ((PlayMode & 8) == 8)) {
AutoDMAReadBuffer(Index, 1);
} else {
AutoDMAReadBuffer(Index, 0);
}
if ((Index == 1) && ((PlayMode & 8) == 8))
{
AutoDMAReadBuffer(Index, 1);
}
else
{
AutoDMAReadBuffer(Index, 0);
}
#else
if (((PlayMode & 4) == 4) && (Index == 0))
Cores[0].InputPosRead = 0;
if (((PlayMode & 4) == 4) && (Index == 0))
Cores[0].InputPosRead = 0;
AutoDMAReadBuffer(0);
AutoDMAReadBuffer(0);
#endif
// Klonoa 2
if (size == 512)
DMAICounter = size;
}
// Klonoa 2
if (size == 512)
DMAICounter = size;
}
AdmaInProgress = 1;
} else {
InputDataLeft = 0;
DMAICounter = 1;
}
TADR = MADR + (size << 1);
AdmaInProgress = 1;
}
else
{
InputDataLeft = 0;
DMAICounter = 1;
}
TADR = MADR + (size << 1);
}
// HACKFIX: The BIOS breaks if we check the IRQA for both cores when issuing DMA writes. The
@ -186,228 +198,255 @@ void V_Core::StartADMAWrite(u16 *pMem, u32 sz)
// Update: This hack is no longer needed when we don't do a core reset. Guess the null pc was in spu2 memory?
#define NO_BIOS_HACKFIX 1 // set to 1 to disable the hackfix
void V_Core::PlainDMAWrite(u16 *pMem, u32 size)
void V_Core::PlainDMAWrite(u16* pMem, u32 size)
{
// Perform an alignment check.
// Not really important. Everything should work regardless,
// but it could be indicative of an emulation foopah elsewhere.
// Perform an alignment check.
// Not really important. Everything should work regardless,
// but it could be indicative of an emulation foopah elsewhere.
if (MsgToConsole()) {
// Don't need this anymore. Target may still be good to know though.
/*if((uptr)pMem & 15)
if (MsgToConsole())
{
// Don't need this anymore. Target may still be good to know though.
/*if((uptr)pMem & 15)
{
ConLog("* SPU2 DMA Write > Misaligned source. Core: %d IOP: %p TSA: 0x%x Size: 0x%x\n", Index, (void*)pMem, TSA, size);
}*/
if (TSA & 7) {
ConLog("* SPU2 DMA Write > Misaligned target. Core: %d IOP: %p TSA: 0x%x Size: 0x%x\n", Index, (void *)pMem, TSA, size);
}
}
if (TSA & 7)
{
ConLog("* SPU2 DMA Write > Misaligned target. Core: %d IOP: %p TSA: 0x%x Size: 0x%x\n", Index, (void*)pMem, TSA, size);
}
}
if (Index == 0)
DMA4LogWrite(pMem, size << 1);
else
DMA7LogWrite(pMem, size << 1);
if (Index == 0)
DMA4LogWrite(pMem, size << 1);
else
DMA7LogWrite(pMem, size << 1);
TSA &= 0xfffff;
TSA &= 0xfffff;
u32 buff1end = TSA + size;
u32 buff2end = 0;
if (buff1end > 0x100000) {
buff2end = buff1end - 0x100000;
buff1end = 0x100000;
}
u32 buff1end = TSA + size;
u32 buff2end = 0;
if (buff1end > 0x100000)
{
buff2end = buff1end - 0x100000;
buff1end = 0x100000;
}
const int cacheIdxStart = TSA / pcm_WordsPerBlock;
const int cacheIdxEnd = (buff1end + pcm_WordsPerBlock - 1) / pcm_WordsPerBlock;
PcmCacheEntry *cacheLine = &pcm_cache_data[cacheIdxStart];
PcmCacheEntry &cacheEnd = pcm_cache_data[cacheIdxEnd];
const int cacheIdxStart = TSA / pcm_WordsPerBlock;
const int cacheIdxEnd = (buff1end + pcm_WordsPerBlock - 1) / pcm_WordsPerBlock;
PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart];
PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd];
do {
cacheLine->Validated = false;
cacheLine++;
} while (cacheLine != &cacheEnd);
do
{
cacheLine->Validated = false;
cacheLine++;
} while (cacheLine != &cacheEnd);
//ConLog( "* SPU2-X: Cache Clear Range! TSA=0x%x, TDA=0x%x (low8=0x%x, high8=0x%x, len=0x%x)\n",
// TSA, buff1end, flagTSA, flagTDA, clearLen );
//ConLog( "* SPU2-X: Cache Clear Range! TSA=0x%x, TDA=0x%x (low8=0x%x, high8=0x%x, len=0x%x)\n",
// TSA, buff1end, flagTSA, flagTDA, clearLen );
// First Branch needs cleared:
// It starts at TSA and goes to buff1end.
// First Branch needs cleared:
// It starts at TSA and goes to buff1end.
const u32 buff1size = (buff1end - TSA);
memcpy(GetMemPtr(TSA), pMem, buff1size * 2);
const u32 buff1size = (buff1end - TSA);
memcpy(GetMemPtr(TSA), pMem, buff1size * 2);
u32 TDA;
u32 TDA;
if (buff2end > 0) {
// second branch needs copied:
// It starts at the beginning of memory and moves forward to buff2end
if (buff2end > 0)
{
// second branch needs copied:
// It starts at the beginning of memory and moves forward to buff2end
// endpoint cache should be irrelevant, since it's almost certainly dynamic
// memory below 0x2800 (registers and such)
//const u32 endpt2 = (buff2end + roundUp) / indexer_scalar;
//memset( pcm_cache_flags, 0, endpt2 );
// endpoint cache should be irrelevant, since it's almost certainly dynamic
// memory below 0x2800 (registers and such)
//const u32 endpt2 = (buff2end + roundUp) / indexer_scalar;
//memset( pcm_cache_flags, 0, endpt2 );
// Emulation Grayarea: Should addresses wrap around to zero, or wrap around to
// 0x2800? Hard to know for sure (almost no games depend on this)
// Emulation Grayarea: Should addresses wrap around to zero, or wrap around to
// 0x2800? Hard to know for sure (almost no games depend on this)
memcpy(GetMemPtr(0), &pMem[buff1size], buff2end * 2);
TDA = (buff2end + 1) & 0xfffff;
memcpy(GetMemPtr(0), &pMem[buff1size], buff2end * 2);
TDA = (buff2end + 1) & 0xfffff;
// Flag interrupt? If IRQA occurs between start and dest, flag it.
// Important: Test both core IRQ settings for either DMA!
// Note: Because this buffer wraps, we use || instead of &&
// Flag interrupt? If IRQA occurs between start and dest, flag it.
// Important: Test both core IRQ settings for either DMA!
// Note: Because this buffer wraps, we use || instead of &&
#if NO_BIOS_HACKFIX
for (int i = 0; i < 2; i++) {
// Start is exclusive and end is inclusive... maybe? The end is documented to be inclusive,
// which suggests that memory access doesn't trigger interrupts, incrementing registers does
// (which would mean that if TSA=IRQA an interrupt doesn't fire... I guess?)
// Chaos Legion uses interrupt addresses set to the beginning of the two buffers in a double
// buffer scheme and sets LSA of one of the voices to the start of the opposite buffer.
// However it transfers to the same address right after setting IRQA, which by our previous
// understanding would trigger the interrupt early causing it to switch buffers again immediately
// and an interrupt never fires again, leaving the voices looping the same samples forever.
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA || Cores[i].IRQA <= TDA)) {
//ConLog("DMAwrite Core %d: IRQ Called (IRQ passed). IRQA = %x Cycles = %d\n", i, Cores[i].IRQA, Cycles );
SetIrqCall(i);
}
}
#else
if ((IRQEnable && (IRQA > TSA || IRQA <= TDA))
for (int i = 0; i < 2; i++)
{
SetIrqCall(Index);
// Start is exclusive and end is inclusive... maybe? The end is documented to be inclusive,
// which suggests that memory access doesn't trigger interrupts, incrementing registers does
// (which would mean that if TSA=IRQA an interrupt doesn't fire... I guess?)
// Chaos Legion uses interrupt addresses set to the beginning of the two buffers in a double
// buffer scheme and sets LSA of one of the voices to the start of the opposite buffer.
// However it transfers to the same address right after setting IRQA, which by our previous
// understanding would trigger the interrupt early causing it to switch buffers again immediately
// and an interrupt never fires again, leaving the voices looping the same samples forever.
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA || Cores[i].IRQA <= TDA))
{
//ConLog("DMAwrite Core %d: IRQ Called (IRQ passed). IRQA = %x Cycles = %d\n", i, Cores[i].IRQA, Cycles );
SetIrqCall(i);
}
}
#else
if ((IRQEnable && (IRQA > TSA || IRQA <= TDA))
{
SetIrqCall(Index);
}
#endif
} else {
// Buffer doesn't wrap/overflow!
// Just set the TDA and check for an IRQ...
}
else
{
// Buffer doesn't wrap/overflow!
// Just set the TDA and check for an IRQ...
TDA = (buff1end + 1) & 0xfffff;
TDA = (buff1end + 1) & 0xfffff;
// Flag interrupt? If IRQA occurs between start and dest, flag it.
// Important: Test both core IRQ settings for either DMA!
// Flag interrupt? If IRQA occurs between start and dest, flag it.
// Important: Test both core IRQ settings for either DMA!
#if NO_BIOS_HACKFIX
for (int i = 0; i < 2; i++) {
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA && Cores[i].IRQA <= TDA)) {
//ConLog("DMAwrite Core %d: IRQ Called (IRQ passed). IRQA = %x Cycles = %d\n", i, Cores[i].IRQA, Cycles );
SetIrqCall(i);
}
}
for (int i = 0; i < 2; i++)
{
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA && Cores[i].IRQA <= TDA))
{
//ConLog("DMAwrite Core %d: IRQ Called (IRQ passed). IRQA = %x Cycles = %d\n", i, Cores[i].IRQA, Cycles );
SetIrqCall(i);
}
}
#else
if (IRQEnable && (IRQA > TSA) && (IRQA <= TDA)) {
SetIrqCall(Index);
}
if (IRQEnable && (IRQA > TSA) && (IRQA <= TDA))
{
SetIrqCall(Index);
}
#endif
}
}
TSA = TDA;
DMAICounter = size;
TADR = MADR + (size << 1);
TSA = TDA;
DMAICounter = size;
TADR = MADR + (size << 1);
}
void V_Core::DoDMAread(u16 *pMem, u32 size)
void V_Core::DoDMAread(u16* pMem, u32 size)
{
TSA &= 0xfffff;
TSA &= 0xfffff;
u32 buff1end = TSA + size;
u32 buff2end = 0;
if (buff1end > 0x100000) {
buff2end = buff1end - 0x100000;
buff1end = 0x100000;
}
u32 buff1end = TSA + size;
u32 buff2end = 0;
if (buff1end > 0x100000)
{
buff2end = buff1end - 0x100000;
buff1end = 0x100000;
}
const u32 buff1size = (buff1end - TSA);
memcpy(pMem, GetMemPtr(TSA), buff1size * 2);
const u32 buff1size = (buff1end - TSA);
memcpy(pMem, GetMemPtr(TSA), buff1size * 2);
// Note on TSA's position after our copy finishes:
// IRQA should be measured by the end of the writepos+0x20. But the TDA
// should be written back at the precise endpoint of the xfer.
// Note on TSA's position after our copy finishes:
// IRQA should be measured by the end of the writepos+0x20. But the TDA
// should be written back at the precise endpoint of the xfer.
u32 TDA;
u32 TDA;
if (buff2end > 0) {
// second branch needs cleared:
// It starts at the beginning of memory and moves forward to buff2end
if (buff2end > 0)
{
// second branch needs cleared:
// It starts at the beginning of memory and moves forward to buff2end
memcpy(&pMem[buff1size], GetMemPtr(0), buff2end * 2);
memcpy(&pMem[buff1size], GetMemPtr(0), buff2end * 2);
TDA = (buff2end + 0x20) & 0xfffff;
TDA = (buff2end + 0x20) & 0xfffff;
// Flag interrupt? If IRQA occurs between start and dest, flag it.
// Important: Test both core IRQ settings for either DMA!
// Note: Because this buffer wraps, we use || instead of &&
// Flag interrupt? If IRQA occurs between start and dest, flag it.
// Important: Test both core IRQ settings for either DMA!
// Note: Because this buffer wraps, we use || instead of &&
for (int i = 0; i < 2; i++) {
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA || Cores[i].IRQA <= TDA)) {
SetIrqCall(i);
}
}
} else {
// Buffer doesn't wrap/overflow!
// Just set the TDA and check for an IRQ...
for (int i = 0; i < 2; i++)
{
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA || Cores[i].IRQA <= TDA))
{
SetIrqCall(i);
}
}
}
else
{
// Buffer doesn't wrap/overflow!
// Just set the TDA and check for an IRQ...
TDA = (buff1end + 0x20) & 0xfffff;
TDA = (buff1end + 0x20) & 0xfffff;
// Flag interrupt? If IRQA occurs between start and dest, flag it.
// Important: Test both core IRQ settings for either DMA!
// Flag interrupt? If IRQA occurs between start and dest, flag it.
// Important: Test both core IRQ settings for either DMA!
for (int i = 0; i < 2; i++) {
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA && Cores[i].IRQA <= TDA)) {
SetIrqCall(i);
}
}
}
for (int i = 0; i < 2; i++)
{
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA && Cores[i].IRQA <= TDA))
{
SetIrqCall(i);
}
}
}
TSA = TDA;
TSA = TDA;
DMAICounter = size;
Regs.STATX &= ~0x80;
//Regs.ATTR |= 0x30;
TADR = MADR + (size << 1);
DMAICounter = size;
Regs.STATX &= ~0x80;
//Regs.ATTR |= 0x30;
TADR = MADR + (size << 1);
}
void V_Core::DoDMAwrite(u16 *pMem, u32 size)
void V_Core::DoDMAwrite(u16* pMem, u32 size)
{
DMAPtr = pMem;
DMAPtr = pMem;
if (size < 2) {
Regs.STATX &= ~0x80;
//Regs.ATTR |= 0x30;
DMAICounter = 1;
if (size < 2)
{
Regs.STATX &= ~0x80;
//Regs.ATTR |= 0x30;
DMAICounter = 1;
return;
}
return;
}
if (IsDevBuild) {
DebugCores[Index].lastsize = size;
DebugCores[Index].dmaFlag = 2;
}
if (IsDevBuild)
{
DebugCores[Index].lastsize = size;
DebugCores[Index].dmaFlag = 2;
}
if (MsgToConsole()) {
if (TSA > 0xfffff) {
ConLog("* SPU2-X: Transfer Start Address out of bounds. TSA is %x\n", TSA);
}
}
if (MsgToConsole())
{
if (TSA > 0xfffff)
{
ConLog("* SPU2-X: Transfer Start Address out of bounds. TSA is %x\n", TSA);
}
}
TSA &= 0xfffff;
TSA &= 0xfffff;
bool adma_enable = ((AutoDMACtrl & (Index + 1)) == (Index + 1));
bool adma_enable = ((AutoDMACtrl & (Index + 1)) == (Index + 1));
if (adma_enable) {
TSA &= 0x1fff;
StartADMAWrite(pMem, size);
} else {
if (MsgDMA())
ConLog("* SPU2-X: DMA%c Transfer of %d bytes to %x (%02x %x %04x). IRQE = %d IRQA = %x \n",
GetDmaIndexChar(), size << 1, TSA, DMABits, AutoDMACtrl, (~Regs.ATTR) & 0x7fff,
Cores[0].IRQEnable, Cores[0].IRQA);
if (adma_enable)
{
TSA &= 0x1fff;
StartADMAWrite(pMem, size);
}
else
{
if (MsgDMA())
ConLog("* SPU2-X: DMA%c Transfer of %d bytes to %x (%02x %x %04x). IRQE = %d IRQA = %x \n",
GetDmaIndexChar(), size << 1, TSA, DMABits, AutoDMACtrl, (~Regs.ATTR) & 0x7fff,
Cores[0].IRQEnable, Cores[0].IRQA);
PlainDMAWrite(pMem, size);
}
Regs.STATX &= ~0x80;
//Regs.ATTR |= 0x30;
PlainDMAWrite(pMem, size);
}
Regs.STATX &= ~0x80;
//Regs.ATTR |= 0x30;
}

View File

@ -16,6 +16,6 @@
#pragma once
extern void DMALogOpen();
extern void DMA4LogWrite(void *lpData, u32 ulSize);
extern void DMA7LogWrite(void *lpData, u32 ulSize);
extern void DMA4LogWrite(void* lpData, u32 ulSize);
extern void DMA7LogWrite(void* lpData, u32 ulSize);
extern void DMALogClose();

View File

@ -57,114 +57,114 @@ 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;
AccL += (PL - AccL) * 0.1f;
AccR += (PR - AccR) * 0.1f;
// Calculate power balance
float Balance = (AccR - AccL); // -1 .. 1
// Calculate power balance
float Balance = (AccR - AccL); // -1 .. 1
// 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
// 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
// Equalize the power levels for L/R
float B = std::min(0.9f, std::max(-0.9f, Balance));
// Equalize the power levels for L/R
float B = std::min(0.9f, std::max(-0.9f, Balance));
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 VL = L / (1 - B); // if B>0, it means R>L, so increase L, else decrease L
float VR = R / (1 + B); // vice-versa
// 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;
// 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 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
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
// Adjust the volume of the front speakers based on what we calculated above
L *= Frontness;
R *= Frontness;
// Adjust the volume of the front speakers based on what we calculated above
L *= Frontness;
R *= Frontness;
s32 CX = (s32)(C * AddCLR);
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);
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;
float SUB = C;
s32 CX = (s32)(C * AddCLR); // +15.16
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);
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

@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#pragma once
#define NOMINMAX
@ -27,7 +27,7 @@ struct V_Core;
namespace soundtouch
{
class SoundTouch;
class SoundTouch;
}
#include <assert.h>
@ -44,9 +44,9 @@ class 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
} // namespace VersionInfo
//////////////////////////////////////////////////////////////////////////
// Override Win32 min/max macros with the STL's type safe and macro
@ -56,22 +56,22 @@ static const u8 Revision = 0; // increase that with each version
#undef max
template <typename T>
static __forceinline void Clampify(T &src, T min, T max)
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)
{
return std::min(std::max(src, min), max);
return std::min(std::max(src, min), max);
}
#ifdef __WXMAC__
#else
extern void SysMessage(const char *fmt, ...);
extern void SysMessage(const char* fmt, ...);
#endif
extern void SysMessage(const wchar_t *fmt, ...);
extern void SysMessage(const wchar_t* fmt, ...);
//////////////////////////////////////////////////////////////
// Dev / Debug conditionals --
@ -100,4 +100,3 @@ extern void SysMessage(const wchar_t *fmt, ...);
#include "Config.h"
#include "Debug.h"
#include "SndOut.h"

View File

@ -27,226 +27,241 @@
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,"* 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,"All set up.\n");
return 0;
}
void Close()
{
//fprintf(stderr,"* SPU2-X: Closing Alsa\n");
if (handle == NULL)
return;
void Close()
{
//fprintf(stderr,"* SPU2-X: Closing Alsa\n");
if (handle == NULL)
return;
snd_pcm_drop(handle);
snd_pcm_close(handle);
handle = NULL;
}
snd_pcm_drop(handle);
snd_pcm_close(handle);
handle = NULL;
}
virtual void Configure(uptr parent)
{
}
virtual void Configure(uptr parent)
{
}
virtual bool Is51Out() const { return false; }
virtual bool Is51Out() const { return false; }
s32 Test() const
{
return 0;
}
s32 Test() const
{
return 0;
}
int GetEmptySampleCount()
{
if (handle == NULL) {
fprintf(stderr, "Handle is NULL!\n");
return 0;
}
int GetEmptySampleCount()
{
if (handle == NULL)
{
fprintf(stderr, "Handle is NULL!\n");
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);
}
// 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 *GetIdent() const
{
return L"Alsa";
}
const wchar_t* GetIdent() const
{
return L"Alsa";
}
const wchar_t *GetLongName() const
{
return L"Alsa";
}
const wchar_t* GetLongName() const
{
return L"Alsa";
}
void ReadSettings()
{
}
void ReadSettings()
{
}
void SetApiSettings(wxString api)
{
}
void SetApiSettings(wxString api)
{
}
void WriteSettings() const
{
}
void WriteSettings() const
{
}
} static Alsa;
SndOutModule *AlsaOut = &Alsa;
SndOutModule* AlsaOut = &Alsa;
#endif

View File

@ -30,11 +30,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__

View File

@ -16,91 +16,91 @@
#include "Dialogs.h"
#include <wx/fileconf.h>
wxFileConfig *spuConfig = nullptr;
wxFileConfig* spuConfig = nullptr;
wxString path(L"~/.config/PCSX2/inis/SPU2.ini");
bool pathSet = false;
void initIni()
{
if (spuConfig == nullptr)
spuConfig = new wxFileConfig(L"", L"", path, L"", wxCONFIG_USE_LOCAL_FILE);
if (spuConfig == nullptr)
spuConfig = new wxFileConfig(L"", L"", path, L"", wxCONFIG_USE_LOCAL_FILE);
}
void setIni(const wchar_t *Section)
void setIni(const wchar_t* Section)
{
initIni();
spuConfig->SetPath(wxsFormat(L"/%s", Section));
initIni();
spuConfig->SetPath(wxsFormat(L"/%s", Section));
}
void CfgSetSettingsDir(const char *dir)
void CfgSetSettingsDir(const char* dir)
{
FileLog("CfgSetSettingsDir(%s)\n", dir);
path = wxString::FromUTF8(dir) + L"/SPU2.ini";
pathSet = true;
FileLog("CfgSetSettingsDir(%s)\n", dir);
path = wxString::FromUTF8(dir) + L"/SPU2.ini";
pathSet = true;
}
void CfgWriteBool(const wchar_t *Section, const wchar_t *Name, bool 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 CfgWriteInt(const wchar_t *Section, const wchar_t *Name, int Value)
void CfgWriteInt(const wchar_t* Section, const wchar_t* Name, int 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 CfgWriteFloat(const wchar_t* Section, const wchar_t* Name, float Value)
{
setIni(Section);
spuConfig->Write(Name, (double)Value);
setIni(Section);
spuConfig->Write(Name, (double)Value);
}
void CfgWriteStr(const wchar_t *Section, const wchar_t *Name, const wxString &Data)
void CfgWriteStr(const wchar_t* Section, const wchar_t* Name, const wxString& Data)
{
setIni(Section);
spuConfig->Write(Name, Data);
setIni(Section);
spuConfig->Write(Name, Data);
}
bool CfgReadBool(const wchar_t *Section, const wchar_t *Name, bool Default)
bool CfgReadBool(const wchar_t* Section, const wchar_t* Name, bool Default)
{
bool ret;
bool ret;
setIni(Section);
spuConfig->Read(Name, &ret, Default);
setIni(Section);
spuConfig->Read(Name, &ret, Default);
return ret;
return ret;
}
int CfgReadInt(const wchar_t *Section, const wchar_t *Name, int Default)
int CfgReadInt(const wchar_t* Section, const wchar_t* Name, int Default)
{
int ret;
int 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)
float CfgReadFloat(const wchar_t* Section, const wchar_t* Name, float Default)
{
double ret;
double ret;
setIni(Section);
spuConfig->Read(Name, &ret, (double)Default);
setIni(Section);
spuConfig->Read(Name, &ret, (double)Default);
return (float)ret;
return (float)ret;
}
void CfgReadStr(const wchar_t *Section, const wchar_t *Name, wchar_t *Data, int DataSize, 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);
wcscpy(Data, spuConfig->Read(Name, Default).wc_str());
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)
void CfgReadStr(const wchar_t* Section, const wchar_t* Name, wxString& Data, const wchar_t* Default)
{
setIni(Section);
Data = spuConfig->Read(Name, Default);
setIni(Section);
Data = spuConfig->Read(Name, Default);
}

View File

@ -79,153 +79,157 @@ bool temp_debug_state;
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;
}
// 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;
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);
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;
wxString temp;
#if SDL_MAJOR_VERSION >= 2 || !defined(SPU2X_PORTAUDIO)
CfgReadStr(L"OUTPUT", L"Output_Module", temp, SDLOut->GetIdent());
CfgReadStr(L"OUTPUT", L"Output_Module", temp, SDLOut->GetIdent());
#else
CfgReadStr(L"OUTPUT", L"Output_Module", temp, PortaudioOut->GetIdent());
CfgReadStr(L"OUTPUT", L"Output_Module", temp, PortaudioOut->GetIdent());
#endif
OutputModule = FindOutputModuleById(temp.c_str()); // find the driver index of this module
OutputModule = FindOutputModuleById(temp.c_str()); // find the driver index of this module
// find current API
#ifdef SPU2X_PORTAUDIO
#ifdef __linux__
CfgReadStr(L"PORTAUDIO", L"HostApi", temp, L"ALSA");
if (temp == L"OSS")
OutputAPI = 1;
else if (temp == L"JACK")
OutputAPI = 2;
else // L"ALSA"
OutputAPI = 0;
CfgReadStr(L"PORTAUDIO", L"HostApi", temp, L"ALSA");
if (temp == L"OSS")
OutputAPI = 1;
else if (temp == L"JACK")
OutputAPI = 2;
else // L"ALSA"
OutputAPI = 0;
#else
CfgReadStr(L"PORTAUDIO", L"HostApi", temp, L"OSS");
OutputAPI = 0; // L"OSS"
CfgReadStr(L"PORTAUDIO", L"HostApi", temp, L"OSS");
OutputAPI = 0; // L"OSS"
#endif
#endif
#if defined(__unix__) || defined(__APPLE__)
CfgReadStr(L"SDL", L"HostApi", temp, L"pulseaudio");
SdlOutputAPI = 0;
CfgReadStr(L"SDL", L"HostApi", temp, L"pulseaudio");
SdlOutputAPI = 0;
#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);
numSpeakers = CfgReadInt(L"OUTPUT", L"SpeakerConfiguration", 0);
SndOutLatencyMS = CfgReadInt(L"OUTPUT", L"Latency", 300);
SynchMode = CfgReadInt(L"OUTPUT", L"Synch_Mode", 0);
numSpeakers = CfgReadInt(L"OUTPUT", L"SpeakerConfiguration", 0);
#ifdef SPU2X_PORTAUDIO
PortaudioOut->ReadSettings();
PortaudioOut->ReadSettings();
#endif
#if defined(__unix__) || defined(__APPLE__)
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);
if (mods[OutputModule] == nullptr) {
fwprintf(stderr, L"* SPU2-X: Unknown output module '%s' specified in configuration file.\n", temp.wc_str());
fprintf(stderr, "* SPU2-X: Defaulting to SDL (%S).\n", SDLOut->GetIdent());
OutputModule = FindOutputModuleById(SDLOut->GetIdent());
}
if (mods[OutputModule] == nullptr)
{
fwprintf(stderr, L"* SPU2-X: Unknown output module '%s' specified in configuration file.\n", temp.wc_str());
fprintf(stderr, "* SPU2-X: Defaulting to SDL (%S).\n", SDLOut->GetIdent());
OutputModule = FindOutputModuleById(SDLOut->GetIdent());
}
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"OUTPUT", L"SpeakerConfiguration", numSpeakers);
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"DEBUG", L"DelayCycles", delayCycles);
#ifdef SPU2X_PORTAUDIO
PortaudioOut->WriteSettings();
PortaudioOut->WriteSettings();
#endif
#if defined(__unix__) || defined(__APPLE__)
SDLOut->WriteSettings();
SDLOut->WriteSettings();
#endif
SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings();
SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings();
}
void configure()
{
auto *dialog = new Dialog;
auto* dialog = new Dialog;
initIni();
ReadSettings();
dialog->Display();
WriteSettings();
delete spuConfig;
spuConfig = nullptr;
wxDELETE(dialog);
initIni();
ReadSettings();
dialog->Display();
WriteSettings();
delete spuConfig;
spuConfig = nullptr;
wxDELETE(dialog);
}

View File

@ -97,21 +97,21 @@ const int LATENCY_MIN_TIMESTRETCH = 15;
namespace SoundtouchCfg
{
extern const int SequenceLen_Min;
extern const int SequenceLen_Max;
extern const int SequenceLen_Min;
extern const int SequenceLen_Max;
extern const int SeekWindow_Min;
extern const int SeekWindow_Max;
extern const int SeekWindow_Min;
extern const int SeekWindow_Max;
extern const int Overlap_Min;
extern const int Overlap_Max;
extern const int Overlap_Min;
extern const int Overlap_Max;
extern int SequenceLenMS;
extern int SeekWindowMS;
extern int OverlapMS;
extern int SequenceLenMS;
extern int SeekWindowMS;
extern int OverlapMS;
void ReadSettings();
void WriteSettings();
void ReadSettings();
void WriteSettings();
}; // namespace SoundtouchCfg
void ReadSettings();
@ -119,7 +119,7 @@ void WriteSettings();
void DisplayDialog();
void configure();
extern wxFileConfig *spuConfig;
extern wxFileConfig* spuConfig;
extern bool pathSet;
extern void initIni();
#endif // CONFIG_H_INCLUDED

View File

@ -51,105 +51,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";
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";
static void set_default_filenames()
{
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);
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);
_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);
void WriteSettings()
{
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);
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);
}
CfgWriteStr(Section, L"Info_Dump_Filename", CoresDumpFileName);
CfgWriteStr(Section, L"Mem_Dump_Filename", MemDumpFileName);
CfgWriteStr(Section, L"Reg_Dump_Filename", RegDumpFileName);
}
} // namespace DebugConfig

View File

@ -20,49 +20,49 @@
namespace SoundtouchCfg
{
// Timestretch Slider Bounds, Min/Max
const int SequenceLen_Min = 20;
const int SequenceLen_Max = 100;
// Timestretch Slider Bounds, Min/Max
const int SequenceLen_Min = 20;
const int SequenceLen_Max = 100;
const int SeekWindow_Min = 10;
const int SeekWindow_Max = 30;
const int SeekWindow_Min = 10;
const int SeekWindow_Max = 30;
const int Overlap_Min = 5;
const int Overlap_Max = 15;
const int Overlap_Min = 5;
const int Overlap_Max = 15;
int SequenceLenMS = 30;
int SeekWindowMS = 20;
int OverlapMS = 10;
int SequenceLenMS = 30;
int SeekWindowMS = 20;
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);
}
} // namespace SoundtouchCfg

View File

@ -21,32 +21,32 @@
#if defined(__unix__)
#include <wx/wx.h>
void SysMessage(const char *fmt, ...)
void SysMessage(const char* fmt, ...)
{
va_list list;
char msg[512];
va_list list;
char msg[512];
va_start(list, fmt);
vsprintf(msg, fmt, list);
va_end(list);
va_start(list, 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;
wxMessageDialog dialog(nullptr, msg, "Info", wxOK);
dialog.ShowModal();
wxMessageDialog dialog(nullptr, msg, "Info", wxOK);
dialog.ShowModal();
}
void SysMessage(const wchar_t *fmt, ...)
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);
wxMessageDialog dialog(nullptr, msg, "Info", wxOK);
dialog.ShowModal();
wxMessageDialog dialog(nullptr, msg, "Info", wxOK);
dialog.ShowModal();
}
#endif
@ -54,7 +54,7 @@ void DspUpdate()
{
}
s32 DspLoadLibrary(wchar_t *fileName, int modnum)
s32 DspLoadLibrary(wchar_t* fileName, int modnum)
{
return 0;
return 0;
}

View File

@ -21,22 +21,22 @@
namespace DebugConfig
{
extern void ReadSettings();
extern void WriteSettings();
extern void ReadSettings();
extern void WriteSettings();
} // namespace DebugConfig
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

@ -21,72 +21,72 @@
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)
{
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)
: impl_lpf(freq, srate)
{
}
LowPassFilter64::LowPassFilter64(double freq, double srate)
: impl_lpf(freq, srate)
: impl_lpf(freq, srate)
{
}
float LowPassFilter32::sample(float inval)
{
return impl_lpf.sample(inval);
return impl_lpf.sample(inval);
}
double LowPassFilter64::sample(double inval)
{
return impl_lpf.sample(inval);
return impl_lpf.sample(inval);
}

View File

@ -18,25 +18,25 @@
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

@ -21,112 +21,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)
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)
, 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)
{
}
, 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 StereoOut32 clamp_mix(const StereoOut32 &sample, u8 bitshift = 0);
extern StereoOut32 clamp_mix(const StereoOut32& sample, u8 bitshift = 0);

View File

@ -30,145 +30,163 @@
//
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)) {
AdmaInProgress = 0;
if (InputDataLeft >= 0x200) {
if ((InputPosRead == 0x100) || (InputPosRead >= 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(!SPU2_dummy_callback)
spu2DMA4Irq();
else
SPU2interruptDMA4();
} else {
if(!SPU2_dummy_callback)
spu2DMA7Irq();
else
SPU2interruptDMA7();
}
}
}
InputPosRead &= 0x1ff;
}
return retval;
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 (!SPU2_dummy_callback)
spu2DMA4Irq();
else
SPU2interruptDMA4();
}
else
{
if (!SPU2_dummy_callback)
spu2DMA7Irq();
else
SPU2interruptDMA7();
}
}
}
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)) {
AdmaInProgress = 0;
if (InputDataLeft >= 0x200) {
//u8 k=InputDataLeft>=InputDataProgress;
if (AutoDMACtrl & (Index + 1) && (InputPosRead == 0x100 || InputPosRead == 0x200))
{
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(!SPU2_dummy_callback)
spu2DMA4Irq();
else
SPU2interruptDMA4();
} else {
if(!SPU2_dummy_callback)
spu2DMA7Irq();
else
SPU2interruptDMA7();
}
}
}
}
InputPosRead &= 0x1ff;
return retval;
InputDataLeft = 0;
// Hack, kinda. We call the interrupt early here, since PCSX2 doesn't like them delayed.
//DMAICounter = 1;
if (Index == 0)
{
if (!SPU2_dummy_callback)
spu2DMA4Irq();
else
SPU2interruptDMA4();
}
else
{
if (!SPU2_dummy_callback)
spu2DMA7Irq();
else
SPU2interruptDMA7();
}
}
}
}
InputPosRead &= 0x1ff;
return retval;
}

View File

@ -15,281 +15,295 @@
#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)
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_VOL:
RegLog(2, "IIR_VOL", rmem, core, value);
break;
case R_COMB1_VOL:
RegLog(2, "COMB1_VOL", rmem, core, value);
break;
case R_COMB2_VOL:
RegLog(2, "COMB2_VOL", rmem, core, value);
break;
case R_COMB3_VOL:
RegLog(2, "COMB3_VOL", rmem, core, value);
break;
case R_COMB4_VOL:
RegLog(2, "COMB4_VOL", rmem, core, value);
break;
case R_WALL_VOL:
RegLog(2, "WALL_VOL", rmem, core, value);
break;
case R_APF1_VOL:
RegLog(2, "APF1_VOL", rmem, core, value);
break;
case R_APF2_VOL:
RegLog(2, "APF2_VOL", 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);
break;
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;
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_VOL:
RegLog(2, "IIR_VOL", rmem, core, value);
break;
case R_COMB1_VOL:
RegLog(2, "COMB1_VOL", rmem, core, value);
break;
case R_COMB2_VOL:
RegLog(2, "COMB2_VOL", rmem, core, value);
break;
case R_COMB3_VOL:
RegLog(2, "COMB3_VOL", rmem, core, value);
break;
case R_COMB4_VOL:
RegLog(2, "COMB4_VOL", rmem, core, value);
break;
case R_WALL_VOL:
RegLog(2, "WALL_VOL", rmem, core, value);
break;
case R_APF1_VOL:
RegLog(2, "APF1_VOL", rmem, core, value);
break;
case R_APF2_VOL:
RegLog(2, "APF2_VOL", 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);
break;
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;
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(APF1_SIZE, "APF1_SIZE")
LOG_REVB_REG(APF2_SIZE, "APF2_SIZE")
LOG_REVB_REG(SAME_L_SRC, "SAME_L_SRC")
LOG_REVB_REG(SAME_R_SRC, "SAME_R_SRC")
LOG_REVB_REG(DIFF_L_SRC, "DIFF_L_SRC")
LOG_REVB_REG(DIFF_R_SRC, "DIFF_R_SRC")
LOG_REVB_REG(SAME_L_DST, "SAME_L_DST")
LOG_REVB_REG(SAME_R_DST, "SAME_R_DST")
LOG_REVB_REG(DIFF_L_DST, "DIFF_L_DST")
LOG_REVB_REG(DIFF_R_DST, "DIFF_R_DST")
LOG_REVB_REG(COMB1_L_SRC, "COMB1_L_SRC")
LOG_REVB_REG(COMB1_R_SRC, "COMB1_R_SRC")
LOG_REVB_REG(COMB2_L_SRC, "COMB2_L_SRC")
LOG_REVB_REG(COMB2_R_SRC, "COMB2_R_SRC")
LOG_REVB_REG(COMB3_L_SRC, "COMB3_L_SRC")
LOG_REVB_REG(COMB3_R_SRC, "COMB3_R_SRC")
LOG_REVB_REG(COMB4_L_SRC, "COMB4_L_SRC")
LOG_REVB_REG(COMB4_R_SRC, "COMB4_R_SRC")
LOG_REVB_REG(APF1_L_DST, "APF1_L_DST")
LOG_REVB_REG(APF1_R_DST, "APF1_R_DST")
LOG_REVB_REG(APF2_L_DST, "APF2_L_DST")
LOG_REVB_REG(APF2_R_DST, "APF2_R_DST")
LOG_REVB_REG(APF1_SIZE, "APF1_SIZE")
LOG_REVB_REG(APF2_SIZE, "APF2_SIZE")
LOG_REVB_REG(SAME_L_SRC, "SAME_L_SRC")
LOG_REVB_REG(SAME_R_SRC, "SAME_R_SRC")
LOG_REVB_REG(DIFF_L_SRC, "DIFF_L_SRC")
LOG_REVB_REG(DIFF_R_SRC, "DIFF_R_SRC")
LOG_REVB_REG(SAME_L_DST, "SAME_L_DST")
LOG_REVB_REG(SAME_R_DST, "SAME_R_DST")
LOG_REVB_REG(DIFF_L_DST, "DIFF_L_DST")
LOG_REVB_REG(DIFF_R_DST, "DIFF_R_DST")
LOG_REVB_REG(COMB1_L_SRC, "COMB1_L_SRC")
LOG_REVB_REG(COMB1_R_SRC, "COMB1_R_SRC")
LOG_REVB_REG(COMB2_L_SRC, "COMB2_L_SRC")
LOG_REVB_REG(COMB2_R_SRC, "COMB2_R_SRC")
LOG_REVB_REG(COMB3_L_SRC, "COMB3_L_SRC")
LOG_REVB_REG(COMB3_R_SRC, "COMB3_R_SRC")
LOG_REVB_REG(COMB4_L_SRC, "COMB4_L_SRC")
LOG_REVB_REG(COMB4_R_SRC, "COMB4_R_SRC")
LOG_REVB_REG(APF1_L_DST, "APF1_L_DST")
LOG_REVB_REG(APF1_R_DST, "APF1_R_DST")
LOG_REVB_REG(APF2_L_DST, "APF2_L_DST")
LOG_REVB_REG(APF2_R_DST, "APF2_R_DST")
default:
RegLog(2, "UNKNOWN", rmem, core, value);
spu2Ru16(mem) = value;
}
}
default:
RegLog(2, "UNKNOWN", rmem, core, value);
spu2Ru16(mem) = value;
}
}
}

View File

@ -16,286 +16,286 @@
#include "Global.h"
#define PCORE(c, p) \
U16P(Cores[c].p)
U16P(Cores[c].p)
#define PVCP(c, v, p) \
PCORE(c, Voices[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
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)
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)
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, APF1_SIZE),
PREVB_REG(0, APF2_SIZE),
PREVB_REG(0, SAME_L_DST),
PREVB_REG(0, SAME_R_DST),
PREVB_REG(0, COMB1_L_SRC),
PREVB_REG(0, COMB1_R_SRC),
PREVB_REG(0, COMB2_L_SRC),
PREVB_REG(0, COMB2_R_SRC),
PREVB_REG(0, SAME_L_SRC),
PREVB_REG(0, SAME_R_SRC),
PREVB_REG(0, DIFF_L_DST),
PREVB_REG(0, DIFF_R_DST),
PREVB_REG(0, COMB3_L_SRC),
PREVB_REG(0, COMB3_R_SRC),
PREVB_REG(0, COMB4_L_SRC),
PREVB_REG(0, COMB4_R_SRC),
PREVB_REG(0, DIFF_L_SRC),
PREVB_REG(0, DIFF_R_SRC),
PREVB_REG(0, APF1_L_DST),
PREVB_REG(0, APF1_R_DST),
PREVB_REG(0, APF2_L_DST),
PREVB_REG(0, APF2_R_DST),
PREVB_REG(0, APF1_SIZE),
PREVB_REG(0, APF2_SIZE),
PREVB_REG(0, SAME_L_DST),
PREVB_REG(0, SAME_R_DST),
PREVB_REG(0, COMB1_L_SRC),
PREVB_REG(0, COMB1_R_SRC),
PREVB_REG(0, COMB2_L_SRC),
PREVB_REG(0, COMB2_R_SRC),
PREVB_REG(0, SAME_L_SRC),
PREVB_REG(0, SAME_R_SRC),
PREVB_REG(0, DIFF_L_DST),
PREVB_REG(0, DIFF_R_DST),
PREVB_REG(0, COMB3_L_SRC),
PREVB_REG(0, COMB3_R_SRC),
PREVB_REG(0, COMB4_L_SRC),
PREVB_REG(0, COMB4_R_SRC),
PREVB_REG(0, DIFF_L_SRC),
PREVB_REG(0, DIFF_R_SRC),
PREVB_REG(0, APF1_L_DST),
PREVB_REG(0, APF1_R_DST),
PREVB_REG(0, APF2_L_DST),
PREVB_REG(0, APF2_R_DST),
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, APF1_SIZE),
PREVB_REG(1, APF2_SIZE),
PREVB_REG(1, SAME_L_DST),
PREVB_REG(1, SAME_R_DST),
PREVB_REG(1, COMB1_L_SRC),
PREVB_REG(1, COMB1_R_SRC),
PREVB_REG(1, COMB2_L_SRC),
PREVB_REG(1, COMB2_R_SRC),
PREVB_REG(1, SAME_L_SRC),
PREVB_REG(1, SAME_R_SRC),
PREVB_REG(1, DIFF_L_DST),
PREVB_REG(1, DIFF_R_DST),
PREVB_REG(1, COMB3_L_SRC),
PREVB_REG(1, COMB3_R_SRC),
PREVB_REG(1, COMB4_L_SRC),
PREVB_REG(1, COMB4_R_SRC),
PREVB_REG(1, DIFF_L_SRC),
PREVB_REG(1, DIFF_R_SRC),
PREVB_REG(1, APF1_L_DST),
PREVB_REG(1, APF1_R_DST),
PREVB_REG(1, APF2_L_DST),
PREVB_REG(1, APF2_R_DST),
PREVB_REG(1, APF1_SIZE),
PREVB_REG(1, APF2_SIZE),
PREVB_REG(1, SAME_L_DST),
PREVB_REG(1, SAME_R_DST),
PREVB_REG(1, COMB1_L_SRC),
PREVB_REG(1, COMB1_R_SRC),
PREVB_REG(1, COMB2_L_SRC),
PREVB_REG(1, COMB2_R_SRC),
PREVB_REG(1, SAME_L_SRC),
PREVB_REG(1, SAME_R_SRC),
PREVB_REG(1, DIFF_L_DST),
PREVB_REG(1, DIFF_R_DST),
PREVB_REG(1, COMB3_L_SRC),
PREVB_REG(1, COMB3_R_SRC),
PREVB_REG(1, COMB4_L_SRC),
PREVB_REG(1, COMB4_R_SRC),
PREVB_REG(1, DIFF_L_SRC),
PREVB_REG(1, DIFF_R_SRC),
PREVB_REG(1, APF1_L_DST),
PREVB_REG(1, APF1_R_DST),
PREVB_REG(1, APF2_L_DST),
PREVB_REG(1, APF2_R_DST),
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_VOL),
PCORE(0, Revb.COMB1_VOL),
PCORE(0, Revb.COMB2_VOL),
PCORE(0, Revb.COMB3_VOL),
PCORE(0, Revb.COMB4_VOL),
PCORE(0, Revb.WALL_VOL),
PCORE(0, Revb.APF1_VOL),
PCORE(0, Revb.APF2_VOL),
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_VOL),
PCORE(0, Revb.COMB1_VOL),
PCORE(0, Revb.COMB2_VOL),
PCORE(0, Revb.COMB3_VOL),
PCORE(0, Revb.COMB4_VOL),
PCORE(0, Revb.WALL_VOL),
PCORE(0, Revb.APF1_VOL),
PCORE(0, Revb.APF2_VOL),
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_VOL),
PCORE(1, Revb.COMB1_VOL),
PCORE(1, Revb.COMB2_VOL),
PCORE(1, Revb.COMB3_VOL),
PCORE(1, Revb.COMB4_VOL),
PCORE(1, Revb.WALL_VOL),
PCORE(1, Revb.APF1_VOL),
PCORE(1, Revb.APF2_VOL),
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_VOL),
PCORE(1, Revb.COMB1_VOL),
PCORE(1, Revb.COMB2_VOL),
PCORE(1, Revb.COMB3_VOL),
PCORE(1, Revb.COMB4_VOL),
PCORE(1, Revb.WALL_VOL),
PCORE(1, Revb.APF1_VOL),
PCORE(1, Revb.APF2_VOL),
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

@ -17,115 +17,122 @@
__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 (EffectsBufferSize <= 0) {
return StereoOut32::Empty;
}
if (EffectsBufferSize <= 0)
{
return StereoOut32::Empty;
}
bool R = Cycles & 1;
bool R = Cycles & 1;
// Calculate the read/write addresses we'll be needing for this session of reverb.
// Calculate the read/write addresses we'll be needing for this session of reverb.
const u32 same_src = RevbGetIndexer(R ? RevBuffers.SAME_R_SRC : RevBuffers.SAME_L_SRC);
const u32 same_dst = RevbGetIndexer(R ? RevBuffers.SAME_R_DST : RevBuffers.SAME_L_DST);
const u32 same_prv = RevbGetIndexer(R ? RevBuffers.SAME_R_PRV : RevBuffers.SAME_L_PRV);
const u32 same_src = RevbGetIndexer(R ? RevBuffers.SAME_R_SRC : RevBuffers.SAME_L_SRC);
const u32 same_dst = RevbGetIndexer(R ? RevBuffers.SAME_R_DST : RevBuffers.SAME_L_DST);
const u32 same_prv = RevbGetIndexer(R ? RevBuffers.SAME_R_PRV : RevBuffers.SAME_L_PRV);
const u32 diff_src = RevbGetIndexer(R ? RevBuffers.DIFF_L_SRC : RevBuffers.DIFF_R_SRC);
const u32 diff_dst = RevbGetIndexer(R ? RevBuffers.DIFF_R_DST : RevBuffers.DIFF_L_DST);
const u32 diff_prv = RevbGetIndexer(R ? RevBuffers.DIFF_R_PRV : RevBuffers.DIFF_L_PRV);
const u32 diff_src = RevbGetIndexer(R ? RevBuffers.DIFF_L_SRC : RevBuffers.DIFF_R_SRC);
const u32 diff_dst = RevbGetIndexer(R ? RevBuffers.DIFF_R_DST : RevBuffers.DIFF_L_DST);
const u32 diff_prv = RevbGetIndexer(R ? RevBuffers.DIFF_R_PRV : RevBuffers.DIFF_L_PRV);
const u32 comb1_src = RevbGetIndexer(R ? RevBuffers.COMB1_R_SRC : RevBuffers.COMB1_L_SRC);
const u32 comb2_src = RevbGetIndexer(R ? RevBuffers.COMB2_R_SRC : RevBuffers.COMB2_L_SRC);
const u32 comb3_src = RevbGetIndexer(R ? RevBuffers.COMB3_R_SRC : RevBuffers.COMB3_L_SRC);
const u32 comb4_src = RevbGetIndexer(R ? RevBuffers.COMB4_R_SRC : RevBuffers.COMB4_L_SRC);
const u32 comb1_src = RevbGetIndexer(R ? RevBuffers.COMB1_R_SRC : RevBuffers.COMB1_L_SRC);
const u32 comb2_src = RevbGetIndexer(R ? RevBuffers.COMB2_R_SRC : RevBuffers.COMB2_L_SRC);
const u32 comb3_src = RevbGetIndexer(R ? RevBuffers.COMB3_R_SRC : RevBuffers.COMB3_L_SRC);
const u32 comb4_src = RevbGetIndexer(R ? RevBuffers.COMB4_R_SRC : RevBuffers.COMB4_L_SRC);
const u32 apf1_src = RevbGetIndexer(R ? RevBuffers.APF1_R_SRC : RevBuffers.APF1_L_SRC);
const u32 apf1_dst = RevbGetIndexer(R ? RevBuffers.APF1_R_DST : RevBuffers.APF1_L_DST);
const u32 apf2_src = RevbGetIndexer(R ? RevBuffers.APF2_R_SRC : RevBuffers.APF2_L_SRC);
const u32 apf2_dst = RevbGetIndexer(R ? RevBuffers.APF2_R_DST : RevBuffers.APF2_L_DST);
const u32 apf1_src = RevbGetIndexer(R ? RevBuffers.APF1_R_SRC : RevBuffers.APF1_L_SRC);
const u32 apf1_dst = RevbGetIndexer(R ? RevBuffers.APF1_R_DST : RevBuffers.APF1_L_DST);
const u32 apf2_src = RevbGetIndexer(R ? RevBuffers.APF2_R_SRC : RevBuffers.APF2_L_SRC);
const u32 apf2_dst = RevbGetIndexer(R ? RevBuffers.APF2_R_DST : RevBuffers.APF2_L_DST);
// -----------------------------------------
// 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 == same_src) || (Cores[i].IRQA == diff_src) ||
(Cores[i].IRQA == same_dst) || (Cores[i].IRQA == diff_dst) ||
(Cores[i].IRQA == same_prv) || (Cores[i].IRQA == diff_prv) ||
for (int i = 0; i < 2; i++)
{
if (Cores[i].IRQEnable && ((Cores[i].IRQA >= EffectsStartA) && (Cores[i].IRQA <= EffectsEndA)))
{
if ((Cores[i].IRQA == same_src) || (Cores[i].IRQA == diff_src) ||
(Cores[i].IRQA == same_dst) || (Cores[i].IRQA == diff_dst) ||
(Cores[i].IRQA == same_prv) || (Cores[i].IRQA == diff_prv) ||
(Cores[i].IRQA == comb1_src) || (Cores[i].IRQA == comb2_src) ||
(Cores[i].IRQA == comb3_src) || (Cores[i].IRQA == comb4_src) ||
(Cores[i].IRQA == comb1_src) || (Cores[i].IRQA == comb2_src) ||
(Cores[i].IRQA == comb3_src) || (Cores[i].IRQA == comb4_src) ||
(Cores[i].IRQA == apf1_dst) || (Cores[i].IRQA == apf1_src) ||
(Cores[i].IRQA == apf2_dst) || (Cores[i].IRQA == apf2_src)) {
//printf("Core %d IRQ Called (Reverb). IRQA = %x\n",i,addr);
SetIrqCall(i);
}
}
}
(Cores[i].IRQA == apf1_dst) || (Cores[i].IRQA == apf1_src) ||
(Cores[i].IRQA == apf2_dst) || (Cores[i].IRQA == apf2_src))
{
//printf("Core %d IRQ Called (Reverb). IRQA = %x\n",i,addr);
SetIrqCall(i);
}
}
}
// Reverb algorithm pretty much directly ripped from http://drhell.web.fc2.com/ps1/
// minus the 35 step FIR which just seems to break things.
// Reverb algorithm pretty much directly ripped from http://drhell.web.fc2.com/ps1/
// minus the 35 step FIR which just seems to break things.
s32 in, same, diff, apf1, apf2, out;
s32 in, same, diff, apf1, apf2, out;
#define MUL(x, y) ((x) * (y) >> 15)
in = MUL(R ? Revb.IN_COEF_R : Revb.IN_COEF_L, R ? Input.Right : Input.Left);
in = MUL(R ? Revb.IN_COEF_R : Revb.IN_COEF_L, R ? Input.Right : Input.Left);
same = MUL(Revb.IIR_VOL, in + MUL(Revb.WALL_VOL, _spu2mem[same_src]) - _spu2mem[same_prv]) + _spu2mem[same_prv];
diff = MUL(Revb.IIR_VOL, in + MUL(Revb.WALL_VOL, _spu2mem[diff_src]) - _spu2mem[diff_prv]) + _spu2mem[diff_prv];
same = MUL(Revb.IIR_VOL, in + MUL(Revb.WALL_VOL, _spu2mem[same_src]) - _spu2mem[same_prv]) + _spu2mem[same_prv];
diff = MUL(Revb.IIR_VOL, in + MUL(Revb.WALL_VOL, _spu2mem[diff_src]) - _spu2mem[diff_prv]) + _spu2mem[diff_prv];
out = MUL(Revb.COMB1_VOL, _spu2mem[comb1_src]) + MUL(Revb.COMB2_VOL, _spu2mem[comb2_src]) + MUL(Revb.COMB3_VOL, _spu2mem[comb3_src]) + MUL(Revb.COMB4_VOL, _spu2mem[comb4_src]);
out = MUL(Revb.COMB1_VOL, _spu2mem[comb1_src]) + MUL(Revb.COMB2_VOL, _spu2mem[comb2_src]) + MUL(Revb.COMB3_VOL, _spu2mem[comb3_src]) + MUL(Revb.COMB4_VOL, _spu2mem[comb4_src]);
apf1 = out - MUL(Revb.APF1_VOL, _spu2mem[apf1_src]);
out = _spu2mem[apf1_src] + MUL(Revb.APF1_VOL, apf1);
apf2 = out - MUL(Revb.APF2_VOL, _spu2mem[apf2_src]);
out = _spu2mem[apf2_src] + MUL(Revb.APF2_VOL, apf2);
apf1 = out - MUL(Revb.APF1_VOL, _spu2mem[apf1_src]);
out = _spu2mem[apf1_src] + MUL(Revb.APF1_VOL, apf1);
apf2 = out - MUL(Revb.APF2_VOL, _spu2mem[apf2_src]);
out = _spu2mem[apf2_src] + MUL(Revb.APF2_VOL, apf2);
// According to no$psx the effects always run but don't always write back, see check in V_Core::Mix
if (FxEnable) {
_spu2mem[same_dst] = clamp_mix(same);
_spu2mem[diff_dst] = clamp_mix(diff);
_spu2mem[apf1_dst] = clamp_mix(apf1);
_spu2mem[apf2_dst] = clamp_mix(apf2);
}
// According to no$psx the effects always run but don't always write back, see check in V_Core::Mix
if (FxEnable)
{
_spu2mem[same_dst] = clamp_mix(same);
_spu2mem[diff_dst] = clamp_mix(diff);
_spu2mem[apf1_dst] = clamp_mix(apf1);
_spu2mem[apf2_dst] = clamp_mix(apf2);
}
(R ? LastEffect.Right : LastEffect.Left) = -clamp_mix(out);
(R ? LastEffect.Right : LastEffect.Left) = -clamp_mix(out);
return LastEffect;
return LastEffect;
}

View File

@ -18,208 +18,219 @@
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
{
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
XAudio2Out,
DSoundOut,
WaveOut,
XAudio2Out,
DSoundOut,
WaveOut,
#endif
#if defined(_WIN32) || defined(SPU2X_PORTAUDIO)
PortaudioOut,
PortaudioOut,
#endif
SDLOut,
SDLOut,
#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;
StereoOut32* SndBuffer::m_buffer;
s32 SndBuffer::m_size;
__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)
{
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)
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)
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)
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
@ -227,100 +238,105 @@ void SndBuffer::_ReadSamples_Safe(StereoOut32 *bData, int nSamples)
// 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)
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:
std::fill_n(bData, quietSamples, 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:
std::fill_n(bData, quietSamples, 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)
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) {
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!
@ -346,65 +362,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:
// initialize sound buffer
// Buffer actually attempts to run ~50%, so allocate near double what
// the requested latency is:
m_rpos = 0;
m_wpos = 0;
m_rpos = 0;
m_wpos = 0;
try {
const float latencyMS = SndOutLatencyMS * 16;
m_size = GetAlignedBufferSize((int)(latencyMS * SampleRate / 1000.0f));
printf("%d SampleRate: \n", SampleRate);
m_buffer = new StereoOut32[m_size];
m_underrun_freeze = false;
try
{
const float latencyMS = SndOutLatencyMS * 16;
m_size = GetAlignedBufferSize((int)(latencyMS * SampleRate / 1000.0f));
printf("%d SampleRate: \n", SampleRate);
m_buffer = new StereoOut32[m_size];
m_underrun_freeze = false;
sndTempBuffer = new StereoOut32[SndOutPacketSize];
sndTempBuffer16 = new StereoOut16[SndOutPacketSize * 2]; // in case of leftovers.
} catch (std::bad_alloc &) {
// out of memory exception (most likely)
sndTempBuffer = new StereoOut32[SndOutPacketSize];
sndTempBuffer16 = new StereoOut16[SndOutPacketSize * 2]; // in case of leftovers.
}
catch (std::bad_alloc&)
{
// out of memory exception (most likely)
SysMessage("Out of memory error occurred while initializing SPU2.");
_InitFail();
return;
}
SysMessage("Out of memory error occurred while initializing SPU2.");
_InitFail();
return;
}
sndTempProgress = 0;
sndTempProgress = 0;
soundtouchInit(); // initializes the timestretching
soundtouchInit(); // initializes the timestretching
// initialize module
if (mods[OutputModule]->Init() == -1)
_InitFail();
// 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;
@ -414,78 +434,85 @@ 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--;
// Play silence
std::fill_n(sndTempBuffer, SndOutPacketSize, StereoOut32{});
}
//Don't play anything directly after loading a savestate, avoids static killing your speakers.
if (ssFreeze > 0)
{
ssFreeze--;
// Play silence
std::fill_n(sndTempBuffer, SndOutPacketSize, StereoOut32{});
}
#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

@ -35,159 +35,168 @@ typedef StereoOut16 StereoOut_SDL;
namespace
{
/* Since spu2 only ever outputs stereo, we don't worry about emitting surround sound
/* 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);
}
} // namespace
struct SDLAudioMod : public SndOutModule
{
static SDLAudioMod mod;
std::string m_api;
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;
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

@ -21,7 +21,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,7 +36,7 @@ float SndBuffer::eTempo = 1;
void SndBuffer::PredictDataWrite(int samples)
{
m_predictData += samples;
m_predictData += samples;
}
// Calculate the buffer status percentage.
@ -46,17 +46,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;
}
@ -108,266 +108,278 @@ 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;
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;
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;
unsigned int actualWindow = std::min(available, AVERAGING_WINDOW);
unsigned int first = (nextAvgPos - actualWindow + AVERAGING_BUFFER_SIZE) % 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;
// 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
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);
tempoAdjust = GetClamped(tempoAdjust, 0.05f, 10.0f);
if (tempoAdjust < 1)
baseTargetFullness /= sqrt(tempoAdjust); // slightly increase latency when running slow.
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;
dynamicTargetFullness += (baseTargetFullness / tempoAdjust - dynamicTargetFullness) / (double)compensationDivider;
if (IsInRange(tempoAdjust, 0.9f, 1.1f) && IsInRange(dynamicTargetFullness, baseTargetFullness * 0.9f, baseTargetFullness * 1.1f))
dynamicTargetFullness = baseTargetFullness;
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)
{
if (IsInRange(tempoAdjust, 1.0f / hys_ok_factor, hys_ok_factor))
hys_ok_count++;
else
hys_ok_count = 0;
if (hys_ok_count >= hys_min_ok_count) {
inside_hysteresis = true;
if (MsgOverruns())
ConLog("======> stretch: None (1:1)\n");
}
if (hys_ok_count >= hys_min_ok_count)
{
inside_hysteresis = true;
if (MsgOverruns())
ConLog("======> stretch: None (1:1)\n");
}
}
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;
}
} 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)
tempoAdjust = 1.0;
if (inside_hysteresis)
tempoAdjust = 1.0;
if (MsgOverruns())
{
static int iters = 0;
static wxDateTime last = wxDateTime::UNow();
wxDateTime unow = wxDateTime::UNow();
wxTimeSpan delta = unow.Subtract(last);
if (MsgOverruns()) {
static int iters = 0;
static wxDateTime last = wxDateTime::UNow();
wxDateTime unow = wxDateTime::UNow();
wxTimeSpan delta = unow.Subtract(last);
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 (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;
pSoundTouch->setTempo(tempoAdjust);
if (gRequestStretcherReset >= STRETCHER_RESET_THRESHOLD)
gRequestStretcherReset = 0;
return;
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),
@ -375,164 +387,174 @@ 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

@ -37,109 +37,113 @@ static const char dataStr[] = "data";
// Class WavOutFile
//
WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels)
WavOutFile::WavOutFile(const char* fileName, int sampleRate, int bits, int channels)
{
bytesWritten = 0;
fptr = fopen(fileName, "wb");
if (fptr == NULL) {
string msg = "Error : Unable to open file \"";
msg += fileName;
msg += "\" for writing.";
//pmsg = msg.c_str;
throw runtime_error(msg);
}
bytesWritten = 0;
fptr = fopen(fileName, "wb");
if (fptr == NULL)
{
string msg = "Error : Unable to open file \"";
msg += fileName;
msg += "\" for writing.";
//pmsg = msg.c_str;
throw runtime_error(msg);
}
fillInHeader(sampleRate, bits, channels);
writeHeader();
fillInHeader(sampleRate, bits, channels);
writeHeader();
}
WavOutFile::~WavOutFile()
{
if (fptr) {
finishHeader();
fclose(fptr);
}
if (fptr)
{
finishHeader();
fclose(fptr);
}
}
void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels)
{
// fill in the 'riff' part..
// fill in the 'riff' part..
// copy string 'RIFF' to riff_char
memcpy(&(header.riff.riff_char), riffStr, 4);
// package_len unknown so far
header.riff.package_len = 0;
// copy string 'WAVE' to wave
memcpy(&(header.riff.wave), waveStr, 4);
// copy string 'RIFF' to riff_char
memcpy(&(header.riff.riff_char), riffStr, 4);
// package_len unknown so far
header.riff.package_len = 0;
// copy string 'WAVE' to wave
memcpy(&(header.riff.wave), waveStr, 4);
// fill in the 'format' part..
// fill in the 'format' part..
// copy string 'fmt ' to fmt
memcpy(&(header.format.fmt), fmtStr, 4);
// copy string 'fmt ' to fmt
memcpy(&(header.format.fmt), fmtStr, 4);
header.format.format_len = 0x10;
header.format.fixed = 1;
header.format.channel_number = (short)channels;
header.format.sample_rate = (int)sampleRate;
header.format.bits_per_sample = (short)bits;
header.format.byte_per_sample = (short)(bits * channels / 8);
header.format.byte_rate = header.format.byte_per_sample * (int)sampleRate;
header.format.sample_rate = (int)sampleRate;
header.format.format_len = 0x10;
header.format.fixed = 1;
header.format.channel_number = (short)channels;
header.format.sample_rate = (int)sampleRate;
header.format.bits_per_sample = (short)bits;
header.format.byte_per_sample = (short)(bits * channels / 8);
header.format.byte_rate = header.format.byte_per_sample * (int)sampleRate;
header.format.sample_rate = (int)sampleRate;
// fill in the 'data' part..
// fill in the 'data' part..
// copy string 'data' to data_field
memcpy(&(header.data.data_field), dataStr, 4);
// data_len unknown so far
header.data.data_len = 0;
// copy string 'data' to data_field
memcpy(&(header.data.data_field), dataStr, 4);
// data_len unknown so far
header.data.data_len = 0;
}
void WavOutFile::finishHeader()
{
// supplement the file length into the header structure
header.riff.package_len = bytesWritten + 36;
header.data.data_len = bytesWritten;
// supplement the file length into the header structure
header.riff.package_len = bytesWritten + 36;
header.data.data_len = bytesWritten;
writeHeader();
writeHeader();
}
void WavOutFile::writeHeader()
{
int res;
int res;
// 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) {
throw runtime_error("Error while writing to a wav file.");
}
// 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)
{
throw runtime_error("Error while writing to a wav file.");
}
// jump back to the end of the file
fseek(fptr, 0, SEEK_END);
// jump back to the end of the file
fseek(fptr, 0, SEEK_END);
}
void WavOutFile::write(const short *buffer, int numElems)
void WavOutFile::write(const short* buffer, int numElems)
{
int res;
int res;
// 16bit format & 16 bit samples
// 16bit format & 16 bit samples
assert(header.format.bits_per_sample == 16);
if (numElems < 1)
return; // nothing to do
assert(header.format.bits_per_sample == 16);
if (numElems < 1)
return; // nothing to do
res = fwrite(buffer, 2, numElems, fptr);
res = fwrite(buffer, 2, numElems, fptr);
if (res != numElems) {
throw runtime_error("Error while writing to a wav file.");
}
bytesWritten += 2 * numElems;
if (res != numElems)
{
throw runtime_error("Error while writing to a wav file.");
}
bytesWritten += 2 * numElems;
}

View File

@ -29,38 +29,38 @@ typedef unsigned int uint;
/// WAV audio file 'riff' section header
typedef struct
{
char riff_char[4];
int package_len;
char wave[4];
char riff_char[4];
int package_len;
char wave[4];
} WavRiff;
/// WAV audio file 'format' section header
typedef struct
{
char fmt[4];
int format_len;
short fixed;
short channel_number;
int sample_rate;
int byte_rate;
short byte_per_sample;
short bits_per_sample;
char fmt[4];
int format_len;
short fixed;
short channel_number;
int sample_rate;
int byte_rate;
short byte_per_sample;
short bits_per_sample;
} WavFormat;
/// WAV audio file 'data' section header
typedef struct
{
char data_field[4];
uint data_len;
char data_field[4];
uint data_len;
} WavData;
/// WAV audio file header
typedef struct
{
WavRiff riff;
WavFormat format;
WavData data;
WavRiff riff;
WavFormat format;
WavData data;
} WavHeader;
@ -68,42 +68,42 @@ typedef struct
class WavOutFile
{
private:
/// Pointer to the WAV file
FILE *fptr;
/// Pointer to the WAV file
FILE* fptr;
/// WAV file header data.
WavHeader header;
/// WAV file header data.
WavHeader header;
/// Counter of how many bytes have been written to the file so far.
int bytesWritten;
/// Counter of how many bytes have been written to the file so far.
int bytesWritten;
/// Fills in WAV file header information.
void fillInHeader(const uint sampleRate, const uint bits, const uint channels);
/// Fills in WAV file header information.
void fillInHeader(const uint sampleRate, const uint bits, const uint channels);
/// Finishes the WAV file header by supplementing information of amount of
/// data written to file etc
void finishHeader();
/// Finishes the WAV file header by supplementing information of amount of
/// data written to file etc
void finishHeader();
/// Writes the WAV file header.
void writeHeader();
/// Writes the WAV file header.
void writeHeader();
public:
/// 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)
);
/// 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)
);
/// Destructor: Finalizes & closes the WAV file.
~WavOutFile();
/// Destructor: Finalizes & closes the WAV file.
~WavOutFile();
/// 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.
);
/// 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.
);
};
#endif

View File

@ -20,78 +20,85 @@
#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];
static WavOutFile* m_CoreWav[2][CoreSrc_Count];
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%ud-%s.wav",
cidx, m_tbl_CoreOutputTypeNames[srcidx]);
sprintf(wavfilename, "logs/spu2x-Core%ud-%s.wav",
cidx, m_tbl_CoreOutputTypeNames[srcidx]);
#else
sprintf(wavfilename, "logs\\spu2x-Core%ud-%s.wav",
cidx, m_tbl_CoreOutputTypeNames[srcidx]);
sprintf(wavfilename, "logs\\spu2x-Core%ud-%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));
}
} // namespace WaveDump
#include "Utilities/Threading.h"
@ -99,42 +106,45 @@ using namespace Threading;
bool WavRecordEnabled = false;
static WavOutFile *m_wavrecord = NULL;
static WavOutFile* m_wavrecord = NULL;
static Mutex WavRecordMutex;
void RecordStart(std::wstring* filename)
{
WavRecordEnabled = false;
WavRecordEnabled = false;
try {
ScopedLock lock(WavRecordMutex);
safe_delete(m_wavrecord);
try
{
ScopedLock lock(WavRecordMutex);
safe_delete(m_wavrecord);
#ifdef _WIN32
if (filename)
m_wavrecord = new WavOutFile((*filename) + "wav", 48000, 16, 2);
else
m_wavrecord = new WavOutFile("audio_recording.wav", 48000, 16, 2);
if (filename)
m_wavrecord = new WavOutFile((*filename) + "wav", 48000, 16, 2);
else
m_wavrecord = new WavOutFile("audio_recording.wav", 48000, 16, 2);
#elif defined(__unix__)
m_wavrecord = new WavOutFile("audio_recording.wav", 48000, 16, 2);
m_wavrecord = new WavOutFile("audio_recording.wav", 48000, 16, 2);
#endif
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.", "audio_recording.wav");
}
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.", "audio_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

@ -20,29 +20,29 @@
extern uptr gsWindowHandle;
void SysMessage(const char *fmt, ...)
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, ...)
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);
}
//////
@ -51,9 +51,9 @@ void SysMessage(const wchar_t *fmt, ...)
static wxString CfgFile(L"inis/SPU2.ini");
void CfgSetSettingsDir(const char *dir)
void CfgSetSettingsDir(const char* dir)
{
CfgFile = Path::Combine((dir == NULL) ? wxString(L"inis") : wxString::FromUTF8(dir), L"SPU2.ini");
CfgFile = Path::Combine((dir == NULL) ? wxString(L"inis") : wxString::FromUTF8(dir), L"SPU2.ini");
}
@ -72,24 +72,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)
@ -97,99 +97,104 @@ 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

@ -83,344 +83,366 @@ 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());
CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2Out->GetIdent());
// CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, PortaudioOut->GetIdent());
CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2Out->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);
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();
PortaudioOut->WriteSettings();
DSoundOut->WriteSettings();
SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings();
}
void CheckOutputModule(HWND window)
{
OutputModule = SendMessage(GetDlgItem(window, IDC_OUTPUT), CB_GETCURSEL, 0, 0);
const bool IsConfigurable =
mods[OutputModule] == PortaudioOut ||
mods[OutputModule] == WaveOut ||
mods[OutputModule] == DSoundOut;
OutputModule = SendMessage(GetDlgItem(window, IDC_OUTPUT), CB_GETCURSEL, 0, 0);
const bool IsConfigurable =
mods[OutputModule] == PortaudioOut ||
mods[OutputModule] == WaveOut ||
mods[OutputModule] == DSoundOut;
const bool AudioExpansion =
mods[OutputModule] == XAudio2Out ||
mods[OutputModule] == PortaudioOut;
const bool AudioExpansion =
mods[OutputModule] == XAudio2Out ||
mods[OutputModule] == PortaudioOut;
EnableWindow(GetDlgItem(window, IDC_OUTCONF), IsConfigurable);
EnableWindow(GetDlgItem(window, IDC_SPEAKERS), AudioExpansion);
EnableWindow(GetDlgItem(window, IDC_SPEAKERS_TEXT), AudioExpansion);
EnableWindow(GetDlgItem(window, IDC_OUTCONF), IsConfigurable);
EnableWindow(GetDlgItem(window, IDC_SPEAKERS), AudioExpansion);
EnableWindow(GetDlgItem(window, IDC_SPEAKERS_TEXT), AudioExpansion);
}
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_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_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_OUTPUT, CB_RESETCONTENT, 0, 0);
SendDialogMsg(hWnd, IDC_OUTPUT, CB_RESETCONTENT, 0, 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);
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);
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);
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);
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_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);
int configvol = (int)(FinalVolume * 100 + 0.5f);
INIT_SLIDER(IDC_VOLUME_SLIDER, 0, 100, 10, 42, 1);
int configvol = (int)(FinalVolume * 100 + 0.5f);
INIT_SLIDER(IDC_VOLUME_SLIDER, 0, 100, 10, 42, 1);
SendDialogMsg(hWnd, IDC_VOLUME_SLIDER, TBM_SETPOS, TRUE, configvol);
swprintf_s(temp, L"%d%%", configvol);
SetWindowText(GetDlgItem(hWnd, IDC_VOLUME_LABEL), temp);
SendDialogMsg(hWnd, IDC_VOLUME_SLIDER, TBM_SETPOS, TRUE, configvol);
swprintf_s(temp, L"%d%%", configvol);
SetWindowText(GetDlgItem(hWnd, IDC_VOLUME_LABEL), temp);
CheckOutputModule(hWnd);
CheckOutputModule(hWnd);
EnableWindow(GetDlgItem(hWnd, IDC_OPEN_CONFIG_SOUNDTOUCH), (SynchMode == 0));
EnableWindow(GetDlgItem(hWnd, IDC_OPEN_CONFIG_DEBUG), DebugEnabled);
EnableWindow(GetDlgItem(hWnd, IDC_OPEN_CONFIG_SOUNDTOUCH), (SynchMode == 0));
EnableWindow(GetDlgItem(hWnd, IDC_OPEN_CONFIG_DEBUG), DebugEnabled);
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;
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 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 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);
WriteSettings();
EndDialog(hWnd, 0);
} break;
WriteSettings();
EndDialog(hWnd, 0);
}
break;
case IDCANCEL:
EndDialog(hWnd, 0);
break;
case IDCANCEL:
EndDialog(hWnd, 0);
break;
case IDC_OUTPUT:
if (wmEvent == CBN_SELCHANGE) {
CheckOutputModule(hWnd);
}
break;
case IDC_OUTPUT:
if (wmEvent == CBN_SELCHANGE)
{
CheckOutputModule(hWnd);
}
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_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_OPEN_CONFIG_DEBUG: {
// Quick Hack -- DebugEnabled is re-loaded with the DebugConfig's API,
// so we need to override it here:
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;
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);
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;
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;
int curpos = HIWORD(wParam);
int curpos = HIWORD(wParam);
switch (wmEvent) {
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_TOP:
case TB_BOTTOM:
curpos = (int)SendMessage(hwndDlg, TBM_GETPOS, 0, 0);
switch (wmEvent)
{
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_TOP:
case TB_BOTTOM:
curpos = (int)SendMessage(hwndDlg, TBM_GETPOS, 0, 0);
case TB_THUMBPOSITION:
case TB_THUMBTRACK:
Clampify(curpos,
(int)SendMessage(hwndDlg, TBM_GETRANGEMIN, 0, 0),
(int)SendMessage(hwndDlg, TBM_GETRANGEMAX, 0, 0));
case TB_THUMBPOSITION:
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_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_VOLUME_SLIDER))
{
swprintf_s(temp, L"%d%%", curpos);
SetDlgItemText(hWnd, IDC_VOLUME_LABEL, temp);
}
break;
default:
return FALSE;
}
} break;
default:
return FALSE;
}
}
break;
default:
return FALSE;
}
return TRUE;
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

@ -55,213 +55,219 @@ 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
{
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);
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);
_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);
void WriteSettings()
{
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)
{
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());
}
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());
}
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);
}
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);
}
static BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId;
//wchar_t temp[384]={0};
static BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
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;
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;
}
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();
}
}
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();
}
} // namespace DebugConfig

View File

@ -32,98 +32,106 @@ 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)
{
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)
{
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

@ -23,19 +23,19 @@
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 DebugConfig
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);
} // namespace SoundtouchCfg
extern int SendDialogMsg(HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam);
@ -44,31 +44,31 @@ 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))
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

@ -23,24 +23,24 @@ HWND hDebugDialog = NULL;
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);
}
@ -48,46 +48,52 @@ HFONT hf = NULL;
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)); // light blue for playing voice
if (vc.Modulated) {
SetDCBrushColor(hdc, RGB(0, 128, 0)); // light green for playing voice with modulation enabled
}
if (vc.Noise) {
SetDCBrushColor(hdc, RGB(128, 0, 0)); // light red for playing voice with noise enabled
}
}
/*
SetDCBrushColor(hdc, RGB(0, 0, 0));
if ((vc.ADSR.Phase > 0) && (vc.ADSR.Phase < 6))
{
SetDCBrushColor(hdc, RGB(0, 0, 128)); // light blue for playing voice
if (vc.Modulated)
{
SetDCBrushColor(hdc, RGB(0, 128, 0)); // light green for playing voice with modulation enabled
}
if (vc.Noise)
{
SetDCBrushColor(hdc, RGB(128, 0, 0)); // light red for playing voice with noise enabled
}
}
/*
else
{
if(vcd.lastStopReason==1)
@ -100,168 +106,181 @@ 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)
{
y = val;
}
else
val = -val;
if (val != 0) {
FillRectangle(hdc, IX + 90 + i, IY + 24 - y, 1, val);
}
}
}
if (val != 0)
{
FillRectangle(hdc, IX + 90 + i, IY + 24 - y, 1, val);
}
}
}
SetTextColor(hdc, RGB(0, 255, 0));
SetBkColor(hdc, RGB(0, 0, 0));
SetTextColor(hdc, RGB(0, 255, 0));
SetBkColor(hdc, RGB(0, 0, 0));
static wchar_t t[256];
static wchar_t t[256];
swprintf_s(t, L"%06x", vc.StartA);
TextOut(hdc, IX + 4, IY + 4, t, 6);
swprintf_s(t, L"%06x", vc.StartA);
TextOut(hdc, IX + 4, IY + 4, t, 6);
swprintf_s(t, L"%06x", vc.NextA);
TextOut(hdc, IX + 4, IY + 18, t, 6);
swprintf_s(t, L"%06x", vc.NextA);
TextOut(hdc, IX + 4, IY + 18, t, 6);
swprintf_s(t, L"%06x", vc.LoopStartA);
TextOut(hdc, IX + 4, IY + 32, t, 6);
swprintf_s(t, L"%06x", vc.LoopStartA);
TextOut(hdc, IX + 4, IY + 32, t, 6);
vcd.displayPeak = 0;
}
vcd.displayPeak = 0;
}
// top now: 400
int JX = 8 + c * 256;
int JY = 584;
// top now: 400
int JX = 8 + c * 256;
int JY = 584;
SetDCBrushColor(hdc, RGB(0, 0, 0));
SetDCPenColor(hdc, RGB(255, 128, 32));
SetDCBrushColor(hdc, RGB(0, 0, 0));
SetDCPenColor(hdc, RGB(255, 128, 32));
FillRectangle(hdc, JX, JY, 252, 60);
DrawRectangle(hdc, JX, JY, 252, 60);
FillRectangle(hdc, JX, JY, 252, 60);
DrawRectangle(hdc, JX, JY, 252, 60);
SetTextColor(hdc, RGB(255, 255, 255));
SetBkColor(hdc, RGB(0, 0, 0));
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);
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);
memset(t, 0, sizeof(t));
swprintf_s(t, L"(%x)", cx.EffectsBufferSize);
TextOut(hdc, JX + 200, JY + 4, t, 7);
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);
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);
memset(t, 0, sizeof(t));
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);
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--;
}
}
TextOut(hdc, JX + 64, JY + 46, t, wcslen(t));
FillRectangle(hdc, JX + 40, JY + 46, 10, 10);
cd.dmaFlag--;
}
}
ReleaseDC(hDebugDialog, hdc);
lCount = 0;
}
ReleaseDC(hDebugDialog, hdc);
lCount = 0;
}
MSG msg;
while (PeekMessage(&msg, hDebugDialog, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
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

@ -24,432 +24,462 @@
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(IIDFromString(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(IIDFromString(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(IIDFromString(m_Device, &DevGuid));
SendMessage(GetDlgItem(hWnd, IDC_DS_DEVICE), CB_RESETCONTENT, 0, 0);
haveGuid = !FAILED(IIDFromString(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_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_TOP:
case TB_BOTTOM:
wmEvent = (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
case TB_THUMBPOSITION:
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_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_TOP:
case TB_BOTTOM:
wmEvent = (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
case TB_THUMBPOSITION:
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;
}
}
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;
}
s32 Test() const
{
return 0;
}
int GetEmptySampleCount()
{
DWORD play, write;
buffer->GetCurrentPosition(&play, &write);
int GetEmptySampleCount()
{
DWORD play, write;
buffer->GetCurrentPosition(&play, &write);
// Note: Dsound's write cursor is bogus. Use our own instead:
// Note: Dsound's write cursor is bogus. Use our own instead:
int empty = play - myLastWrite;
if (empty < 0)
empty = -empty;
int empty = play - myLastWrite;
if (empty < 0)
empty = -empty;
return empty / 2;
}
return empty / 2;
}
const wchar_t *GetIdent() const
{
return L"dsound";
}
const wchar_t* GetIdent() const
{
return L"dsound";
}
const wchar_t *GetLongName() const
{
return L"DirectSound (Nice)";
}
const wchar_t* GetLongName() const
{
return L"DirectSound (Nice)";
}
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 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);
Clampify(m_NumBuffers, (u8)3, (u8)8);
}
Clampify(m_NumBuffers, (u8)3, (u8)8);
}
void SetApiSettings(wxString api)
{
}
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);
}
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)
{
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)
{
pxAssume(DSoundOut != NULL);
return DS._DSEnumCallback(lpGuid, lpcstrDescription, lpcstrModule, lpContext);
pxAssume(DSoundOut != NULL);
return DS._DSEnumCallback(lpGuid, lpcstrDescription, lpcstrModule, lpContext);
}
SndOutModule *DSoundOut = &DS;
SndOutModule* DSoundOut = &DS;

View File

@ -27,395 +27,408 @@
namespace Exception
{
class XAudio2Error : public std::runtime_error
{
private:
static std::string CreateErrorMessage(const HRESULT result, const std::string &msg)
{
std::stringstream ss;
ss << " (code 0x" << std::hex << result << ")\n\n";
switch (result) {
case XAUDIO2_E_INVALID_CALL:
ss << "Invalid call for the XA2 object state.";
break;
case XAUDIO2_E_DEVICE_INVALIDATED:
ss << "Device is unavailable, unplugged, unsupported, or has been consumed by The Nothing.";
break;
default:
ss << "Unknown error code!";
break;
}
return msg + ss.str();
}
class XAudio2Error : public std::runtime_error
{
private:
static std::string CreateErrorMessage(const HRESULT result, const std::string& msg)
{
std::stringstream ss;
ss << " (code 0x" << std::hex << result << ")\n\n";
switch (result)
{
case XAUDIO2_E_INVALID_CALL:
ss << "Invalid call for the XA2 object state.";
break;
case XAUDIO2_E_DEVICE_INVALIDATED:
ss << "Device is unavailable, unplugged, unsupported, or has been consumed by The Nothing.";
break;
default:
ss << "Unknown error code!";
break;
}
return msg + ss.str();
}
public:
explicit XAudio2Error(const HRESULT result, const std::string &msg)
: std::runtime_error(CreateErrorMessage(result, msg))
{
}
};
}
public:
explicit XAudio2Error(const HRESULT result, const std::string& msg)
: std::runtime_error(CreateErrorMessage(result, msg))
{
}
};
} // namespace Exception
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;
std::unique_ptr<s16[]> m_buffer;
class BaseStreamingVoice : public IXAudio2VoiceCallback
{
protected:
IXAudio2SourceVoice* pSourceVoice;
std::unique_ptr<s16[]> m_buffer;
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()
{
DeleteCriticalSection(&cs);
}
virtual ~BaseStreamingVoice()
{
DeleteCriticalSection(&cs);
}
BaseStreamingVoice(uint numChannels)
: pSourceVoice(nullptr)
, m_nBuffers(Config_XAudio2.NumBuffers)
, m_nChannels(numChannels)
, m_BufferSize(SndOutPacketSize * m_nChannels * PacketsPerBuffer)
, m_BufferSizeBytes(m_BufferSize * sizeof(s16))
{
InitializeCriticalSection(&cs);
}
BaseStreamingVoice(uint numChannels)
: pSourceVoice(nullptr)
, m_nBuffers(Config_XAudio2.NumBuffers)
, m_nChannels(numChannels)
, m_BufferSize(SndOutPacketSize * m_nChannels * PacketsPerBuffer)
, m_BufferSizeBytes(m_BufferSize * sizeof(s16))
{
InitializeCriticalSection(&cs);
}
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;
HRESULT hr;
if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX *)&wfx,
XAUDIO2_VOICE_NOSRC, 1.0f, this))) {
throw Exception::XAudio2Error(hr, "XAudio2 CreateSourceVoice failure: ");
}
HRESULT hr;
if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx,
XAUDIO2_VOICE_NOSRC, 1.0f, this)))
{
throw Exception::XAudio2Error(hr, "XAudio2 CreateSourceVoice failure: ");
}
EnterCriticalSection(&cs);
EnterCriticalSection(&cs);
pSourceVoice->FlushSourceBuffers();
pSourceVoice->Start(0, 0);
pSourceVoice->FlushSourceBuffers();
pSourceVoice->Start(0, 0);
m_buffer = std::make_unique<s16[]>(m_nBuffers * m_BufferSize);
m_buffer = std::make_unique<s16[]>(m_nBuffers * m_BufferSize);
// Start some buffers.
for (uint i = 0; i < m_nBuffers; i++) {
XAUDIO2_BUFFER buf = {0};
buf.AudioBytes = m_BufferSizeBytes;
buf.pContext = &m_buffer[i * m_BufferSize];
buf.pAudioData = (BYTE *)buf.pContext;
pSourceVoice->SubmitSourceBuffer(&buf);
}
// Start some buffers.
for (uint i = 0; i < m_nBuffers; i++)
{
XAUDIO2_BUFFER buf = {0};
buf.AudioBytes = m_BufferSizeBytes;
buf.pContext = &m_buffer[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()
: BaseStreamingVoice(sizeof(T) / sizeof(s16))
{
}
template <typename T>
class StreamingVoice : public BaseStreamingVoice
{
public:
StreamingVoice()
: BaseStreamingVoice(sizeof(T) / sizeof(s16))
{
}
virtual ~StreamingVoice()
{
IXAudio2SourceVoice *killMe = pSourceVoice;
// XXX: Potentially leads to a race condition that causes a nullptr
// dereference when SubmitSourceBuffer is called in OnBufferEnd?
pSourceVoice = nullptr;
if (killMe != nullptr) {
killMe->FlushSourceBuffers();
killMe->DestroyVoice();
}
virtual ~StreamingVoice()
{
IXAudio2SourceVoice* killMe = pSourceVoice;
// XXX: Potentially leads to a race condition that causes a nullptr
// dereference when SubmitSourceBuffer is called in OnBufferEnd?
pSourceVoice = nullptr;
if (killMe != nullptr)
{
killMe->FlushSourceBuffers();
killMe->DestroyVoice();
}
// XXX: Not sure we even need a critical section - DestroyVoice is
// blocking, and the documentation states no callbacks are called
// or audio data is read after it returns, so it's safe to free up
// resources.
EnterCriticalSection(&cs);
m_buffer = nullptr;
LeaveCriticalSection(&cs);
}
// XXX: Not sure we even need a critical section - DestroyVoice is
// blocking, and the documentation states no callbacks are called
// or audio data is read after it returns, so it's safe to free up
// resources.
EnterCriticalSection(&cs);
m_buffer = nullptr;
LeaveCriticalSection(&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.
// XXX: The pSourceVoice nullptr check seems a bit self-inflicted
// due to the destructor logic.
if (pSourceVoice == nullptr || context == nullptr) {
LeaveCriticalSection(&cs);
return;
}
// All of these checks are necessary because XAudio2 is wonky shizat.
// XXX: The pSourceVoice nullptr check seems a bit self-inflicted
// due to the destructor logic.
if (pSourceVoice == nullptr || context == nullptr)
{
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 = nullptr;
decltype(&XAudio2Create) pXAudio2Create = nullptr;
CComPtr<IXAudio2> pXAudio2;
IXAudio2MasteringVoice *pMasteringVoice = nullptr;
std::unique_ptr<BaseStreamingVoice> m_voiceContext;
HMODULE xAudio2DLL = nullptr;
decltype(&XAudio2Create) pXAudio2Create = nullptr;
CComPtr<IXAudio2> pXAudio2;
IXAudio2MasteringVoice* pMasteringVoice = nullptr;
std::unique_ptr<BaseStreamingVoice> m_voiceContext;
public:
s32 Init()
{
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
s32 Init()
{
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
try {
HRESULT hr;
try
{
HRESULT hr;
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()));
if (FAILED(hr = pXAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)))
throw Exception::XAudio2Error(hr, "Failed to init XAudio2 engine. Error Details:");
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;
// speakers = (numSpeakers + 1) *2; ?
switch (numSpeakers) {
case 0: // Stereo
speakers = 2;
break;
case 1: // Quadrafonic
speakers = 4;
break;
case 2: // Surround 5.1
speakers = 6;
break;
case 3: // Surround 7.1
speakers = 8;
break;
default:
speakers = 2;
}
int speakers;
// speakers = (numSpeakers + 1) *2; ?
switch (numSpeakers)
{
case 0: // Stereo
speakers = 2;
break;
case 1: // Quadrafonic
speakers = 4;
break;
case 2: // Surround 5.1
speakers = 6;
break;
case 3: // Surround 7.1
speakers = 8;
break;
default:
speakers = 2;
}
if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice, speakers, SampleRate)))
throw Exception::XAudio2Error(hr, "Failed creating mastering voice: ");
if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice, speakers, SampleRate)))
throw Exception::XAudio2Error(hr, "Failed creating mastering voice: ");
switch (speakers) {
case 2:
ConLog("* SPU2 > Using normal 2 speaker stereo output.\n");
m_voiceContext = std::make_unique<StreamingVoice<StereoOut16>>();
break;
case 3:
ConLog("* SPU2 > 2.1 speaker expansion enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo21Out16>>();
break;
case 4:
ConLog("* SPU2 > 4 speaker expansion enabled [quadraphenia]\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo40Out16>>();
break;
case 5:
ConLog("* SPU2 > 4.1 speaker expansion enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo41Out16>>();
break;
case 6:
case 7:
switch (dplLevel) {
case 0: // "normal" stereo upmix
ConLog("* SPU2 > 5.1 speaker expansion enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo51Out16>>();
break;
case 1: // basic Dpl decoder without rear stereo balancing
ConLog("* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo51Out16Dpl>>();
break;
case 2: // gigas PLII
ConLog("* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo51Out16DplII>>();
break;
}
break;
default: // anything 8 or more gets the 7.1 treatment!
ConLog("* SPU2 > 7.1 speaker expansion enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo51Out16>>();
break;
}
switch (speakers)
{
case 2:
ConLog("* SPU2 > Using normal 2 speaker stereo output.\n");
m_voiceContext = std::make_unique<StreamingVoice<StereoOut16>>();
break;
case 3:
ConLog("* SPU2 > 2.1 speaker expansion enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo21Out16>>();
break;
case 4:
ConLog("* SPU2 > 4 speaker expansion enabled [quadraphenia]\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo40Out16>>();
break;
case 5:
ConLog("* SPU2 > 4.1 speaker expansion enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo41Out16>>();
break;
case 6:
case 7:
switch (dplLevel)
{
case 0: // "normal" stereo upmix
ConLog("* SPU2 > 5.1 speaker expansion enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo51Out16>>();
break;
case 1: // basic Dpl decoder without rear stereo balancing
ConLog("* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo51Out16Dpl>>();
break;
case 2: // gigas PLII
ConLog("* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo51Out16DplII>>();
break;
}
break;
default: // anything 8 or more gets the 7.1 treatment!
ConLog("* SPU2 > 7.1 speaker expansion enabled.\n");
m_voiceContext = std::make_unique<StreamingVoice<Stereo51Out16>>();
break;
}
m_voiceContext->Init(pXAudio2);
} catch (std::runtime_error &ex) {
SysMessage(ex.what());
Close();
return -1;
}
m_voiceContext->Init(pXAudio2);
}
catch (std::runtime_error& ex)
{
SysMessage(ex.what());
Close();
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:
m_voiceContext = nullptr;
m_voiceContext = nullptr;
if (pMasteringVoice != nullptr)
pMasteringVoice->DestroyVoice();
if (pMasteringVoice != nullptr)
pMasteringVoice->DestroyVoice();
pMasteringVoice = nullptr;
pMasteringVoice = nullptr;
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 (m_voiceContext == nullptr)
return 0;
return m_voiceContext->GetEmptySampleCount();
}
int GetEmptySampleCount()
{
if (m_voiceContext == nullptr)
return 0;
return m_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;
SndOutModule *XAudio2Out = &XA2;
SndOutModule* XAudio2Out = &XA2;

View File

@ -20,75 +20,77 @@
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))
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
int speakerConfig;
@ -129,193 +131,203 @@ public:
}
#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_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_TOP:
case TB_BOTTOM:
wmEvent = (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
case TB_THUMBPOSITION:
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_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_TOP:
case TB_BOTTOM:
wmEvent = (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
case TB_THUMBPOSITION:
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;
}
}
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;
}
s32 Test() const
{
if (waveOutGetNumDevs() == 0)
{
SysMessage("No waveOut Devices Present\n");
return -1;
}
return 0;
}
int GetEmptySampleCount()
{
int result = 0;
for (int i = 0; i < MAX_BUFFER_COUNT; i++) {
result += (whbuffer[i].dwFlags & WHDR_DONE) ? BufferSize : 0;
}
return result;
}
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 *GetIdent() const
{
return L"waveout";
}
const wchar_t* GetIdent() const
{
return L"waveout";
}
const wchar_t *GetLongName() const
{
return L"WaveOut (Laggy)";
}
const wchar_t* GetLongName() const
{
return L"WaveOut (Laggy)";
}
void ReadSettings()
{
}
void ReadSettings()
{
}
void SetApiSettings(wxString api)
{
}
void SetApiSettings(wxString api)
{
}
void WriteSettings() const
{
}
void WriteSettings() const
{
}
} static WO;
SndOutModule *WaveOut = &WO;
SndOutModule* WaveOut = &WO;

View File

@ -18,30 +18,31 @@
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);
}
__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)
{
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)
{
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
@ -49,29 +50,30 @@ void AssignSliderValue(HWND hWnd, int idc, int editbox, int value)
// updating a custom label.
BOOL DoHandleScrollMessage(HWND hwndDisplay, WPARAM wParam, LPARAM lParam)
{
int wmId = LOWORD(wParam);
int wmEvent = HIWORD(wParam);
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;
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;
default:
return FALSE;
}
return TRUE;
}
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,26 +31,26 @@ 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
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)
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)
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)
if ((HWND)lParam == GetDlgItem(hWnd, idc)) \
return DoHandleScrollMessage(GetDlgItem(hWnd, idcDisplay), wParam, lParam)
// *** BEGIN DRIVER-SPECIFIC CONFIGURATION ***
@ -58,26 +58,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

@ -23,14 +23,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;
@ -44,94 +44,100 @@ bool running;
DWORD WINAPI DspUpdateThread(PVOID param);
#endif
s32 DspLoadLibrary(wchar_t *fileName, int modNum)
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)
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()
@ -141,36 +147,39 @@ 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

@ -26,32 +26,32 @@
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)
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
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

@ -2,72 +2,72 @@
// Microsoft Visual C++ generated include file.
// Used by Spu2-X.rc
//
#define IDD_CONFIG 9
#define IDD_DEBUG 105
#define IDD_DSOUND 106
#define IDD_WAVEOUT 109
#define IDB_SPU2X_SMALL 116
#define IDD_CONFIG_SOUNDTOUCH 117
#define IDD_CONFIG_DEBUG 118
#define IDD_PORTAUDIO 119
#define IDC_EFFECTS_DISABLE 1001
#define IDC_DUMPREGS 1003
#define IDC_DUMPMEM 1004
#define IDC_DUMPCORE 1005
#define IDC_LOGWAVE 1006
#define IDC_LOGDMA 1007
#define IDC_LOGREGS 1008
#define IDC_DEBUG 1009
#define IDC_DEBUG_ENABLE 1010
#define IDC_INTERPOLATE 1011
#define IDC_DEALIASFILTER 1012
#define IDC_OUTPUT 1013
#define IDC_BUFFERS_SLIDER 1014
#define IDC_SPEAKERS 1015
#define IDC_SPEAKERS_TEXT 1016
#define IDC_MSGKEY 1020
#define IDC_MSGDMA 1021
#define IDC_MSGADMA 1022
#define IDC_MSGVOICE 1023
#define IDC_MSGSHOW 1024
#define IDC_OUTCONF 1028
#define IDC_DSP_ENABLE 1029
#define IDC_DS_DEVICE 1032
#define IDC_PA_DEVICE 1033
#define IDC_DBG_OVERRUNS 1038
#define IDC_DBG_CACHE 1039
#define IDC_LATENCY_SLIDER 1040
#define IDC_LATENCY_LABEL 1041
#define ICD_LR_CENTER_SLIDER 1042
#define IDC_SEQLEN_SLIDER 1043
#define IDC_SEEKWIN_SLIDER 1044
#define IDC_OVERLAP_SLIDER 1045
#define IDC_MSG_PUBLIC_BUILD 1048
#define IDC_RESET_DEFAULTS 1057
#define IDC_OPEN_CONFIG_SOUNDTOUCH 1058
#define IDC_OPEN_CONFIG_DEBUG 1059
#define IDC_GLOBALFOCUS_DISABLE 1060
#define IDC_GLOBALFOCUS_DISABLE2 1061
#define IDC_USE_HARDWARE 1062
#define IDC_COMBO1 1063
#define IDC_SYNCHMODE 1064
#define IDC_DEBUG_OTHERS 1065
#define IDC_DEBUG_VISUAL 1066
#define IDC_VOLUME_LABEL 1067
#define IDC_VOLUME_SLIDER 1068
#define IDC_MINIMIZE 1069
#define IDC_MANUAL 1070
#define IDC_PA_HOSTAPI 1071
#define IDC_LATENCY 1072
#define IDC_EXCLUSIVE 1073
#define IDD_CONFIG 9
#define IDD_DEBUG 105
#define IDD_DSOUND 106
#define IDD_WAVEOUT 109
#define IDB_SPU2X_SMALL 116
#define IDD_CONFIG_SOUNDTOUCH 117
#define IDD_CONFIG_DEBUG 118
#define IDD_PORTAUDIO 119
#define IDC_EFFECTS_DISABLE 1001
#define IDC_DUMPREGS 1003
#define IDC_DUMPMEM 1004
#define IDC_DUMPCORE 1005
#define IDC_LOGWAVE 1006
#define IDC_LOGDMA 1007
#define IDC_LOGREGS 1008
#define IDC_DEBUG 1009
#define IDC_DEBUG_ENABLE 1010
#define IDC_INTERPOLATE 1011
#define IDC_DEALIASFILTER 1012
#define IDC_OUTPUT 1013
#define IDC_BUFFERS_SLIDER 1014
#define IDC_SPEAKERS 1015
#define IDC_SPEAKERS_TEXT 1016
#define IDC_MSGKEY 1020
#define IDC_MSGDMA 1021
#define IDC_MSGADMA 1022
#define IDC_MSGVOICE 1023
#define IDC_MSGSHOW 1024
#define IDC_OUTCONF 1028
#define IDC_DSP_ENABLE 1029
#define IDC_DS_DEVICE 1032
#define IDC_PA_DEVICE 1033
#define IDC_DBG_OVERRUNS 1038
#define IDC_DBG_CACHE 1039
#define IDC_LATENCY_SLIDER 1040
#define IDC_LATENCY_LABEL 1041
#define ICD_LR_CENTER_SLIDER 1042
#define IDC_SEQLEN_SLIDER 1043
#define IDC_SEEKWIN_SLIDER 1044
#define IDC_OVERLAP_SLIDER 1045
#define IDC_MSG_PUBLIC_BUILD 1048
#define IDC_RESET_DEFAULTS 1057
#define IDC_OPEN_CONFIG_SOUNDTOUCH 1058
#define IDC_OPEN_CONFIG_DEBUG 1059
#define IDC_GLOBALFOCUS_DISABLE 1060
#define IDC_GLOBALFOCUS_DISABLE2 1061
#define IDC_USE_HARDWARE 1062
#define IDC_COMBO1 1063
#define IDC_SYNCHMODE 1064
#define IDC_DEBUG_OTHERS 1065
#define IDC_DEBUG_VISUAL 1066
#define IDC_VOLUME_LABEL 1067
#define IDC_VOLUME_SLIDER 1068
#define IDC_MINIMIZE 1069
#define IDC_MANUAL 1070
#define IDC_PA_HOSTAPI 1071
#define IDC_LATENCY 1072
#define IDC_EXCLUSIVE 1073
// Next default values for new objects
//
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 120
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1074
#define _APS_NEXT_SYMED_VALUE 101
#define _APS_NEXT_RESOURCE_VALUE 120
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1074
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -22,10 +22,10 @@
// 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* 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);
@ -33,164 +33,164 @@ 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() = default;
V_VolumeLR(s32 both)
: Left(both)
, Right(both)
{
}
V_VolumeLR() = default;
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() = default;
V_VolumeSlide(s16 regval, s32 fullvol)
: Reg_VOL(regval)
, Value(fullvol)
, Increment(0)
, Mode(0)
{
}
V_VolumeSlide() = default;
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() = default;
V_VolumeSlideLR(s16 regval, s32 bothval)
: Left(regval, bothval)
, Right(regval, bothval)
{
}
V_VolumeSlideLR() = default;
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 **
@ -198,25 +198,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.
@ -224,310 +224,310 @@ 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 APF1_SIZE;
u32 APF2_SIZE;
u32 APF1_SIZE;
u32 APF2_SIZE;
s16 APF1_VOL;
s16 APF2_VOL;
s16 APF1_VOL;
s16 APF2_VOL;
u32 SAME_L_SRC;
u32 SAME_R_SRC;
u32 DIFF_L_SRC;
u32 DIFF_R_SRC;
u32 SAME_L_DST;
u32 SAME_R_DST;
u32 DIFF_L_DST;
u32 DIFF_R_DST;
u32 SAME_L_SRC;
u32 SAME_R_SRC;
u32 DIFF_L_SRC;
u32 DIFF_R_SRC;
u32 SAME_L_DST;
u32 SAME_R_DST;
u32 DIFF_L_DST;
u32 DIFF_R_DST;
s16 IIR_VOL;
s16 WALL_VOL;
s16 IIR_VOL;
s16 WALL_VOL;
u32 COMB1_L_SRC;
u32 COMB1_R_SRC;
u32 COMB2_L_SRC;
u32 COMB2_R_SRC;
u32 COMB3_L_SRC;
u32 COMB3_R_SRC;
u32 COMB4_L_SRC;
u32 COMB4_R_SRC;
u32 COMB1_L_SRC;
u32 COMB1_R_SRC;
u32 COMB2_L_SRC;
u32 COMB2_R_SRC;
u32 COMB3_L_SRC;
u32 COMB3_R_SRC;
u32 COMB4_L_SRC;
u32 COMB4_R_SRC;
s16 COMB1_VOL;
s16 COMB2_VOL;
s16 COMB3_VOL;
s16 COMB4_VOL;
s16 COMB1_VOL;
s16 COMB2_VOL;
s16 COMB3_VOL;
s16 COMB4_VOL;
u32 APF1_L_DST;
u32 APF1_R_DST;
u32 APF2_L_DST;
u32 APF2_R_DST;
u32 APF1_L_DST;
u32 APF1_R_DST;
u32 APF2_L_DST;
u32 APF2_R_DST;
};
struct V_ReverbBuffers
{
s32 SAME_L_SRC;
s32 SAME_R_SRC;
s32 DIFF_R_SRC;
s32 DIFF_L_SRC;
s32 SAME_L_DST;
s32 SAME_R_DST;
s32 DIFF_L_DST;
s32 DIFF_R_DST;
s32 SAME_L_SRC;
s32 SAME_R_SRC;
s32 DIFF_R_SRC;
s32 DIFF_L_SRC;
s32 SAME_L_DST;
s32 SAME_R_DST;
s32 DIFF_L_DST;
s32 DIFF_R_DST;
s32 COMB1_L_SRC;
s32 COMB1_R_SRC;
s32 COMB2_L_SRC;
s32 COMB2_R_SRC;
s32 COMB3_L_SRC;
s32 COMB3_R_SRC;
s32 COMB4_L_SRC;
s32 COMB4_R_SRC;
s32 COMB1_L_SRC;
s32 COMB1_R_SRC;
s32 COMB2_L_SRC;
s32 COMB2_R_SRC;
s32 COMB3_L_SRC;
s32 COMB3_R_SRC;
s32 COMB4_L_SRC;
s32 COMB4_R_SRC;
s32 APF1_L_DST;
s32 APF1_R_DST;
s32 APF2_L_DST;
s32 APF2_R_DST;
s32 APF1_L_DST;
s32 APF1_R_DST;
s32 APF2_L_DST;
s32 APF2_R_DST;
s32 SAME_L_PRV;
s32 SAME_R_PRV;
s32 DIFF_L_PRV;
s32 DIFF_R_PRV;
s32 SAME_L_PRV;
s32 SAME_R_PRV;
s32 DIFF_L_PRV;
s32 DIFF_R_PRV;
s32 APF1_L_SRC;
s32 APF1_R_SRC;
s32 APF2_L_SRC;
s32 APF2_R_SRC;
s32 APF1_L_SRC;
s32 APF1_R_SRC;
s32 APF2_L_SRC;
s32 APF2_R_SRC;
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;
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
{
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
// Preserves the channel processed last cycle
StereoOut32 LastEffect;
// Preserves the channel processed last cycle
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;
// 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;
s32 EffectsBufferIndexer(s32 offset) const;
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];
@ -540,25 +540,25 @@ extern s16 InputPos;
// SPU Mixing Cycles ("Ticks mixed" counter)
extern u32 Cycles;
extern s16 *spu2regs;
extern s16 *_spu2mem;
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 SPU2Savestate
{
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();
} // namespace SPU2Savestate
// --------------------------------------------------------------------------------------
// ADPCM Decoder Cache
@ -580,8 +580,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

@ -184,10 +184,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)
#define U16P_HI(x) (((u16*)&(x)) + 1)
extern u16 *regtable[0x401];
extern u16 const *const regtable_original[0x401];
extern u16* regtable[0x401];
extern u16 const* const regtable_original[0x401];

View File

@ -67,13 +67,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;
/*
@ -100,8 +100,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

@ -26,7 +26,7 @@
using namespace Threading;
MutexRecursive mtx_SPU2Status;
MutexRecursive mtx_SPU2Status;
bool SPU2_dummy_callback = false;
#include "svnrev.h"
@ -41,7 +41,7 @@ static bool IsInitialized = false;
static u32 pClocks = 0;
u32 *cyclePtr = NULL;
u32* cyclePtr = NULL;
u32 lClocks = 0;
@ -49,7 +49,7 @@ u32 lClocks = 0;
static bool CheckSSE()
{
return true;
return true;
#if 0
if( !cpu_detected )
@ -68,216 +68,225 @@ static bool CheckSSE()
void SPU2configure()
{
if (!CheckSSE())
return;
configure();
if (!CheckSSE())
return;
configure();
}
// --------------------------------------------------------------------------------------
// DMA 4/7 Callbacks from Core Emulator
// --------------------------------------------------------------------------------------
u16 *DMABaseAddr;
u16* DMABaseAddr;
u32 SPU2ReadMemAddr(int core)
{
return Cores[core].MADR;
return Cores[core].MADR;
}
void SPU2WriteMemAddr(int core, u32 value)
{
Cores[core].MADR = value;
Cores[core].MADR = value;
}
void SPU2setDMABaseAddr(uptr baseaddr)
{
DMABaseAddr = (u16 *)baseaddr;
DMABaseAddr = (u16*)baseaddr;
}
void SPU2setSettingsDir(const char *dir)
void SPU2setSettingsDir(const char* dir)
{
CfgSetSettingsDir(dir);
CfgSetSettingsDir(dir);
}
void SPU2setLogDir(const char *dir)
void SPU2setLogDir(const char* dir)
{
CfgSetLogDir(dir);
CfgSetLogDir(dir);
}
void SPU2readDMA4Mem(u16 *pMem, u32 size) // size now in 16bit units
void SPU2readDMA4Mem(u16* pMem, u32 size) // size now in 16bit units
{
if (cyclePtr != NULL)
TimeUpdate(*cyclePtr);
if (cyclePtr != NULL)
TimeUpdate(*cyclePtr);
FileLog("[%10d] SPU2 readDMA4Mem size %x\n", Cycles, size << 1);
Cores[0].DoDMAread(pMem, size);
FileLog("[%10d] SPU2 readDMA4Mem size %x\n", Cycles, size << 1);
Cores[0].DoDMAread(pMem, size);
}
void SPU2writeDMA4Mem(u16 *pMem, u32 size) // size now in 16bit units
void SPU2writeDMA4Mem(u16* pMem, u32 size) // size now in 16bit units
{
if (cyclePtr != NULL)
TimeUpdate(*cyclePtr);
if (cyclePtr != NULL)
TimeUpdate(*cyclePtr);
FileLog("[%10d] SPU2 writeDMA4Mem size %x at address %x\n", Cycles, size << 1, Cores[0].TSA);
FileLog("[%10d] SPU2 writeDMA4Mem size %x at address %x\n", Cycles, size << 1, Cores[0].TSA);
#ifdef S2R_ENABLE
if (!replay_mode)
s2r_writedma4(Cycles, pMem, size);
if (!replay_mode)
s2r_writedma4(Cycles, pMem, size);
#endif
Cores[0].DoDMAwrite(pMem, size);
Cores[0].DoDMAwrite(pMem, size);
}
void SPU2interruptDMA4()
{
FileLog("[%10d] SPU2 interruptDMA4\n", Cycles);
Cores[0].Regs.STATX |= 0x80;
//Cores[0].Regs.ATTR &= ~0x30;
FileLog("[%10d] SPU2 interruptDMA4\n", Cycles);
Cores[0].Regs.STATX |= 0x80;
//Cores[0].Regs.ATTR &= ~0x30;
}
void SPU2interruptDMA7()
{
FileLog("[%10d] SPU2 interruptDMA7\n", Cycles);
Cores[1].Regs.STATX |= 0x80;
//Cores[1].Regs.ATTR &= ~0x30;
FileLog("[%10d] SPU2 interruptDMA7\n", Cycles);
Cores[1].Regs.STATX |= 0x80;
//Cores[1].Regs.ATTR &= ~0x30;
}
void SPU2readDMA7Mem(u16 *pMem, u32 size)
void SPU2readDMA7Mem(u16* pMem, u32 size)
{
if (cyclePtr != NULL)
TimeUpdate(*cyclePtr);
if (cyclePtr != NULL)
TimeUpdate(*cyclePtr);
FileLog("[%10d] SPU2 readDMA7Mem size %x\n", Cycles, size << 1);
Cores[1].DoDMAread(pMem, size);
FileLog("[%10d] SPU2 readDMA7Mem size %x\n", Cycles, size << 1);
Cores[1].DoDMAread(pMem, size);
}
void SPU2writeDMA7Mem(u16 *pMem, u32 size)
void SPU2writeDMA7Mem(u16* pMem, u32 size)
{
if (cyclePtr != NULL)
TimeUpdate(*cyclePtr);
if (cyclePtr != NULL)
TimeUpdate(*cyclePtr);
FileLog("[%10d] SPU2 writeDMA7Mem size %x at address %x\n", Cycles, size << 1, Cores[1].TSA);
FileLog("[%10d] SPU2 writeDMA7Mem size %x at address %x\n", Cycles, size << 1, Cores[1].TSA);
#ifdef S2R_ENABLE
if (!replay_mode)
s2r_writedma7(Cycles, pMem, size);
if (!replay_mode)
s2r_writedma7(Cycles, pMem, size);
#endif
Cores[1].DoDMAwrite(pMem, size);
Cores[1].DoDMAwrite(pMem, size);
}
s32 SPU2reset()
{
if (SndBuffer::Test() == 0 && SampleRate != 48000)
{
SampleRate = 48000;
SndBuffer::Cleanup();
if (SndBuffer::Test() == 0 && SampleRate != 48000)
{
SampleRate = 48000;
SndBuffer::Cleanup();
try {
SndBuffer::Init();
}
catch (std::exception& ex) {
fprintf(stderr, "SPU2-X Error: Could not initialize device, or something.\nReason: %s", ex.what());
SPU2close();
return -1;
}
}
else
SampleRate = 48000;
try
{
SndBuffer::Init();
}
catch (std::exception& ex)
{
fprintf(stderr, "SPU2-X Error: Could not initialize device, or something.\nReason: %s", ex.what());
SPU2close();
return -1;
}
}
else
SampleRate = 48000;
memset(spu2regs, 0, 0x010000);
memset(_spu2mem, 0, 0x200000);
memset(_spu2mem + 0x2800, 7, 0x10); // from BIOS reversal. Locks the voices so they don't run free.
Cores[0].Init(0);
Cores[1].Init(1);
return 0;
memset(spu2regs, 0, 0x010000);
memset(_spu2mem, 0, 0x200000);
memset(_spu2mem + 0x2800, 7, 0x10); // from BIOS reversal. Locks the voices so they don't run free.
Cores[0].Init(0);
Cores[1].Init(1);
return 0;
}
s32 SPU2ps1reset()
{
printf("RESET PS1 \n");
printf("RESET PS1 \n");
if (SndBuffer::Test() == 0 && SampleRate != 44100)
{
SampleRate = 44100;
SndBuffer::Cleanup();
if (SndBuffer::Test() == 0 && SampleRate != 44100)
{
SampleRate = 44100;
SndBuffer::Cleanup();
try {
SndBuffer::Init();
}
catch (std::exception& ex) {
fprintf(stderr, "SPU2-X Error: Could not initialize device, or something.\nReason: %s", ex.what());
SPU2close();
return -1;
}
}
else
SampleRate = 44100;
try
{
SndBuffer::Init();
}
catch (std::exception& ex)
{
fprintf(stderr, "SPU2-X Error: Could not initialize device, or something.\nReason: %s", ex.what());
SPU2close();
return -1;
}
}
else
SampleRate = 44100;
/* memset(spu2regs, 0, 0x010000);
/* memset(spu2regs, 0, 0x010000);
memset(_spu2mem, 0, 0x200000);
memset(_spu2mem + 0x2800, 7, 0x10); // from BIOS reversal. Locks the voices so they don't run free.
Cores[0].Init(0);
Cores[1].Init(1);*/
return 0;
return 0;
}
s32 SPU2init()
{
assert(regtable[0x400] == NULL);
assert(regtable[0x400] == NULL);
if (IsInitialized) {
printf(" * SPU2-X: Already initialized - Ignoring SPU2init signal.");
return 0;
}
if (IsInitialized)
{
printf(" * SPU2-X: Already initialized - Ignoring SPU2init signal.");
return 0;
}
IsInitialized = true;
SPU2_dummy_callback = false;
IsInitialized = true;
SPU2_dummy_callback = false;
ReadSettings();
ReadSettings();
#ifdef SPU2_LOG
if (AccessLog()) {
spu2Log = OpenLog(AccessLogFileName);
setvbuf(spu2Log, NULL, _IONBF, 0);
FileLog("SPU2init\n");
}
if (AccessLog())
{
spu2Log = OpenLog(AccessLogFileName);
setvbuf(spu2Log, NULL, _IONBF, 0);
FileLog("SPU2init\n");
}
#endif
srand((unsigned)time(NULL));
srand((unsigned)time(NULL));
spu2regs = (s16 *)malloc(0x010000);
_spu2mem = (s16 *)malloc(0x200000);
spu2regs = (s16*)malloc(0x010000);
_spu2mem = (s16*)malloc(0x200000);
// adpcm decoder cache:
// the cache data size is determined by taking the number of adpcm blocks
// (2MB / 16) and multiplying it by the decoded block size (28 samples).
// Thus: pcm_cache_data = 7,340,032 bytes (ouch!)
// Expanded: 16 bytes expands to 56 bytes [3.5:1 ratio]
// Resulting in 2MB * 3.5.
// adpcm decoder cache:
// the cache data size is determined by taking the number of adpcm blocks
// (2MB / 16) and multiplying it by the decoded block size (28 samples).
// Thus: pcm_cache_data = 7,340,032 bytes (ouch!)
// Expanded: 16 bytes expands to 56 bytes [3.5:1 ratio]
// Resulting in 2MB * 3.5.
pcm_cache_data = (PcmCacheEntry *)calloc(pcm_BlockCount, sizeof(PcmCacheEntry));
pcm_cache_data = (PcmCacheEntry*)calloc(pcm_BlockCount, sizeof(PcmCacheEntry));
if ((spu2regs == NULL) || (_spu2mem == NULL) || (pcm_cache_data == NULL)) {
SysMessage("SPU2-X: Error allocating Memory\n");
return -1;
}
if ((spu2regs == NULL) || (_spu2mem == NULL) || (pcm_cache_data == NULL))
{
SysMessage("SPU2-X: Error allocating Memory\n");
return -1;
}
// Patch up a copy of regtable that directly maps "NULLs" to SPU2 memory.
// Patch up a copy of regtable that directly maps "NULLs" to SPU2 memory.
memcpy(regtable, regtable_original, sizeof(regtable));
memcpy(regtable, regtable_original, sizeof(regtable));
for (uint mem = 0; mem < 0x800; mem++) {
u16 *ptr = regtable[mem >> 1];
if (!ptr) {
regtable[mem >> 1] = &(spu2Ru16(mem));
}
}
for (uint mem = 0; mem < 0x800; mem++)
{
u16* ptr = regtable[mem >> 1];
if (!ptr)
{
regtable[mem >> 1] = &(spu2Ru16(mem));
}
}
SPU2reset();
SPU2reset();
DMALogOpen();
InitADSR();
DMALogOpen();
InitADSR();
#ifdef S2R_ENABLE
if (!replay_mode)
s2r_open(Cycles, "replay_dump.s2r");
if (!replay_mode)
s2r_open(Cycles, "replay_dump.s2r");
#endif
return 0;
return 0;
}
#ifdef _MSC_VER
@ -287,147 +296,158 @@ extern HWND hDebugDialog;
static INT_PTR CALLBACK DebugProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId;
int wmId;
switch (uMsg) {
case WM_PAINT:
return FALSE;
case WM_INITDIALOG: {
debugDialogOpen = true;
} break;
switch (uMsg)
{
case WM_PAINT:
return FALSE;
case WM_INITDIALOG:
{
debugDialogOpen = true;
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId) {
case IDOK:
case IDCANCEL:
debugDialogOpen = false;
EndDialog(hWnd, 0);
break;
default:
return FALSE;
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDOK:
case IDCANCEL:
debugDialogOpen = false;
EndDialog(hWnd, 0);
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
default:
return FALSE;
}
return TRUE;
}
#endif
uptr gsWindowHandle = 0;
s32 SPU2open(void *pDsp)
s32 SPU2open(void* pDsp)
{
ScopedLock lock( mtx_SPU2Status );
if (IsOpened)
return 0;
ScopedLock lock(mtx_SPU2Status);
if (IsOpened)
return 0;
FileLog("[%10d] SPU2 Open\n", Cycles);
FileLog("[%10d] SPU2 Open\n", Cycles);
if (pDsp != NULL)
gsWindowHandle = *(uptr *)pDsp;
else
gsWindowHandle = 0;
if (pDsp != NULL)
gsWindowHandle = *(uptr*)pDsp;
else
gsWindowHandle = 0;
#ifdef _MSC_VER
#ifdef PCSX2_DEVBUILD // Define may not be needed but not tested yet. Better make sure.
if (IsDevBuild && VisualDebug()) {
if (debugDialogOpen == 0) {
hDebugDialog = CreateDialogParam(hInstance, MAKEINTRESOURCE(IDD_DEBUG), 0, DebugProc, 0);
ShowWindow(hDebugDialog, SW_SHOWNORMAL);
debugDialogOpen = 1;
}
} else if (debugDialogOpen) {
DestroyWindow(hDebugDialog);
debugDialogOpen = 0;
}
if (IsDevBuild && VisualDebug())
{
if (debugDialogOpen == 0)
{
hDebugDialog = CreateDialogParam(hInstance, MAKEINTRESOURCE(IDD_DEBUG), 0, DebugProc, 0);
ShowWindow(hDebugDialog, SW_SHOWNORMAL);
debugDialogOpen = 1;
}
}
else if (debugDialogOpen)
{
DestroyWindow(hDebugDialog);
debugDialogOpen = 0;
}
#endif
#endif
IsOpened = true;
lClocks = (cyclePtr != NULL) ? *cyclePtr : 0;
IsOpened = true;
lClocks = (cyclePtr != NULL) ? *cyclePtr : 0;
try {
SndBuffer::Init();
try
{
SndBuffer::Init();
#ifndef __POSIX__
DspLoadLibrary(dspPlugin, dspPluginModule);
DspLoadLibrary(dspPlugin, dspPluginModule);
#endif
WaveDump::Open();
} catch (std::exception &ex) {
fprintf(stderr, "SPU2-X Error: Could not initialize device, or something.\nReason: %s", ex.what());
SPU2close();
return -1;
}
SPU2setDMABaseAddr((uptr)iopMem->Main);
WaveDump::Open();
}
catch (std::exception& ex)
{
fprintf(stderr, "SPU2-X Error: Could not initialize device, or something.\nReason: %s", ex.what());
SPU2close();
return -1;
}
SPU2setDMABaseAddr((uptr)iopMem->Main);
SPU2setClockPtr(&psxRegs.cycle);
return 0;
return 0;
}
void SPU2close()
{
ScopedLock lock( mtx_SPU2Status );
if (!IsOpened)
return;
IsOpened = false;
ScopedLock lock(mtx_SPU2Status);
if (!IsOpened)
return;
IsOpened = false;
FileLog("[%10d] SPU2 Close\n", Cycles);
FileLog("[%10d] SPU2 Close\n", Cycles);
#ifndef __POSIX__
DspCloseLibrary();
DspCloseLibrary();
#endif
SndBuffer::Cleanup();
SndBuffer::Cleanup();
}
void SPU2shutdown()
{
if (!IsInitialized)
return;
IsInitialized = false;
SPU2_dummy_callback = false;
if (!IsInitialized)
return;
IsInitialized = false;
SPU2_dummy_callback = false;
ConLog("* SPU2-X: Shutting down.\n");
ConLog("* SPU2-X: Shutting down.\n");
SPU2close();
SPU2close();
#ifdef S2R_ENABLE
if (!replay_mode)
s2r_close();
if (!replay_mode)
s2r_close();
#endif
DoFullDump();
DoFullDump();
#ifdef STREAM_DUMP
fclose(il0);
fclose(il1);
fclose(il0);
fclose(il1);
#endif
#ifdef EFFECTS_DUMP
fclose(el0);
fclose(el1);
fclose(el0);
fclose(el1);
#endif
WaveDump::Close();
WaveDump::Close();
DMALogClose();
DMALogClose();
safe_free(spu2regs);
safe_free(_spu2mem);
safe_free(pcm_cache_data);
safe_free(spu2regs);
safe_free(_spu2mem);
safe_free(pcm_cache_data);
#ifdef SPU2_LOG
if (!AccessLog())
return;
FileLog("[%10d] SPU2shutdown\n", Cycles);
if (spu2Log)
fclose(spu2Log);
if (!AccessLog())
return;
FileLog("[%10d] SPU2shutdown\n", Cycles);
if (spu2Log)
fclose(spu2Log);
#endif
}
void SPU2setClockPtr(u32 *ptr)
void SPU2setClockPtr(u32* ptr)
{
cyclePtr = ptr;
cyclePtr = ptr;
}
#ifdef DEBUG_KEYS
@ -437,116 +457,134 @@ static bool lState[6];
void SPU2async(u32 cycles)
{
DspUpdate();
DspUpdate();
if (cyclePtr != NULL) {
TimeUpdate(*cyclePtr);
} else {
pClocks += cycles;
TimeUpdate(pClocks);
}
if (cyclePtr != NULL)
{
TimeUpdate(*cyclePtr);
}
else
{
pClocks += cycles;
TimeUpdate(pClocks);
}
#ifdef DEBUG_KEYS
u32 curTicks = GetTickCount();
if ((curTicks - lastTicks) >= 50) {
int oldI = Interpolation;
bool cState[6];
for (int i = 0; i < 6; i++) {
cState[i] = !!(GetAsyncKeyState(VK_NUMPAD0 + i) & 0x8000);
u32 curTicks = GetTickCount();
if ((curTicks - lastTicks) >= 50)
{
int oldI = Interpolation;
bool cState[6];
for (int i = 0; i < 6; i++)
{
cState[i] = !!(GetAsyncKeyState(VK_NUMPAD0 + i) & 0x8000);
if ((cState[i] && !lState[i]) && i != 5)
Interpolation = i;
if ((cState[i] && !lState[i]) && i != 5)
Interpolation = i;
if ((cState[i] && !lState[i]) && i == 5) {
postprocess_filter_enabled = !postprocess_filter_enabled;
printf("Post process filters %s \n", postprocess_filter_enabled ? "enabled" : "disabled");
}
if ((cState[i] && !lState[i]) && i == 5)
{
postprocess_filter_enabled = !postprocess_filter_enabled;
printf("Post process filters %s \n", postprocess_filter_enabled ? "enabled" : "disabled");
}
lState[i] = cState[i];
}
lState[i] = cState[i];
}
if (Interpolation != oldI) {
printf("Interpolation set to %d", Interpolation);
switch (Interpolation) {
case 0:
printf(" - Nearest.\n");
break;
case 1:
printf(" - Linear.\n");
break;
case 2:
printf(" - Cubic.\n");
break;
case 3:
printf(" - Hermite.\n");
break;
case 4:
printf(" - Catmull-Rom.\n");
break;
default:
printf(" (unknown).\n");
break;
}
}
if (Interpolation != oldI)
{
printf("Interpolation set to %d", Interpolation);
switch (Interpolation)
{
case 0:
printf(" - Nearest.\n");
break;
case 1:
printf(" - Linear.\n");
break;
case 2:
printf(" - Cubic.\n");
break;
case 3:
printf(" - Hermite.\n");
break;
case 4:
printf(" - Catmull-Rom.\n");
break;
default:
printf(" (unknown).\n");
break;
}
}
lastTicks = curTicks;
}
lastTicks = curTicks;
}
#endif
}
u16 SPU2read(u32 rmem)
{
// if(!replay_mode)
// s2r_readreg(Cycles,rmem);
// if(!replay_mode)
// s2r_readreg(Cycles,rmem);
u16 ret = 0xDEAD;
u32 core = 0, mem = rmem & 0xFFFF, omem = mem;
if (mem & 0x400) {
omem ^= 0x400;
core = 1;
}
u16 ret = 0xDEAD;
u32 core = 0, mem = rmem & 0xFFFF, omem = mem;
if (mem & 0x400)
{
omem ^= 0x400;
core = 1;
}
if (omem == 0x1f9001AC) {
ret = Cores[core].DmaRead();
} else {
if (cyclePtr != NULL)
TimeUpdate(*cyclePtr);
if (omem == 0x1f9001AC)
{
ret = Cores[core].DmaRead();
}
else
{
if (cyclePtr != NULL)
TimeUpdate(*cyclePtr);
if (rmem >> 16 == 0x1f80) {
ret = Cores[0].ReadRegPS1(rmem);
} else if (mem >= 0x800) {
ret = spu2Ru16(mem);
ConLog("* SPU2-X: Read from reg>=0x800: %x value %x\n", mem, ret);
} else {
ret = *(regtable[(mem >> 1)]);
//FileLog("[%10d] SPU2 read mem %x (core %d, register %x): %x\n",Cycles, mem, core, (omem & 0x7ff), ret);
SPU2writeLog("read", rmem, ret);
}
}
if (rmem >> 16 == 0x1f80)
{
ret = Cores[0].ReadRegPS1(rmem);
}
else if (mem >= 0x800)
{
ret = spu2Ru16(mem);
ConLog("* SPU2-X: Read from reg>=0x800: %x value %x\n", mem, ret);
}
else
{
ret = *(regtable[(mem >> 1)]);
//FileLog("[%10d] SPU2 read mem %x (core %d, register %x): %x\n",Cycles, mem, core, (omem & 0x7ff), ret);
SPU2writeLog("read", rmem, ret);
}
}
return ret;
return ret;
}
void SPU2write(u32 rmem, u16 value)
{
#ifdef S2R_ENABLE
if (!replay_mode)
s2r_writereg(Cycles, rmem, value);
if (!replay_mode)
s2r_writereg(Cycles, rmem, value);
#endif
// Note: Reverb/Effects are very sensitive to having precise update timings.
// If the SPU2 isn't in in sync with the IOP, samples can end up playing at rather
// incorrect pitches and loop lengths.
// Note: Reverb/Effects are very sensitive to having precise update timings.
// If the SPU2 isn't in in sync with the IOP, samples can end up playing at rather
// incorrect pitches and loop lengths.
if (cyclePtr != NULL)
TimeUpdate(*cyclePtr);
if (cyclePtr != NULL)
TimeUpdate(*cyclePtr);
if (rmem >> 16 == 0x1f80)
Cores[0].WriteRegPS1(rmem, value);
else {
SPU2writeLog("write", rmem, value);
SPU2_FastWrite(rmem, value);
}
if (rmem >> 16 == 0x1f80)
Cores[0].WriteRegPS1(rmem, value);
else
{
SPU2writeLog("write", rmem, value);
SPU2_FastWrite(rmem, value);
}
}
// if start is 1, starts recording spu2 data, else stops
@ -554,80 +592,86 @@ void SPU2write(u32 rmem, u16 value)
// for now, pData is not used
int SPU2setupRecording(int start, std::wstring* filename)
{
if (start == 0)
RecordStop();
else if (start == 1)
RecordStart(filename);
if (start == 0)
RecordStop();
else if (start == 1)
RecordStart(filename);
return 0;
return 0;
}
s32 SPU2freeze(int mode, freezeData *data)
s32 SPU2freeze(int mode, freezeData* data)
{
pxAssume(data != NULL);
if (!data) {
printf("SPU2-X savestate null pointer!\n");
return -1;
}
pxAssume(data != NULL);
if (!data)
{
printf("SPU2-X savestate null pointer!\n");
return -1;
}
if (mode == FREEZE_SIZE) {
data->size = SPU2Savestate::SizeIt();
return 0;
}
if (mode == FREEZE_SIZE)
{
data->size = SPU2Savestate::SizeIt();
return 0;
}
pxAssume(mode == FREEZE_LOAD || mode == FREEZE_SAVE);
pxAssume(mode == FREEZE_LOAD || mode == FREEZE_SAVE);
if (data->data == NULL) {
printf("SPU2-X savestate null pointer!\n");
return -1;
}
if (data->data == NULL)
{
printf("SPU2-X savestate null pointer!\n");
return -1;
}
SPU2Savestate::DataBlock &spud = (SPU2Savestate::DataBlock &)*(data->data);
SPU2Savestate::DataBlock& spud = (SPU2Savestate::DataBlock&)*(data->data);
switch (mode) {
case FREEZE_LOAD:
return SPU2Savestate::ThawIt(spud);
case FREEZE_SAVE:
return SPU2Savestate::FreezeIt(spud);
switch (mode)
{
case FREEZE_LOAD:
return SPU2Savestate::ThawIt(spud);
case FREEZE_SAVE:
return SPU2Savestate::FreezeIt(spud);
jNO_DEFAULT;
}
jNO_DEFAULT;
}
// technically unreachable, but kills a warning:
return 0;
// technically unreachable, but kills a warning:
return 0;
}
void SPU2DoFreezeOut( void* dest )
void SPU2DoFreezeOut(void* dest)
{
ScopedLock lock( mtx_SPU2Status );
ScopedLock lock(mtx_SPU2Status);
freezeData fP = { 0, (s8*)dest };
if (SPU2freeze( FREEZE_SIZE, &fP)!=0) return;
if (!fP.size) return;
freezeData fP = {0, (s8*)dest};
if (SPU2freeze(FREEZE_SIZE, &fP) != 0)
return;
if (!fP.size)
return;
Console.Indent().WriteLn( "Saving SPU-2");
Console.Indent().WriteLn("Saving SPU-2");
if (SPU2freeze(FREEZE_SAVE, &fP)!=0)
throw std::runtime_error(" * SPU-2: Error saving state!\n");
if (SPU2freeze(FREEZE_SAVE, &fP) != 0)
throw std::runtime_error(" * SPU-2: Error saving state!\n");
}
void SPU2DoFreezeIn( pxInputStream& infp )
void SPU2DoFreezeIn(pxInputStream& infp)
{
ScopedLock lock( mtx_SPU2Status );
ScopedLock lock(mtx_SPU2Status);
freezeData fP = { 0, NULL };
if (SPU2freeze( FREEZE_SIZE, &fP )!=0)
freezeData fP = {0, NULL};
if (SPU2freeze(FREEZE_SIZE, &fP) != 0)
fP.size = 0;
Console.Indent().WriteLn( "Loading SPU-2");
Console.Indent().WriteLn("Loading SPU-2");
if (!infp.IsOk() || !infp.Length())
{
// no state data to read, but SPU-2 expects some state data?
// Issue a warning to console...
if( fP.size != 0 )
Console.Indent().Warning( "Warning: No data for SPU-2 found. Status may be unpredictable." );
if (fP.size != 0)
Console.Indent().Warning("Warning: No data for SPU-2 found. Status may be unpredictable.");
return;
@ -637,10 +681,10 @@ void SPU2DoFreezeIn( pxInputStream& infp )
// on the status of the plugin when loading, so let's ignore it.
}
ScopedAlloc<s8> data( fP.size );
ScopedAlloc<s8> data(fP.size);
fP.data = data.GetPtr();
infp.Read( fP.data, fP.size );
if (SPU2freeze(FREEZE_LOAD, &fP)!=0)
throw std::runtime_error(" * SPU-2: Error loading state!\n");
infp.Read(fP.data, fP.size);
if (SPU2freeze(FREEZE_LOAD, &fP) != 0)
throw std::runtime_error(" * SPU-2: Error loading state!\n");
}

View File

@ -19,14 +19,14 @@
#include "Utilities/Threading.h"
#include "SaveState.h"
extern Threading::MutexRecursive mtx_SPU2Status;
extern Threading::MutexRecursive mtx_SPU2Status;
extern bool SPU2_dummy_callback;
s32 SPU2init();
s32 SPU2reset();
s32 SPU2ps1reset();
s32 SPU2open(void *pDsp);
s32 SPU2open(void* pDsp);
void SPU2close();
void SPU2shutdown();
void SPU2write(u32 mem, u16 value);
@ -38,40 +38,40 @@ u16 SPU2read(u32 mem);
// for now, pData is not used
int SPU2setupRecording(int start, std::wstring* filename);
void SPU2setClockPtr(u32 *ptr);
void SPU2setClockPtr(u32* ptr);
void SPU2async(u32 cycles);
s32 SPU2freeze(int mode, freezeData *data);
void SPU2DoFreezeIn( pxInputStream& infp );
void SPU2DoFreezeOut( void* dest );
s32 SPU2freeze(int mode, freezeData* data);
void SPU2DoFreezeIn(pxInputStream& infp);
void SPU2DoFreezeOut(void* dest);
void SPU2configure();
u32 SPU2ReadMemAddr(int core);
void SPU2WriteMemAddr(int core, u32 value);
void SPU2setDMABaseAddr(uptr baseaddr);
void SPU2setSettingsDir(const char *dir);
void SPU2setLogDir(const char *dir);
void SPU2readDMA4Mem(u16 *pMem, u32 size);
void SPU2writeDMA4Mem(u16 *pMem, u32 size);
void SPU2setSettingsDir(const char* dir);
void SPU2setLogDir(const char* dir);
void SPU2readDMA4Mem(u16* pMem, u32 size);
void SPU2writeDMA4Mem(u16* pMem, u32 size);
void SPU2interruptDMA4();
void SPU2interruptDMA7();
void SPU2readDMA7Mem(u16 *pMem, u32 size);
void SPU2writeDMA7Mem(u16 *pMem, u32 size);
void SPU2readDMA7Mem(u16* pMem, u32 size);
void SPU2writeDMA7Mem(u16* pMem, u32 size);
#include "spu2replay.h"
extern u8 callirq;
extern s16 *input_data;
extern s16* input_data;
extern u32 input_data_ptr;
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);

View File

@ -18,128 +18,133 @@
namespace SPU2Savestate
{
// 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 = 0x000e;
// versioning for saves.
// Increment this when changes to the savestate system are made.
static const u32 SAVE_VERSION = 0x000e;
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));
}
} // namespace SPU2Savestate
struct SPU2Savestate::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 SPU2Savestate::FreezeIt(DataBlock &spud)
s32 __fastcall SPU2Savestate::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 components 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 components 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 SPU2Savestate::ThawIt(DataBlock &spud)
s32 __fastcall SPU2Savestate::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 PCSX2.\n");
else
fprintf(stderr, "\tThe savestate you are trying to load is incorrect or corrupted.\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 PCSX2.\n");
else
fprintf(stderr, "\tThe savestate you are trying to load is incorrect or corrupted.\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 components 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 components 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 SPU2Savestate::SizeIt()
{
return sizeof(DataBlock);
return sizeof(DataBlock);
}

View File

@ -20,75 +20,75 @@
#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)
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)
{
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)
{
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);
}
///////////////////////////////////////////////////////////////
@ -112,89 +112,89 @@ 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
}
u64 HighResFrequency()
{
u64 freq;
u64 freq;
#ifdef _WIN32
QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
#else
// TODO
#endif
return freq;
return freq;
}
u64 HighResCounter()
{
u64 time;
u64 time;
#ifdef _WIN32
QueryPerformanceCounter((LARGE_INTEGER *)&time);
QueryPerformanceCounter((LARGE_INTEGER*)&time);
#else
// TODO
#endif
return time;
return time;
}
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 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
@ -202,103 +202,108 @@ BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
EXPORT_C_(void)
s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow)
{
int events = 0;
int events = 0;
Running = true;
Running = true;
#ifdef _WIN32
AllocConsole();
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
AllocConsole();
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
conprintf("Playing %s file on %x...", filename, hwnd);
conprintf("Playing %s file on %x...", filename, hwnd);
#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 */ \
}
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);
TryRead(&CurrentIOPCycle, 4, 1, file);
replay_mode = true;
replay_mode = true;
InitWaitSync(); // Initialize the WaitSync stuff
InitWaitSync(); // Initialize the WaitSync stuff
SPU2init();
SPU2_dummy_callback = true;
SPU2setClockPtr(&CurrentIOPCycle);
SPU2open(&hwnd);
SPU2init();
SPU2_dummy_callback = true;
SPU2setClockPtr(&CurrentIOPCycle);
SPU2open(&hwnd);
CurrentIOPCycle = 0;
CurrentIOPCycle = 0;
SPU2async(0);
SPU2async(0);
while (!feof(file) && Running) {
u32 ccycle = 0;
u32 evid = 0;
u32 sval = 0;
u32 tval = 0;
while (!feof(file) && Running)
{
u32 ccycle = 0;
u32 evid = 0;
u32 sval = 0;
u32 tval = 0;
TryRead(&ccycle, 4, 1, file);
TryRead(&sval, 4, 1, file);
TryRead(&ccycle, 4, 1, file);
TryRead(&sval, 4, 1, file);
evid = sval >> 29;
sval &= 0x1FFFFFFF;
evid = sval >> 29;
sval &= 0x1FFFFFFF;
u32 TargetCycle = ccycle * 768;
u32 TargetCycle = ccycle * 768;
while (TargetCycle > CurrentIOPCycle) {
u32 delta = WaitSync(TargetCycle);
SPU2async(delta);
}
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++;
}
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

View File

@ -18,11 +18,11 @@
//#define S2R_ENABLE
// s2r dumping
int s2r_open(u32 ticks, char *filename);
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_writedma4(u32 ticks, u16* data, u32 len);
void s2r_writedma7(u32 ticks, u16* data, u32 len);
void s2r_close();
extern bool replay_mode;

File diff suppressed because it is too large Load Diff

View File

@ -116,11 +116,11 @@ SyncTab::SyncTab(wxWindow* parent)
auto* adv_box = new wxStaticBoxSizer(wxVERTICAL, this, "Advanced");
auto* babble_label = new wxStaticText(this, wxID_ANY, \
"For fine-tuning time stretching.\n"\
"Larger is better for slowdown, && smaller for speedup (60+ fps).\n"\
"All options in microseconds.",\
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL);
auto* babble_label = new wxStaticText(this, wxID_ANY,
"For fine-tuning time stretching.\n"
"Larger is better for slowdown, && smaller for speedup (60+ fps).\n"
"All options in microseconds.",
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL);
babble_label->Wrap(300);
adv_box->Add(babble_label, wxSizerFlags().Centre());