SPU2Ghz: Lots of changes as described in issue 31, thanks again to Jake.Stine.

git-svn-id: http://pcsx2-playground.googlecode.com/svn/trunk@244 a6443dda-0b58-4228-96e9-037be469359c
This commit is contained in:
ramapcsx2 2008-10-28 11:17:17 +00:00 committed by Gregory Hainaut
parent eaf15db0fe
commit 0e1f871606
15 changed files with 1329 additions and 938 deletions

View File

@ -52,51 +52,57 @@ END
// Dialog
//
IDD_CONFIG DIALOGEX 3, 1, 414, 217
IDD_CONFIG DIALOGEX 3, 1, 410, 237
STYLE DS_SETFONT | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "SPU2ghz Settings"
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
PUSHBUTTON "OK",IDOK,300,198,54,15,NOT WS_TABSTOP
PUSHBUTTON "Cancel",IDCANCEL,354,198,54,15,NOT WS_TABSTOP
GROUPBOX "Effects (Reverb) Settings",IDC_STATIC,6,156,119,30
CHECKBOX "Enable Effect Processing",IDC_EFFECTS,12,168,95,10,NOT WS_TABSTOP
GROUPBOX "Output Settings",IDC_STATIC,132,6,119,103
LTEXT "Buffer Size",IDC_STATIC,138,35,35,8,NOT WS_GROUP
LTEXT "Sample Rate",IDC_STATIC,139,19,42,8,NOT WS_GROUP
GROUPBOX "Mixing Settings",IDC_STATIC,6,6,119,80
LTEXT "Interpolation:",IDC_STATIC,11,58,42,8,NOT WS_GROUP
GROUPBOX "",IDC_STATIC,264,18,135,61
GROUPBOX "Dumps (on close)",IDC_STATIC,264,131,135,51
CHECKBOX "Dump Register Data",IDC_DUMPREGS,270,169,80,10,NOT WS_TABSTOP
CHECKBOX "Dump Memory Contents",IDC_DUMPMEM,270,156,91,10,NOT WS_TABSTOP
CHECKBOX "Dump Core and Voice State",IDC_DUMPCORE,270,145,104,10,NOT WS_TABSTOP
GROUPBOX "Logging",IDC_STATIC,263,80,136,50
CHECKBOX "Log Audio Output",IDC_LOGWAVE,269,116,71,10,NOT WS_TABSTOP
CHECKBOX "Log DMA Writes",IDC_LOGDMA,269,104,68,10,NOT WS_TABSTOP
CHECKBOX "Log Register/DMA Actions",IDC_LOGREGS,269,92,101,10,NOT WS_TABSTOP
CHECKBOX "KeyOn/Off Events",IDC_MSGKEY,276,30,74,10,NOT WS_TABSTOP
COMBOBOX IDC_INTERPOLATE,12,66,108,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_SRATE,192,18,54,201,CBS_DROPDOWN | WS_DISABLED | WS_TABSTOP,WS_EX_RIGHT
CONTROL "Slider2",IDC_BUFFER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,138,42,65,10
EDITTEXT IDC_BSIZE,204,42,42,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
LTEXT "Output Module:",IDC_STATIC,12,16,50,8,NOT WS_GROUP
COMBOBOX IDC_OUTPUT,12,24,108,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Number of Buffers:",IDC_STATIC,139,62,60,8
EDITTEXT IDC_BCOUNT,204,60,42,12,ES_RIGHT | ES_AUTOHSCROLL
GROUPBOX "",IDC_STATIC,258,6,150,180
CHECKBOX "Enable Debug Options",IDC_DEBUG,264,6,87,10,NOT WS_TABSTOP
CONTROL "DMA Operations",IDC_MSGDMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,54,68,10
CONTROL "AutoDMA Operations",IDC_MSGADMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,282,66,83,10
CONTROL "Voice Stop Events",IDC_MSGVOICE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,42,75,10
CONTROL "Show In Console",IDC_MSGSHOW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,270,18,69,10
LTEXT "Size = 1024, Numbers = 10",IDC_STATIC,137,94,108,12
PUSHBUTTON "Configure...",IDC_OUTCONF,72,42,48,12
LTEXT "WARNING: The effects processing is experimental and _could_ hurt your ears .\n If that happens, tell me about what game, so I can fix it!",IDC_STATIC,20,191,255,21
GROUPBOX "DSP",IDC_STATIC,6,87,119,68
CONTROL "Enable Winamp DSP plugin",IDC_DSP_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,100,103,10
LTEXT "(configure in the .ini)",IDC_STATIC,43,110,64,8
LTEXT "Recommended:",IDC_STATIC,137,80,108,9
PUSHBUTTON "OK",IDOK,291,219,54,15,NOT WS_TABSTOP
PUSHBUTTON "Cancel",IDCANCEL,351,219,54,15,NOT WS_TABSTOP
GROUPBOX "Mixing Settings",IDC_STATIC,6,6,119,116
GROUPBOX "Speed Limiter (obsolete)",IDC_STATIC,6,127,120,98
GROUPBOX "Output Settings",IDC_STATIC,132,6,119,182
GROUPBOX "",IDC_DEBUG_GROUP,257,7,148,208
GROUPBOX "",IDC_STATIC,264,19,135,85
GROUPBOX "Logging",IDC_STATIC,264,107,136,50
GROUPBOX "Dumps (on close)",IDC_STATIC,264,160,135,49
COMBOBOX IDC_OUTPUT,138,27,108,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Configure...",IDC_OUTCONF,198,42,48,12
COMBOBOX IDC_INTERPOLATE,12,28,108,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "Enable at start-up",IDC_SPEEDLIMIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,176,106,12
COMBOBOX IDC_SRATE,188,62,58,201,CBS_DROPDOWN | WS_DISABLED | WS_TABSTOP,WS_EX_RIGHT
CONTROL "Slider2",IDC_LATENCY_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,177,94,72,10
CONTROL "Use Time-stretching",IDC_TS_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,138,114,79,11
CONTROL "Use a Winamp DSP plugin",IDC_DSP_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,138,160,103,11
CHECKBOX "Enable Debug Options",IDC_DEBUG,264,7,87,10,NOT WS_TABSTOP
CONTROL "Show In Console",IDC_MSGSHOW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,270,19,69,10
CHECKBOX "KeyOn/Off Events",IDC_MSGKEY,276,31,74,10,NOT WS_TABSTOP
CONTROL "Voice Stop Events",IDC_MSGVOICE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,43,75,10
CONTROL "DMA Operations",IDC_MSGDMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,55,68,10
CONTROL "AutoDMA Operations",IDC_MSGADMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,283,67,83,10
CONTROL "Buffer Over/Underruns",IDC_DBG_OVERRUNS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,79,97,11
CONTROL "ADPCM Cache Statistics",IDC_DBG_CACHE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,91,114,9
CHECKBOX "Dump Core and Voice State",IDC_DUMPCORE,270,172,104,10,NOT WS_TABSTOP
CHECKBOX "Dump Memory Contents",IDC_DUMPMEM,270,184,91,10,NOT WS_TABSTOP
CHECKBOX "Dump Register Data",IDC_DUMPREGS,270,196,80,10,NOT WS_TABSTOP
CHECKBOX "Enable Effects Processing",IDC_EFFECTS,12,49,99,10,NOT WS_TABSTOP
LTEXT "Latency:",IDC_STATIC,138,89,33,8,NOT WS_GROUP
LTEXT "Sample Rate:",IDC_STATIC,137,63,44,8,NOT WS_GROUP
LTEXT "Interpolation:",IDC_STATIC,12,18,42,10,NOT WS_GROUP
LTEXT "Module:",IDC_STATIC,138,17,50,9,NOT WS_GROUP
LTEXT "Experimental: Enabling this could break sound badly.",IDC_STATIC,24,61,96,17
LTEXT "(configure in the .ini)",IDC_STATIC,150,172,64,8
LTEXT "Uses the SPU2 to limit framerate for games that cause buffer overruns. Use Timestretching instead.",IDC_STATIC,11,138,109,34
CTEXT "100 ms (avg)",IDC_LATENCY_LABEL,185,84,58,10
LTEXT "Helps reduce latency and usually eliminates audio skips. Uses a little extra CPU.",IDC_STATIC,150,127,96,25
CHECKBOX "Log Register/DMA Actions",IDC_LOGREGS,269,119,101,10,WS_GROUP | NOT WS_TABSTOP
CHECKBOX "Log DMA Writes",IDC_LOGDMA,269,131,68,10,NOT WS_TABSTOP
CHECKBOX "Log Audio Output",IDC_LOGWAVE,269,143,71,10,NOT WS_TABSTOP
CONTROL "Enable runtime toggle",IDC_SPEEDLIMIT_RUNTIME_TOGGLE,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,190,110,10
LTEXT "Allows speed limiter to be toggled with the minus (-) key.",IDC_STATIC,23,202,95,17
CONTROL "Volume Boost",IDC_VOLBOOST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,86,85,11
LTEXT "Can break sound in games that are already loud.",IDC_STATIC,24,99,96,17
END
IDD_DEBUG DIALOGEX 0, 0, 326, 525
@ -107,49 +113,58 @@ BEGIN
DEFPUSHBUTTON "Close",IDOK,269,504,50,14
END
IDD_DSOUND DIALOGEX 0, 0, 186, 58
IDD_DSOUND DIALOGEX 0, 0, 170, 122
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "DirectSound Output Module Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,75,37,50,14
PUSHBUTTON "Cancel",IDCANCEL,129,37,50,14
COMBOBOX IDC_DS_DEVICE,7,17,172,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "DirectSound Device",IDC_STATIC,7,7,63,8
DEFPUSHBUTTON "OK",IDOK,52,104,50,14
PUSHBUTTON "Cancel",IDCANCEL,115,104,50,14
COMBOBOX IDC_DS_DEVICE,4,15,161,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "DirectSound Device",IDC_STATIC,4,3,63,8
LTEXT "Number of Buffers",IDC_STATIC,4,40,61,11
CONTROL "",IDC_BUFFERS_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,71,48,94,10
LTEXT "Use extra buffers if you are experiencing loopy or studdery audio even when games run at high FPS.",IDC_STATIC,8,66,151,27
CTEXT "8 (80 ms latency)",IDC_LATENCY_LABEL,70,37,95,11
END
IDD_DSOUND51 DIALOGEX 0, 0, 265, 182
IDD_DSOUND51 DIALOGEX 0, 0, 336, 180
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "DirectSound 5.1 Output Module Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,154,161,50,14
PUSHBUTTON "Cancel",IDCANCEL,208,161,50,14
COMBOBOX IDC_DS_DEVICE,7,17,251,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "DirectSound Device",IDC_STATIC,7,7,63,8
CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,18,54,30,36
CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,60,56,30,34
CONTROL "",IDC_SLIDER3,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,102,56,30,34
GROUPBOX "Surround Volume Correction",IDC_STATIC,7,36,142,139
CTEXT "Center",IDC_STATIC,54,48,42,8
CTEXT "Left",IDC_STATIC,12,48,42,8
CTEXT "Right",IDC_STATIC,96,48,42,8
CONTROL "",IDC_SLIDER4,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,18,116,30,40
CONTROL "",IDC_SLIDER5,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,60,116,30,40
CONTROL "",IDC_SLIDER6,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,102,116,30,40
CTEXT "LFE (sub)",IDC_STATIC,54,108,42,8
CTEXT "Rear Left",IDC_STATIC,12,108,42,8
CTEXT "Rear Right",IDC_STATIC,96,108,42,8
GROUPBOX "Other Tweaks",IDC_STATIC,155,36,103,120
CONTROL "",IDC_SLIDER7,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,168,56,30,49
CTEXT "Center in LR",IDC_STATIC,162,48,42,8
EDITTEXT IDC_EDIT1,18,90,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT2,60,90,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT3,102,90,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT4,18,156,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT5,60,156,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT6,102,156,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT7,168,108,30,14,ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",IDOK,228,161,50,14
PUSHBUTTON "Cancel",IDCANCEL,281,161,50,14
COMBOBOX IDC_DS_DEVICE,5,17,142,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "DirectSound Device",IDC_STATIC,5,5,63,8
CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,15,53,30,36
CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,57,54,30,34
CONTROL "",IDC_SLIDER3,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,99,54,30,34
GROUPBOX "Surround Volume Correction",IDC_STATIC,5,35,138,139
CTEXT "Center",IDC_STATIC,51,46,42,8
CTEXT "Left",IDC_STATIC,9,46,42,8
CTEXT "Right",IDC_STATIC,93,46,42,8
CONTROL "",IDC_SLIDER4,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,15,115,30,40
CONTROL "",IDC_SLIDER5,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,57,115,30,40
CONTROL "",IDC_SLIDER6,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,99,115,30,40
CTEXT "LFE (sub)",IDC_STATIC,51,107,42,8
CTEXT "Rear Left",IDC_STATIC,9,107,42,8
CTEXT "Rear Right",IDC_STATIC,93,107,42,8
GROUPBOX "Other Tweaks",IDC_STATIC,153,77,63,97
CONTROL "",IDC_SLIDER7,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,169,98,30,49
CTEXT "Center in LR",IDC_STATIC,163,90,42,8
EDITTEXT IDC_EDIT1,15,88,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT2,57,88,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT3,99,88,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT4,15,155,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT5,57,155,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT6,99,155,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT7,169,150,30,14,ES_AUTOHSCROLL
LTEXT "Number of Buffers",IDC_STATIC,160,32,61,11
CONTROL "",IDC_BUFFERS_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,229,40,94,10
LTEXT "Use extra buffers if you are experiencing loopy or studdery audio even when games run at high FPS.",IDC_STATIC,226,69,102,46
CTEXT "8 (80 ms latency)",IDC_LATENCY_LABEL2,227,29,95,11
GROUPBOX "Latency",IDC_STATIC,154,13,174,48
END
IDD_ASIO DIALOGEX 0, 0, 186, 58
@ -163,15 +178,19 @@ BEGIN
LTEXT "ASIO Driver",IDC_STATIC,7,7,39,8
END
IDD_WAVEOUT DIALOGEX 0, 0, 186, 58
IDD_WAVEOUT DIALOGEX 0, 0, 170, 122
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "waveOut Output Module Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,75,37,50,14
PUSHBUTTON "Cancel",IDCANCEL,129,37,50,14
COMBOBOX IDC_DS_DEVICE,7,17,172,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "waveOut Device",IDC_STATIC,7,7,54,8
DEFPUSHBUTTON "OK",IDOK,52,104,50,14
PUSHBUTTON "Cancel",IDCANCEL,115,104,50,14
COMBOBOX IDC_DS_DEVICE,4,15,161,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "waveOut Device",IDC_STATIC,4,3,54,8
LTEXT "Number of Buffers",IDC_STATIC,4,39,61,11
CONTROL "",IDC_BUFFERS_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,71,48,94,10
LTEXT "Use extra buffers if you are experiencing loopy or studdery audio even when games run at high FPS.",IDC_STATIC,8,66,151,27
CTEXT "8 (80 ms latency)",IDC_LATENCY_LABEL,70,37,95,11
END
@ -186,9 +205,8 @@ BEGIN
IDD_CONFIG, DIALOG
BEGIN
LEFTMARGIN, 6
RIGHTMARGIN, 408
TOPMARGIN, 5
BOTTOMMARGIN, 212
RIGHTMARGIN, 405
BOTTOMMARGIN, 234
END
IDD_DEBUG, DIALOG
@ -201,17 +219,17 @@ BEGIN
IDD_DSOUND, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 51
LEFTMARGIN, 4
RIGHTMARGIN, 165
TOPMARGIN, 3
BOTTOMMARGIN, 118
END
IDD_DSOUND51, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 258
TOPMARGIN, 7
LEFTMARGIN, 5
RIGHTMARGIN, 331
TOPMARGIN, 5
BOTTOMMARGIN, 175
END
@ -225,10 +243,10 @@ BEGIN
IDD_WAVEOUT, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 51
LEFTMARGIN, 4
RIGHTMARGIN, 165
TOPMARGIN, 3
BOTTOMMARGIN, 118
END
END
#endif // APSTUDIO_INVOKED

View File

@ -36,8 +36,9 @@ private:
#ifndef __WIN64__
#define BufferSize (CurBufferSize<<1)
#define BufferSizeBytes (BufferSize<<2)
// [Air] : This needs fixed.
static const int BufferSize = SndOutPacketSize;
static const int BufferSizeBytes = BufferSize << 2;
s32* asio_lbuffer;
@ -175,7 +176,7 @@ private:
#define DBL(t) ((t*)(asioDriverInfo.bufferInfos[0].buffers[index]))
#define DBR(t) ((t*)(asioDriverInfo.bufferInfos[1].buffers[index]))
int BLen=BufferSize*CurBufferCount;
int BLen=BufferSize*Config_Asio.NumBuffers;
int ssize=2;
if(showBufferInfo)
@ -241,7 +242,11 @@ private:
bufferInfoReady=true;
}
buff->ReadSamples(asio_lbuffer,buffSize<<1);
// [Air] : Dunno if this is right...
// Maybe there shouldn't be 2 packets? (doesn't make sense for low
// latency drivers, but then again using ASIO at all doesn't make sense).
buff->ReadSamples(asio_lbuffer);
buff->ReadSamples(&asio_lbuffer[SndOutPacketSize]);
s32 asio_read_num = 0;
// perform the processing
@ -586,7 +591,7 @@ public:
for(int i=0;i<driverMax;i++)
{
ConLog(" *** %u - %s\n",i+1,driverNames[i]);
if(stricmp(driverNames[i],AsioDriver)==0)
if(_stricmp(driverNames[i],AsioDriver)==0)
{
selected=i+1;
break;
@ -670,9 +675,9 @@ public:
{
}
virtual bool Is51Out() { return false; }
virtual bool Is51Out() const { return false; }
s32 Test()
s32 Test() const
{
#ifndef __WIN64__
if(asioDrivers->asioGetNumDev()>0)
@ -680,6 +685,22 @@ public:
#endif
return -1;
}
int GetEmptySampleCount() const
{
return 0;
}
const char* GetIdent() const
{
return "asio";
}
const char* GetLongName() const
{
return "ASIO (BROKEN)";
}
} ASIOMod;
SndOutModule *ASIOOut=&ASIOMod;

View File

@ -20,22 +20,31 @@
#include "dialogs.h"
// Config Vars
static bool VolumeBoostEnabled = false;
static int VolumeShiftModifier = 0;
// DEBUG
bool DebugEnabled=false;
bool MsgToConsole=false;
bool MsgKeyOnOff=false;
bool MsgVoiceOff=false;
bool MsgDMA=false;
bool MsgAutoDMA=false;
bool _MsgToConsole=false;
bool _MsgKeyOnOff=false;
bool _MsgVoiceOff=false;
bool _MsgDMA=false;
bool _MsgAutoDMA=false;
bool _MsgOverruns=false;
bool _MsgCache=false;
bool _AccessLog=false;
bool _DMALog=false;
bool _WaveLog=false;
bool _CoresDump=false;
bool _MemDump=false;
bool _RegDump=false;
bool AccessLog=false;
bool DMALog=false;
bool WaveLog=false;
bool CoresDump=false;
bool MemDump=false;
bool RegDump=false;
char AccessLogFileName[255];
char WaveLogFileName[255];
@ -59,19 +68,20 @@ int Interpolation=1;
2. cubic interpolation
*/
// EFFECTS
bool EffectsEnabled=false;
// OUTPUT
int SampleRate=48000;
int CurBufferSize=1024;
int MaxBufferCount=8;
int CurBufferCount=MaxBufferCount;
int SndOutLatencyMS=60;
//int SndOutLatency=1024;
//int MaxBufferCount=8;
//int CurBufferCount=MaxBufferCount;
bool timeStretchEnabled=false;
int OutputModule=OUTPUT_DSOUND;
u32 OutputModule=0; //OUTPUT_DSOUND;
int VolumeMultiplier=1;
int VolumeDivisor=1;
//int VolumeMultiplier=1;
//int VolumeDivisor=1;
int LimitMode=0;
/* values:
@ -80,17 +90,14 @@ int LimitMode=0;
2. Hard limiter -- more cpu-intensive while limiting, but should give better (constant) speeds
*/
u32 GainL =256;
u32 GainR =256;
u32 GainSL =200;
u32 GainSR =200;
u32 GainC =200;
u32 GainLFE=256;
u32 AddCLR = 56;
u32 LowpassLFE=80;
CONFIG_DSOUNDOUT Config_DSoundOut;
CONFIG_DSOUND51 Config_DSound51;
CONFIG_WAVEOUT Config_WaveOut;
CONFIG_ASIO Config_Asio;
// MISC
bool LimiterToggleEnabled=true;
bool LimiterToggleEnabled=false;
int LimiterToggle=VK_SUBTRACT;
// DSP
@ -98,19 +105,15 @@ bool dspPluginEnabled=false;
char dspPlugin[256];
int dspPluginModule=0;
bool timeStretchEnabled=false;
// OUTPUT MODULES
char AsioDriver[129]="";
/// module-specific settings
char DSoundDevice[255];
//////
char CfgFile[]="inis\\SPU2Ghz.ini";
const char NewCfgFile[]="inis\\SPU2Ghz-v2.ini";
const char LegacyCfgFile[]="inis\\SPU2Ghz.ini";
const char* CfgFile=NewCfgFile;
/*| Config File Format: |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*\
@ -128,26 +131,26 @@ char CfgFile[]="inis\\SPU2Ghz.ini";
\*_____________________________________________*/
void CfgWriteBool(char *Section, char*Name, bool Value) {
void CfgWriteBool(const char *Section, const char*Name, bool Value) {
char *Data=Value?"TRUE":"FALSE";
WritePrivateProfileString(Section,Name,Data,CfgFile);
}
void CfgWriteInt(char *Section, char*Name, int Value) {
void CfgWriteInt(const char *Section, const char*Name, int Value) {
char Data[255];
_itoa(Value,Data,10);
WritePrivateProfileString(Section,Name,Data,CfgFile);
}
void CfgWriteStr(char *Section, char*Name,char *Data) {
void CfgWriteStr(const char *Section, const char* Name, const char *Data) {
WritePrivateProfileString(Section,Name,Data,CfgFile);
}
/*****************************************************************************/
bool CfgReadBool(char *Section,char *Name,bool Default) {
bool CfgReadBool(const char *Section,const char *Name,bool Default) {
char Data[255]="";
GetPrivateProfileString(Section,Name,"",Data,255,CfgFile);
Data[254]=0;
@ -164,7 +167,8 @@ bool CfgReadBool(char *Section,char *Name,bool Default) {
return false;
}
int CfgReadInt(char *Section, char*Name,int Default) {
int CfgReadInt(const char *Section, const char*Name,int Default) {
char Data[255]="";
GetPrivateProfileString(Section,Name,"",Data,255,CfgFile);
Data[254]=0;
@ -177,7 +181,8 @@ int CfgReadInt(char *Section, char*Name,int Default) {
return atoi(Data);
}
void CfgReadStr(char *Section, char*Name,char *Data,int DataSize,char *Default) {
void CfgReadStr(const char *Section, const char* Name, char *Data, int DataSize, const char *Default) {
int sl;
GetPrivateProfileString(Section,Name,"",Data,DataSize,CfgFile);
@ -188,24 +193,38 @@ void CfgReadStr(char *Section, char*Name,char *Data,int DataSize,char *Default)
}
}
// Tries to read the requested value.
// Returns FALSE if the value isn't found.
bool CfgFindName( const char *Section, const char* Name)
{
// Only load 24 characters. No need to load more.
char Data[24]="";
GetPrivateProfileString(Section,Name,"",Data,24,CfgFile);
Data[23]=0;
if(strlen(Data)==0) return false;
return true;
}
/*****************************************************************************/
void ReadSettings()
{
DebugEnabled=CfgReadBool("DEBUG","Global_Debug_Enabled",0);
MsgToConsole=DebugEnabled&CfgReadBool("DEBUG","Show_Messages",0);
MsgKeyOnOff =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_Key_On_Off",0);
MsgVoiceOff =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_Voice_Off",0);
MsgDMA =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_DMA_Transfer",0);
MsgAutoDMA =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_AutoDMA",0);
AccessLog =DebugEnabled&CfgReadBool("DEBUG","Log_Register_Access",0);
DMALog =DebugEnabled&CfgReadBool("DEBUG","Log_DMA_Transfers",0);
WaveLog =DebugEnabled&CfgReadBool("DEBUG","Log_WAVE_Output",0);
_MsgToConsole=CfgReadBool("DEBUG","Show_Messages",0);
_MsgKeyOnOff =CfgReadBool("DEBUG","Show_Messages_Key_On_Off",0);
_MsgVoiceOff =CfgReadBool("DEBUG","Show_Messages_Voice_Off",0);
_MsgDMA =CfgReadBool("DEBUG","Show_Messages_DMA_Transfer",0);
_MsgAutoDMA =CfgReadBool("DEBUG","Show_Messages_AutoDMA",0);
_MsgOverruns =CfgReadBool("DEBUG","Show_Messages_Overruns",0);
_MsgCache =CfgReadBool("DEBUG","Show_Messages_CacheStats",0);
CoresDump =DebugEnabled&CfgReadBool("DEBUG","Dump_Info",0);
MemDump =DebugEnabled&CfgReadBool("DEBUG","Dump_Memory",0);
RegDump =DebugEnabled&CfgReadBool("DEBUG","Dump_Regs",0);
_AccessLog =CfgReadBool("DEBUG","Log_Register_Access",0);
_DMALog =CfgReadBool("DEBUG","Log_DMA_Transfers",0);
_WaveLog =CfgReadBool("DEBUG","Log_WAVE_Output",0);
_CoresDump =CfgReadBool("DEBUG","Dump_Info",0);
_MemDump =CfgReadBool("DEBUG","Dump_Memory",0);
_RegDump =CfgReadBool("DEBUG","Dump_Regs",0);
CfgReadStr("DEBUG","Access_Log_Filename",AccessLogFileName,255,"logs\\SPU2Log.txt");
CfgReadStr("DEBUG","WaveLog_Filename", WaveLogFileName, 255,"logs\\SPU2log.wav");
@ -218,55 +237,82 @@ void ReadSettings()
WaveDumpFormat=CfgReadInt("DEBUG","Wave_Log_Format",0);
Interpolation=CfgReadInt("MIXING","Interpolation",1);
AutoDMAPlayRate[0]=CfgReadInt("MIXING","AutoDMA_Play_Rate_0",0);
AutoDMAPlayRate[1]=CfgReadInt("MIXING","AutoDMA_Play_Rate_1",0);
EffectsEnabled=CfgReadBool("EFFECTS","Enable_Effects",0);
Interpolation=CfgReadInt("MIXING","Interpolation",1);
// Moved Timestretch from DSP to Output
timeStretchEnabled = CfgReadBool(
CfgFindName( "OUTPUT", "Timestretch_Enable" ) ? "OUTPUT" : "DSP",
"Timestretch_Enable", true
);
// Moved Effects_Enable from Effects to Mixing
EffectsEnabled = CfgReadBool(
CfgFindName( "MIXING", "Enable_Effects" ) ? "MIXING" : "EFFECTS",
"Enable_Effects", false
);
SampleRate=CfgReadInt("OUTPUT","Sample_Rate",48000);
SndOutLatencyMS=CfgReadInt("OUTPUT","Latency",120);
CurBufferSize=CfgReadInt("OUTPUT","Buffer_Size",1024);
MaxBufferCount=CfgReadInt("OUTPUT","Buffer_Count",10);
if(MaxBufferCount<3) MaxBufferCount=3;
CurBufferCount=MaxBufferCount;
//OutputModule = CfgReadInt("OUTPUT","Output_Module", OUTPUT_DSOUND );
char omodid[128];
CfgReadStr( "OUTPUT", "Output_Module", omodid, 127, DSoundOut->GetIdent() );
OutputModule=CfgReadInt("OUTPUT","Output_Module",OUTPUT_DSOUND);
VolumeMultiplier=CfgReadInt("OUTPUT","Volume_Multiplier",1);
VolumeDivisor =CfgReadInt("OUTPUT","Volume_Divisor",1);
GainL =CfgReadInt("OUTPUT","Channel_Gain_L", 256);
GainR =CfgReadInt("OUTPUT","Channel_Gain_R", 256);
GainC =CfgReadInt("OUTPUT","Channel_Gain_C", 256);
GainLFE=CfgReadInt("OUTPUT","Channel_Gain_LFE",256);
GainSL =CfgReadInt("OUTPUT","Channel_Gain_SL", 200);
GainSR =CfgReadInt("OUTPUT","Channel_Gain_SR", 200);
AddCLR =CfgReadInt("OUTPUT","Channel_Center_In_LR", 56);
LowpassLFE = CfgReadInt("OUTPUT","LFE_Lowpass_Frequency", 80);
// find the driver index of this module:
OutputModule = FindOutputModuleById( omodid );
VolumeShiftModifier = CfgReadInt( "OUTPUT","Volume_Shift", 0 );
LimitMode=CfgReadInt("OUTPUT","Speed_Limit_Mode",0);
CfgReadStr("OUTPUT","Asio_Driver_Name",AsioDriver,128,"");
CfgReadStr("DSP PLUGIN","Filename",dspPlugin,255,"");
dspPluginModule = CfgReadInt("DSP PLUGIN","ModuleNum",0);
dspPluginEnabled= CfgReadBool("DSP PLUGIN","Enabled",false);
timeStretchEnabled = false; /*CfgReadBool("DSP","Timestretch_Enable",false);*/ //has to be false at init
LimiterToggleEnabled = CfgReadBool("KEYS","Limiter_Toggle_Enabled",false);
LimiterToggle = CfgReadInt ("KEYS","Limiter_Toggle",VK_SUBTRACT);
CfgReadStr("DirectSound Output (Stereo)","Device",DSoundDevice,255,"");
// Read DSOUNDOUT and WAVEOUT configs:
CfgReadStr( "DSOUNDOUT", "Device", Config_DSoundOut.Device, 254, "default" );
CfgReadStr( "WAVEOUT", "Device", Config_WaveOut.Device, 254, "default" );
Config_DSoundOut.NumBuffers = CfgReadInt( "DSOUNDOUT", "Buffer_Count", 3 );
Config_WaveOut.NumBuffers = CfgReadInt( "WAVEOUT", "Buffer_Count", 4 );
if(VolumeMultiplier<0) VolumeMultiplier=-VolumeMultiplier;
else if(VolumeMultiplier==0) VolumeMultiplier=1;
// Read DSOUND51 config:
Config_DSound51.GainL =CfgReadInt("DSOUND51","Channel_Gain_L", 256);
Config_DSound51.GainR =CfgReadInt("DSOUND51","Channel_Gain_R", 256);
Config_DSound51.GainC =CfgReadInt("DSOUND51","Channel_Gain_C", 256);
Config_DSound51.GainLFE=CfgReadInt("DSOUND51","Channel_Gain_LFE",256);
Config_DSound51.GainSL =CfgReadInt("DSOUND51","Channel_Gain_SL", 200);
Config_DSound51.GainSR =CfgReadInt("DSOUND51","Channel_Gain_SR", 200);
Config_DSound51.AddCLR =CfgReadInt("DSOUND51","Channel_Center_In_LR", 56);
Config_DSound51.LowpassLFE = CfgReadInt("DSOUND51","LFE_Lowpass_Frequency", 80);
// Read ASIOOUT config:
CfgReadStr("ASIO","Asio_Driver_Name",AsioDriver,128,"");
// Sanity Checks
// -------------
SampleRate = 48000; // Yup nothing else is supported for now.
VolumeShiftModifier = min( max( VolumeShiftModifier, -2 ), 2 );
SndOutVolumeShift = SndOutVolumeShiftBase - VolumeShiftModifier;
SndOutLatencyMS = min( max( SndOutLatencyMS, 20 ), 420 );
Config_DSoundOut.NumBuffers = min( max( Config_DSoundOut.NumBuffers, 2 ), 8 );
Config_WaveOut.NumBuffers = min( max( Config_DSoundOut.NumBuffers, 3 ), 8 );
if( mods[OutputModule] == NULL )
{
// Unsupported or legacy module.
fprintf( stderr, " * SPU2: Unknown output module '%s' specified in configuration file.\n", omodid );
fprintf( stderr, " * SPU2: Defaulting to DirectSound (%s).\n", DSoundOut->GetIdent() );
OutputModule = FindOutputModuleById( DSoundOut->GetIdent() );
}
if(VolumeDivisor<0) VolumeDivisor=-VolumeDivisor;
else if(VolumeDivisor==0) VolumeDivisor=1;
}
@ -276,20 +322,24 @@ void WriteSettings()
{
CfgWriteBool("DEBUG","Global_Debug_Enabled",DebugEnabled);
if(DebugEnabled) {
CfgWriteBool("DEBUG","Show_Messages", MsgToConsole);
CfgWriteBool("DEBUG","Show_Messages_Key_On_Off", MsgKeyOnOff);
CfgWriteBool("DEBUG","Show_Messages_Voice_Off", MsgVoiceOff);
CfgWriteBool("DEBUG","Show_Messages_DMA_Transfer",MsgDMA);
CfgWriteBool("DEBUG","Show_Messages_AutoDMA", MsgAutoDMA);
// [Air] : Commented out so that we retain debug settings even if disabled...
//if(DebugEnabled)
{
CfgWriteBool("DEBUG","Show_Messages", _MsgToConsole);
CfgWriteBool("DEBUG","Show_Messages_Key_On_Off", _MsgKeyOnOff);
CfgWriteBool("DEBUG","Show_Messages_Voice_Off", _MsgVoiceOff);
CfgWriteBool("DEBUG","Show_Messages_DMA_Transfer",_MsgDMA);
CfgWriteBool("DEBUG","Show_Messages_AutoDMA", _MsgAutoDMA);
CfgWriteBool("DEBUG","Show_Messages_Overruns", _MsgOverruns);
CfgWriteBool("DEBUG","Show_Messages_CacheStats", _MsgCache);
CfgWriteBool("DEBUG","Log_Register_Access",AccessLog);
CfgWriteBool("DEBUG","Log_DMA_Transfers", DMALog);
CfgWriteBool("DEBUG","Log_WAVE_Output", WaveLog);
CfgWriteBool("DEBUG","Log_Register_Access",_AccessLog);
CfgWriteBool("DEBUG","Log_DMA_Transfers", _DMALog);
CfgWriteBool("DEBUG","Log_WAVE_Output", _WaveLog);
CfgWriteBool("DEBUG","Dump_Info", CoresDump);
CfgWriteBool("DEBUG","Dump_Memory",MemDump);
CfgWriteBool("DEBUG","Dump_Regs", RegDump);
CfgWriteBool("DEBUG","Dump_Info", _CoresDump);
CfgWriteBool("DEBUG","Dump_Memory",_MemDump);
CfgWriteBool("DEBUG","Dump_Regs", _RegDump);
CfgWriteStr("DEBUG","Access_Log_Filename",AccessLogFileName);
CfgWriteStr("DEBUG","WaveLog_Filename", WaveLogFileName);
@ -308,67 +358,83 @@ void WriteSettings()
CfgWriteInt("MIXING","AutoDMA_Play_Rate_0",AutoDMAPlayRate[0]);
CfgWriteInt("MIXING","AutoDMA_Play_Rate_1",AutoDMAPlayRate[1]);
CfgWriteBool("EFFECTS","Enable_Effects",EffectsEnabled);
CfgWriteBool("MIXING","Enable_Effects",EffectsEnabled);
CfgWriteInt("OUTPUT","Output_Module",OutputModule);
CfgWriteStr("OUTPUT","Output_Module",mods[OutputModule]->GetIdent() );
CfgWriteInt("OUTPUT","Sample_Rate",SampleRate);
CfgWriteInt("OUTPUT","Buffer_Size",CurBufferSize);
CfgWriteInt("OUTPUT","Buffer_Count",MaxBufferCount);
CfgWriteInt("OUTPUT","Volume_Multiplier",VolumeMultiplier);
CfgWriteInt("OUTPUT","Volume_Divisor",VolumeDivisor);
CfgWriteInt("OUTPUT","Channel_Gain_L", GainL);
CfgWriteInt("OUTPUT","Channel_Gain_R", GainR);
CfgWriteInt("OUTPUT","Channel_Gain_C", GainC);
CfgWriteInt("OUTPUT","Channel_Gain_LFE",GainLFE);
CfgWriteInt("OUTPUT","Channel_Gain_SL", GainSL);
CfgWriteInt("OUTPUT","Channel_Gain_SR", GainSR);
CfgWriteInt("OUTPUT","Channel_Center_In_LR", AddCLR);
CfgWriteInt("OUTPUT","LFE_Lowpass_Frequency", LowpassLFE);
CfgWriteInt("OUTPUT","Latency",SndOutLatencyMS);
CfgWriteBool("OUTPUT","Timestretch_Enable",timeStretchEnabled);
CfgWriteInt("OUTPUT","Speed_Limit_Mode",LimitMode);
CfgWriteStr("OUTPUT","Asio_Driver_Name",AsioDriver);
CfgWriteInt("OUTPUT","Volume_Shift",SndOutVolumeShiftBase - SndOutVolumeShift);
CfgWriteStr("DSOUNDOUT","Device",Config_DSoundOut.Device);
CfgWriteInt("DSOUNDOUT","Buffer_Count",Config_DSoundOut.NumBuffers);
CfgWriteStr("WAVEOUT","Device",Config_WaveOut.Device);
CfgWriteInt("WAVEOUT","Buffer_Count",Config_WaveOut.NumBuffers);
CfgWriteInt("DSOUND51","Channel_Gain_L", Config_DSound51.GainL);
CfgWriteInt("DSOUND51","Channel_Gain_R", Config_DSound51.GainR);
CfgWriteInt("DSOUND51","Channel_Gain_C", Config_DSound51.GainC);
CfgWriteInt("DSOUND51","Channel_Gain_LFE",Config_DSound51.GainLFE);
CfgWriteInt("DSOUND51","Channel_Gain_SL", Config_DSound51.GainSL);
CfgWriteInt("DSOUND51","Channel_Gain_SR", Config_DSound51.GainSR);
CfgWriteInt("DSOUND51","Channel_Center_In_LR", Config_DSound51.AddCLR);
CfgWriteInt("DSOUND51","LFE_Lowpass_Frequency", Config_DSound51.LowpassLFE);
CfgWriteStr("ASIO","Asio_Driver_Name",AsioDriver);
CfgWriteStr("DSP PLUGIN","Filename",dspPlugin);
CfgWriteInt("DSP PLUGIN","ModuleNum",dspPluginModule);
CfgWriteBool("DSP PLUGIN","Enabled",dspPluginEnabled);
CfgWriteBool("DSP","Timestretch_Enable",timeStretchEnabled);
CfgWriteBool("KEYS","Limiter_Toggle_Enabled",LimiterToggleEnabled);
CfgWriteInt ("KEYS","Limiter_Toggle",LimiterToggle);
CfgWriteStr("DirectSound Output (Stereo)","Device",DSoundDevice);
}
static void EnableDebugMessages( 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, MsgDMA());
ENABLE_CONTROL(IDC_DBG_OVERRUNS, MsgToConsole());
ENABLE_CONTROL(IDC_DBG_CACHE, MsgToConsole());
}
static void EnableDebugControls( HWND hWnd )
{
EnableDebugMessages( hWnd );
ENABLE_CONTROL(IDC_LOGREGS, DebugEnabled);
ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled);
ENABLE_CONTROL(IDC_LOGWAVE, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPCORE,DebugEnabled);
ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPREGS,DebugEnabled);
}
static int myWidth, myDebugWidth;
static int myHeight;
static bool debugShow = false;
BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
int wmId,wmEvent;
char temp[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
char temp[384]={0};
switch(uMsg)
{
case WM_PAINT:
SET_CHECK(IDC_EFFECTS, EffectsEnabled);
SET_CHECK(IDC_DEBUG, DebugEnabled);
SET_CHECK(IDC_MSGKEY, DebugEnabled&MsgToConsole);
SET_CHECK(IDC_MSGKEY, DebugEnabled&MsgKeyOnOff);
SET_CHECK(IDC_MSGVOICE,DebugEnabled&MsgVoiceOff);
SET_CHECK(IDC_MSGDMA, DebugEnabled&MsgDMA);
SET_CHECK(IDC_MSGADMA, DebugEnabled&MsgDMA&MsgAutoDMA);
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_SPEEDLIMIT,LimitMode);
return FALSE;
case WM_INITDIALOG:
// If debugging is enabled, show the debug box by default:
debugShow = DebugEnabled;
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_RESETCONTENT,0,0);
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"16000");
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"22050");
@ -377,62 +443,64 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"44100");
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"48000");
sprintf(temp,"%d",SampleRate);
sprintf_s(temp,48,"%d",SampleRate);
SetDlgItemText(hWnd,IDC_SRATE,temp);
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_RESETCONTENT,0,0);
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"0 - Nearest (none)");
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"1 - Linear (mid)");
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"2 - Cubic (good)");
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"0 - Nearest (none/fast)");
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"1 - Linear (recommended)");
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"2 - Cubic (better/slower)");
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_SETCURSEL,Interpolation,0);
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_RESETCONTENT,0,0);
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"0 - Disabled (Emulate only)");
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"1 - waveOut (Slow/Laggy)");
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"2 - DSound (Typical)");
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"3 - DSound 5.1 (Experimental)");
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"4 - ASIO (Low Latency, BROKEN)");
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"5 - XAudio2 (Experimental)");
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_RESETCONTENT,0,0);
{
int modidx = 0;
while( mods[modidx] != NULL )
{
sprintf_s( temp, 72, "%d - %s", modidx, mods[modidx]->GetLongName() );
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)temp);
++modidx;
}
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_SETCURSEL,OutputModule,0);
}
INIT_SLIDER(IDC_BUFFER,512,16384,4096,2048,512);
//INIT_SLIDER(IDC_BUFFER,512,16384,4096,2048,512);
INIT_SLIDER( IDC_LATENCY_SLIDER, 20, 420, 100, 20, 5 );
SendMessage(GetDlgItem(hWnd,IDC_BUFFER),TBM_SETPOS,TRUE,CurBufferSize);
sprintf(temp,"%d",CurBufferSize);
SetWindowText(GetDlgItem(hWnd,IDC_BSIZE),temp);
SendMessage(GetDlgItem(hWnd,IDC_LATENCY_SLIDER),TBM_SETPOS,TRUE,SndOutLatencyMS);
sprintf_s(temp,80,"%d ms (avg)",SndOutLatencyMS);
SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp);
sprintf(temp,"%d",MaxBufferCount);
SetWindowText(GetDlgItem(hWnd,IDC_BCOUNT),temp);
ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled);
ENABLE_CONTROL(IDC_MSGKEY, DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGVOICE,DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGDMA, DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA);
ENABLE_CONTROL(IDC_LOGREGS, DebugEnabled);
ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled);
ENABLE_CONTROL(IDC_LOGWAVE, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPCORE,DebugEnabled);
ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPREGS,DebugEnabled);
EnableDebugControls( hWnd );
// Debugging / Logging Flags:
SET_CHECK(IDC_EFFECTS, EffectsEnabled);
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_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_MSGKEY, _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_SPEEDLIMIT,LimitMode);
SET_CHECK(IDC_SPEEDLIMIT_RUNTIME_TOGGLE,LimiterToggleEnabled);
SET_CHECK(IDC_DSP_ENABLE,dspPluginEnabled);
SET_CHECK(IDC_TS_ENABLE,timeStretchEnabled);
VolumeBoostEnabled = ( VolumeShiftModifier > 0 ) ? true : false;
SET_CHECK(IDC_VOLBOOST, VolumeBoostEnabled );
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
@ -444,49 +512,14 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
temp[19]=0;
SampleRate=atoi(temp);
GetDlgItemText(hWnd,IDC_BSIZE,temp,20);
temp[19]=0;
CurBufferSize=atoi(temp);
SndOutLatencyMS = (int)SendMessage( GetDlgItem( hWnd, IDC_LATENCY_SLIDER ), TBM_GETPOS, 0, 0 );
if(CurBufferSize<512) CurBufferSize=512;
if(CurBufferSize>16384) CurBufferSize=16384;
GetDlgItemText(hWnd,IDC_BCOUNT,temp,20);
temp[19]=0;
MaxBufferCount=atoi(temp);
if(MaxBufferCount<4) MaxBufferCount=4;
if(MaxBufferCount>50) MaxBufferCount=50;
if( SndOutLatencyMS > 420 ) SndOutLatencyMS = 420;
if( SndOutLatencyMS < 20 ) SndOutLatencyMS = 20;
Interpolation=(int)SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_GETCURSEL,0,0);
OutputModule=(int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0);
/*
if((BufferSize*CurBufferCount)<9600)
{
int ret=MessageBoxEx(hWnd,"The total buffer space is too small and might cause problems.\n"
"Press [Cancel] to go back and increase the buffer size or number.",
"WARNING",MB_OKCANCEL | MB_ICONEXCLAMATION, 0);
if(ret==IDCANCEL)
break;
}
*/
DebugEnabled=DebugEnabled;
MsgToConsole=DebugEnabled&MsgToConsole;
MsgKeyOnOff =DebugEnabled&MsgToConsole&MsgKeyOnOff;
MsgVoiceOff =DebugEnabled&MsgToConsole&MsgVoiceOff;
MsgDMA =DebugEnabled&MsgToConsole&MsgDMA;
MsgAutoDMA =DebugEnabled&MsgToConsole&MsgAutoDMA;
AccessLog =DebugEnabled&AccessLog;
DMALog =DebugEnabled&DMALog;
WaveLog =DebugEnabled&WaveLog;
CoresDump =DebugEnabled&CoresDump;
MemDump =DebugEnabled&MemDump;
RegDump =DebugEnabled&RegDump;
WriteSettings();
EndDialog(hWnd,0);
break;
@ -495,45 +528,41 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
break;
case IDC_OUTCONF:
SndConfigure(hWnd);
SndConfigure( hWnd,
(int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0)
);
break;
HANDLE_CHECKNB( IDC_VOLBOOST, VolumeBoostEnabled );
VolumeShiftModifier = (VolumeBoostEnabled ? 1 : 0 );
SndOutVolumeShift = SndOutVolumeShiftBase - VolumeShiftModifier;
break;
HANDLE_CHECK(IDC_EFFECTS,EffectsEnabled);
HANDLE_CHECKNB(IDC_DEBUG,DebugEnabled);
ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled);
ENABLE_CONTROL(IDC_MSGKEY, DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGVOICE,DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGDMA, DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA);
ENABLE_CONTROL(IDC_LOGREGS, DebugEnabled);
ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled);
ENABLE_CONTROL(IDC_LOGWAVE, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPCORE,DebugEnabled);
ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPREGS,DebugEnabled);
EnableDebugControls( hWnd );
break;
HANDLE_CHECKNB(IDC_MSGSHOW,MsgToConsole);
ENABLE_CONTROL(IDC_MSGKEY, DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGVOICE,DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGDMA, DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA);
HANDLE_CHECKNB(IDC_MSGSHOW,_MsgToConsole);
EnableDebugMessages( hWnd );
break;
HANDLE_CHECK(IDC_MSGKEY,MsgKeyOnOff);
HANDLE_CHECK(IDC_MSGVOICE,MsgVoiceOff);
HANDLE_CHECKNB(IDC_MSGDMA,MsgDMA);
ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA);
HANDLE_CHECK(IDC_MSGKEY,_MsgKeyOnOff);
HANDLE_CHECK(IDC_MSGVOICE,_MsgVoiceOff);
HANDLE_CHECKNB(IDC_MSGDMA,_MsgDMA);
ENABLE_CONTROL(IDC_MSGADMA, MsgDMA());
break;
HANDLE_CHECK(IDC_MSGADMA,MsgAutoDMA);
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_SPEEDLIMIT,LimitMode);
HANDLE_CHECK(IDC_MSGADMA,_MsgAutoDMA);
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_DSP_ENABLE,dspPluginEnabled);
HANDLE_CHECK(IDC_TS_ENABLE,timeStretchEnabled);
HANDLE_CHECK(IDC_SPEEDLIMIT,LimitMode);
HANDLE_CHECK(IDC_SPEEDLIMIT_RUNTIME_TOGGLE,LimiterToggleEnabled);
default:
return FALSE;
}
@ -550,11 +579,11 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
case TB_PAGEDOWN:
wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0);
case TB_THUMBTRACK:
if(wmEvent<512) wmEvent=512;
if(wmEvent>24000) wmEvent=24000;
if(wmEvent<20) wmEvent=20;
if(wmEvent>420) wmEvent=420;
SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent);
sprintf(temp,"%d",wmEvent);
SetDlgItemText(hWnd,IDC_BSIZE,temp);
sprintf_s(temp,80,"%d ms (avg)",wmEvent);
SetDlgItemText(hWnd,IDC_LATENCY_LABEL,temp);
break;
default:
return FALSE;

View File

@ -21,19 +21,39 @@
extern bool DebugEnabled;
extern bool MsgToConsole;
extern bool MsgKeyOnOff;
extern bool MsgVoiceOff;
extern bool MsgDMA;
extern bool MsgAutoDMA;
extern bool _MsgToConsole;
extern bool _MsgKeyOnOff;
extern bool _MsgVoiceOff;
extern bool _MsgDMA;
extern bool _MsgAutoDMA;
extern bool _MsgOverruns;
extern bool _MsgCache;
extern bool AccessLog;
extern bool DMALog;
extern bool WaveLog;
extern bool _AccessLog;
extern bool _DMALog;
extern bool _WaveLog;
extern bool _CoresDump;
extern bool _MemDump;
extern bool _RegDump;
static __forceinline bool MsgToConsole() { return _MsgToConsole & DebugEnabled; }
static __forceinline bool MsgKeyOnOff() { return _MsgKeyOnOff & MsgToConsole(); }
static __forceinline bool MsgVoiceOff() { return _MsgVoiceOff & MsgToConsole(); }
static __forceinline bool MsgDMA() { return _MsgDMA & MsgToConsole(); }
static __forceinline bool MsgAutoDMA() { return _MsgAutoDMA & MsgToConsole(); }
static __forceinline bool MsgOverruns() { return _MsgOverruns & MsgToConsole(); }
static __forceinline bool MsgCache() { return _MsgCache & MsgToConsole(); }
static __forceinline bool AccessLog() { return _AccessLog & DebugEnabled; }
static __forceinline bool DMALog() { return _DMALog & DebugEnabled; }
static __forceinline bool WaveLog() { return _WaveLog & DebugEnabled; }
static __forceinline bool CoresDump() { return _CoresDump & DebugEnabled; }
static __forceinline bool MemDump() { return _MemDump & DebugEnabled; }
static __forceinline bool RegDump() { return _RegDump & DebugEnabled; }
extern bool CoresDump;
extern bool MemDump;
extern bool RegDump;
extern char AccessLogFileName[255];
extern char WaveLogFileName[255];
@ -55,27 +75,16 @@ extern bool EffectsEnabled;
extern int AutoDMAPlayRate[2];
extern int OutputModule;
extern int CurBufferSize;
extern int CurBufferCount;
extern int MaxBufferCount;
extern u32 OutputModule;
extern int SndOutLatencyMS;
extern int VolumeMultiplier;
extern int VolumeDivisor;
//extern int VolumeMultiplier;
//extern int VolumeDivisor;
extern int LimitMode;
extern char AsioDriver[129];
extern u32 GainL;
extern u32 GainR;
extern u32 GainC;
extern u32 GainLFE;
extern u32 GainSL;
extern u32 GainSR;
extern u32 AddCLR;
extern u32 LowpassLFE;
extern char dspPlugin[];
extern int dspPluginModule;
@ -85,9 +94,82 @@ extern bool timeStretchEnabled;
extern bool LimiterToggleEnabled;
extern int LimiterToggle;
/// module-specific settings
// *** BEGIN DRIVER-SPECIFIC CONFIGURATION ***
// -------------------------------------------
extern char DSoundDevice[];
// DSOUND
struct CONFIG_DSOUNDOUT
{
char Device[256];
s8 NumBuffers;
CONFIG_DSOUNDOUT() :
NumBuffers( 3 )
{
memset( Device, 0, sizeof( Device ) );
}
};
// WAVEOUT
struct CONFIG_WAVEOUT
{
char Device[255];
s8 NumBuffers;
CONFIG_WAVEOUT() :
NumBuffers( 4 )
{
memset( Device, 0, sizeof( Device ) );
}
};
// DSOUND51
struct CONFIG_DSOUND51
{
char Device[256];
u32 NumBuffers;
u32 GainL;
u32 GainR;
u32 GainSL;
u32 GainSR;
u32 GainC;
u32 GainLFE;
u32 AddCLR;
u32 LowpassLFE;
// C++ style struct/class initializer
CONFIG_DSOUND51() :
NumBuffers( 4 )
, GainL( 256 )
, GainR( 256 )
, GainSL( 200 )
, GainSR( 200 )
, GainC( 200 )
, GainLFE( 256 )
, AddCLR( 56 )
, LowpassLFE( 80 )
{
memset( Device, 0, sizeof( Device ) );
}
};
struct CONFIG_ASIO
{
s8 NumBuffers;
CONFIG_ASIO() :
NumBuffers( 8 )
{
//memset( Device, 0, sizeof( Device ) );
}
};
extern CONFIG_DSOUNDOUT Config_DSoundOut;
extern CONFIG_DSOUND51 Config_DSound51;
extern CONFIG_WAVEOUT Config_WaveOut;
extern CONFIG_ASIO Config_Asio;
//////
@ -96,4 +178,4 @@ void ReadSettings();
void WriteSettings();
void configure();
#endif // CONFIG_H_INCLUDED
#endif // CONFIG_H_INCLUDED

View File

@ -29,8 +29,7 @@ void FileLog(const char *fmt, ...) {
int n;
va_list list;
if(!DebugEnabled) return;
if(!AccessLog) return;
if(!AccessLog()) return;
if(!spu2Log) return;
va_start(list, fmt);
@ -55,8 +54,7 @@ void ConLog(const char *fmt, ...) {
int n;
va_list list;
if(!DebugEnabled) return;
if(!MsgToConsole) return;
if(!MsgToConsole()) return;
va_start(list, fmt);
n=vsprintf(s,fmt, list);
@ -78,14 +76,14 @@ void DoFullDump() {
FILE *dump;
u8 c=0, v=0;
if(MemDump) {
if(MemDump()) {
dump=fopen(MemDumpFileName,"wb");
if (dump) {
fwrite(_spu2mem,0x200000,1,dump);
fclose(dump);
}
}
if(RegDump) {
if(RegDump()) {
dump=fopen(RegDumpFileName,"wb");
if (dump) {
fwrite(spu2regs,0x2000,1,dump);
@ -93,7 +91,7 @@ void DoFullDump() {
}
}
if(!CoresDump) return;
if(!CoresDump()) return;
dump=fopen(CoresDumpFileName,"wt");
if (dump) {
for(c=0;c<2;c++) {

View File

@ -34,7 +34,7 @@ u16* MBASE[2] = {0,0};
u16* DMABaseAddr;
void DMALogOpen() {
if(!DMALog) return;
if(!DMALog()) return;
DMA4LogFile=fopen(DMA4LogFileName,"wb");
DMA7LogFile=fopen(DMA7LogFileName,"wb");
ADMA4LogFile=fopen("logs/adma4.raw","wb");
@ -44,42 +44,42 @@ void DMALogOpen() {
//REGWRTLogFile[1]=fopen("logs/RegWrite1.raw","wb");
}
void DMA4LogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return;
if(!DMALog()) return;
if (!DMA4LogFile) return;
fwrite(lpData,ulSize,1,DMA4LogFile);
}
void DMA7LogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return;
if(!DMALog()) return;
if (!DMA7LogFile) return;
fwrite(lpData,ulSize,1,DMA7LogFile);
}
void ADMA4LogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return;
if(!DMALog()) return;
if (!ADMA4LogFile) return;
fwrite(lpData,ulSize,1,ADMA4LogFile);
}
void ADMA7LogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return;
if(!DMALog()) return;
if (!ADMA7LogFile) return;
fwrite(lpData,ulSize,1,ADMA7LogFile);
}
void ADMAOutLogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return;
if(!DMALog()) return;
if (!ADMAOutLogFile) return;
fwrite(lpData,ulSize,1,ADMAOutLogFile);
}
void RegWriteLog(u32 core,u16 value)
{
if(!DMALog) return;
if(!DMALog()) return;
if (!REGWRTLogFile[core]) return;
fwrite(&value,2,1,REGWRTLogFile[core]);
}
void DMALogClose() {
if(!DMALog) return;
if(!DMALog()) return;
if (DMA4LogFile) fclose(DMA4LogFile);
if (DMA7LogFile) fclose(DMA7LogFile);
if (REGWRTLogFile[0]) fclose(REGWRTLogFile[0]);
@ -142,7 +142,7 @@ void AutoDMAReadBuffer(int core, int mode) //mode: 0= split stereo; 1 = do not s
void StartADMAWrite(int core,u16 *pMem, u32 sz)
{
int size=(sz)&(~511);
if(MsgAutoDMA) ConLog(" * SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff);
if(MsgAutoDMA()) ConLog(" * SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff);
Cores[core].InputDataProgress=0;
if((Cores[core].AutoDMACtrl&(core+1))==0)
@ -202,7 +202,7 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
else
DMA7LogWrite(pMem,size<<1);
if(MsgDMA) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff);
if(MsgDMA()) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff);
Cores[core].TDA=Cores[core].TSA;
for (i=0;i<size;i++) {

View File

@ -48,11 +48,11 @@ extern HRESULT GUIDFromString(const char *str, LPGUID guid);
class DSound51: public SndOutModule
{
private:
# define PI 3.14159265f
# define MAX_BUFFER_COUNT 8
# define BufferSize (CurBufferSize*6)
# define BufferSizeBytes (BufferSize<<1)
# define TBufferSize (BufferSize*CurBufferCount)
static const int PacketsPerBuffer = (1024 / SndOutPacketSize);
static const int BufferSize = SndOutPacketSize*PacketsPerBuffer * 6;
static const int BufferSizeBytes = BufferSize << 1;
s32* tbuffer;
@ -64,8 +64,6 @@ private:
HANDLE thread;
DWORD tid;
#define MAX_BUFFER_COUNT 3
IDirectSound8* dsound;
IDirectSoundBuffer8* buffer;
IDirectSoundNotify8* buffer_notify;
@ -206,12 +204,12 @@ private:
SL = (SLd * 209 + SC * 148)>>8; //16.0
SR = (SRd * 209 + SC * 148)>>8; //16.0
obuffer[0]=spdif_data[0] + (((L * GainL ) + (C * AddCLR))>>8);
obuffer[1]=spdif_data[1] + (((R * GainR ) + (C * AddCLR))>>8);
obuffer[2]=spdif_data[2] + (((C * GainC ))>>8);
obuffer[3]=spdif_data[3] + (((LFE * GainLFE))>>8);
obuffer[4]=spdif_data[4] + (((SL * GainSL ))>>8);
obuffer[5]=spdif_data[5] + (((SR * GainSR ))>>8);
obuffer[0]=spdif_data[0] + (((L * Config_DSound51.GainL ) + (C * Config_DSound51.AddCLR))>>8);
obuffer[1]=spdif_data[1] + (((R * Config_DSound51.GainR ) + (C * Config_DSound51.AddCLR))>>8);
obuffer[2]=spdif_data[2] + (((C * Config_DSound51.GainC ))>>8);
obuffer[3]=spdif_data[3] + (((LFE * Config_DSound51.GainLFE))>>8);
obuffer[4]=spdif_data[4] + (((SL * Config_DSound51.GainSL ))>>8);
obuffer[5]=spdif_data[5] + (((SR * Config_DSound51.GainSR ))>>8);
#else
obuffer[0]=spdif_data[0]+(ValL>>8);
obuffer[1]=spdif_data[1]+(ValR>>8);
@ -245,33 +243,35 @@ private:
{
while( dsound_running )
{
u32 rv = WaitForMultipleObjects(MAX_BUFFER_COUNT,buffer_events,FALSE,400);
u32 rv = WaitForMultipleObjects(Config_DSound51.NumBuffers,buffer_events,FALSE,200);
LPVOID p1,p2;
s16* p1, *oldp1;
LPVOID p2;
DWORD s1,s2;
for(int i=0;i<MAX_BUFFER_COUNT;i++)
u32 poffset=BufferSizeBytes * rv;
verifyc(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0));
oldp1 = p1;
for(int p=0; p<PacketsPerBuffer; p++, p1+=SndOutPacketSize )
{
if (rv==WAIT_OBJECT_0+i)
s32 temp[SndOutPacketSize];
s32* s = temp;
s16* t = p1;
buff->ReadSamples( temp );
for(int j=0;j<SndOutPacketSize/2;j++)
{
u32 poffset=BufferSizeBytes * i;
// DPL2 code here: inputs s[0] and s[1]. outputs t[0] to t[5]
Convert(t,s[0],s[1]);
buff->ReadSamples(tbuffer,CurBufferSize*2);
verifyc(buffer->Lock(poffset,BufferSizeBytes,&p1,&s1,&p2,&s2,0));
s16 *t = (s16*)p1;
s32 *s = tbuffer;
for(int j=0;j<CurBufferSize;j++)
{
// DPL2 code here: inputs s[0] and s[1]. outputs t[0] to t[5]
Convert(t,s[0],s[1]);
t+=6;
s+=2;
}
verifyc(buffer->Unlock(p1,s1,p2,s2));
}
t+=6;
s+=2;
}
}
verifyc(buffer->Unlock(oldp1,s1,p2,s2));
}
return 0;
}
@ -279,8 +279,6 @@ private:
public:
s32 Init(SndBuffer *sb)
{
if(CurBufferSize<1024) CurBufferSize=1024;
buff = sb;
//
@ -313,7 +311,7 @@ public:
memset(&desc, 0, sizeof(DSBUFFERDESC));
desc.dwSize = sizeof(DSBUFFERDESC);
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
desc.dwBufferBytes = BufferSizeBytes * MAX_BUFFER_COUNT;
desc.dwBufferBytes = BufferSizeBytes * Config_DSound51.NumBuffers;
desc.lpwfxFormat = &wfx.Format;
desc.dwFlags |=DSBCAPS_LOCSOFTWARE;
@ -327,14 +325,14 @@ public:
DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT];
for(int i=0;i<MAX_BUFFER_COUNT;i++)
for(int i=0;i<Config_DSound51.NumBuffers;i++)
{
buffer_events[i]=CreateEvent(NULL,FALSE,FALSE,NULL);
not[i].dwOffset=(wfx.Format.nBlockAlign*10 + BufferSizeBytes*(i+1))%desc.dwBufferBytes;
not[i].hEventNotify=buffer_events[i];
}
buffer_notify->SetNotificationPositions(MAX_BUFFER_COUNT,not);
buffer_notify->SetNotificationPositions(Config_DSound51.NumBuffers,not);
LPVOID p1=0,p2=0;
DWORD s1=0,s2=0;
@ -344,13 +342,13 @@ public:
memset(p1,0,s1);
verifyc(buffer->Unlock(p1,s1,p2,s2));
LPF_init(&lpf_l,LowpassLFE,SampleRate);
LPF_init(&lpf_r,LowpassLFE,SampleRate);
LPF_init(&lpf_l,Config_DSound51.LowpassLFE,SampleRate);
LPF_init(&lpf_r,Config_DSound51.LowpassLFE,SampleRate);
//Play the buffer !
verifyc(buffer->Play(0,0,DSBPLAY_LOOPING));
tbuffer = new s32[BufferSize];
tbuffer = new s32[SndOutPacketSize];
// Start Thread
dsound_running=true;
@ -376,7 +374,7 @@ public:
//
buffer->Stop();
for(int i=0;i<MAX_BUFFER_COUNT;i++)
for(int i=0;i<Config_DSound51.NumBuffers;i++)
CloseHandle(buffer_events[i]);
buffer_notify->Release();
@ -425,7 +423,7 @@ private:
if(wmEvent<vmin) wmEvent=vmin;
if(wmEvent>vmax) wmEvent=vmax;
SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent);
sprintf(temp,"%d",vmax-wmEvent);
sprintf_s(temp,1024,"%d",vmax-wmEvent);
SetWindowText(hwndDisplay,temp);
break;
default:
@ -445,7 +443,7 @@ private:
{
case WM_INITDIALOG:
haveGuid = ! FAILED(GUIDFromString(DSoundDevice,&DevGuid));
haveGuid = ! FAILED(GUIDFromString(Config_DSound51.Device,&DevGuid));
SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_RESETCONTENT,0,0);
ndevs=0;
@ -474,6 +472,12 @@ private:
INIT_SLIDER(IDC_SLIDER6,0,512,64,16,8);
INIT_SLIDER(IDC_SLIDER7,0,512,64,16,8);
char temp[128];
INIT_SLIDER( IDC_BUFFERS_SLIDER, 2, MAX_BUFFER_COUNT, 2, 1, 1 );
SendMessage(GetDlgItem(hWnd,IDC_BUFFERS_SLIDER),TBM_SETPOS,TRUE,Config_DSound51.NumBuffers);
sprintf_s(temp, 128, "%d (%d ms latency)",Config_DSound51.NumBuffers, 1000 / (96000 / (Config_DSound51.NumBuffers * BufferSize)));
SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
@ -487,11 +491,11 @@ private:
if(!devices[i].hasGuid)
{
DSoundDevice[0]=0; // clear device name to ""
Config_DSound51.Device[0]=0; // clear device name to ""
}
else
{
sprintf_s(DSoundDevice,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
sprintf_s(Config_DSound51.Device,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
devices[i].guid.Data1,
devices[i].guid.Data2,
devices[i].guid.Data3,
@ -504,6 +508,11 @@ private:
devices[i].guid.Data4[6],
devices[i].guid.Data4[7]
);
Config_DSound51.NumBuffers = (int)SendMessage( GetDlgItem( hWnd, IDC_BUFFERS_SLIDER ), TBM_GETPOS, 0, 0 );
if( Config_DSound51.NumBuffers < 2 ) Config_DSound51.NumBuffers = 2;
if( Config_DSound51.NumBuffers > MAX_BUFFER_COUNT ) Config_DSound51.NumBuffers = MAX_BUFFER_COUNT;
}
}
EndDialog(hWnd,0);
@ -515,6 +524,30 @@ private:
return FALSE;
}
break;
case WM_HSCROLL:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch(wmId) {
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0);
case TB_THUMBTRACK:
if( wmEvent < 2 ) wmEvent = 2;
if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT;
SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent);
sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize)));
SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp);
break;
default:
return FALSE;
}
break;
case WM_VSCROLL:
HANDLE_SCROLL_MESSAGE(IDC_SLIDER1,0,512,IDC_EDIT1);
HANDLE_SCROLL_MESSAGE(IDC_SLIDER2,0,512,IDC_EDIT2);
@ -542,13 +575,27 @@ public:
}
}
s32 Test()
s32 Test() const
{
return 0;
}
bool Is51Out() { return true; }
bool Is51Out() const { return true; }
int GetEmptySampleCount() const
{
return 0;
}
const char* GetIdent() const
{
return "dsound51";
}
const char* GetLongName() const
{
return "DSound 5.1 (Experimental)";
}
} DS51;
SndOutModule *DSound51Out=&DS51;
SndOutModule *DSound51Out=&DS51;

View File

@ -68,12 +68,11 @@ HRESULT GUIDFromString(const char *str, LPGUID guid)
class DSound: public SndOutModule
{
private:
# define PI 3.14159265f
# define MAX_BUFFER_COUNT 8
# define BufferSize (CurBufferSize<<1)
# define BufferSizeBytes (BufferSize<<1)
# define TBufferSize (BufferSize*CurBufferCount)
static const int PacketsPerBuffer = (1024 / SndOutPacketSize);
static const int BufferSize = SndOutPacketSize * PacketsPerBuffer;
static const int BufferSizeBytes = BufferSize << 1;
FILE *voicelog;
@ -83,8 +82,6 @@ private:
HANDLE thread;
DWORD tid;
# define MAX_BUFFER_COUNT 5
IDirectSound8* dsound;
IDirectSoundBuffer8* buffer;
IDirectSoundNotify8* buffer_notify;
@ -96,10 +93,7 @@ private:
SndBuffer *buff;
s32 *tbuffer;
# define STRFY(x) #x
# define verifyc(x) if(Verifyc(x,STRFY(x))) return -1;
int __forceinline Verifyc(HRESULT hr,const char* fn)
@ -122,36 +116,21 @@ private:
while( dsound_running )
{
u32 rv = WaitForMultipleObjects(MAX_BUFFER_COUNT,buffer_events,FALSE,400);
u32 rv = WaitForMultipleObjects(Config_DSoundOut.NumBuffers,buffer_events,FALSE,200);
LPVOID p1,p2;
s16* p1, *oldp1;
LPVOID p2;
DWORD s1,s2;
u32 poffset=BufferSizeBytes * rv;
//DWORD play, write;
//buffer->GetCurrentPosition( &play, &write );
//ConLog( " * SPU2 > Play: %d Write: %d poffset: %d\n", play, write, poffset );
verifyc(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0));
oldp1 = p1;
buff->ReadSamples(tbuffer,BufferSize);
verifyc(buffer->Lock(poffset,BufferSizeBytes,&p1,&s1,&p2,&s2,0));
for(int p=0; p<PacketsPerBuffer; p++, p1+=SndOutPacketSize )
buff->ReadSamples( p1 );
{
s16 *t = (s16*)p1;
s32 *s = (s32*)tbuffer;
for(int j=0;j<BufferSize;j++)
{
*(t++) = (s16)((*(s++))>>8);
}
}
/*if( p2 != NULL )
{
ConLog( " * SPU2 > DSound Driver Loop-Around Occured. Length: %d", s2 );
}*/
verifyc(buffer->Unlock(p1,s1,p2,s2));
verifyc(buffer->Unlock(oldp1,s1,p2,s2));
}
return 0;
}
@ -166,7 +145,7 @@ public:
//
GUID cGuid;
if((strlen(DSoundDevice)>0)&&(!FAILED(GUIDFromString(DSoundDevice,&cGuid))))
if((strlen(Config_DSoundOut.Device)>0)&&(!FAILED(GUIDFromString(Config_DSoundOut.Device,&cGuid))))
{
verifyc(DirectSoundCreate8(&cGuid,&dsound,NULL));
}
@ -187,7 +166,7 @@ public:
wfx.nChannels=2;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = 2*2;
wfx.nAvgBytesPerSec = SampleRate * 2 * 2;
wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign;
wfx.cbSize=0;
// Set up DSBUFFERDESC structure.
@ -195,7 +174,7 @@ public:
memset(&desc, 0, sizeof(DSBUFFERDESC));
desc.dwSize = sizeof(DSBUFFERDESC);
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
desc.dwBufferBytes = BufferSizeBytes * MAX_BUFFER_COUNT;
desc.dwBufferBytes = BufferSizeBytes * Config_DSoundOut.NumBuffers;
desc.lpwfxFormat = &wfx;
desc.dwFlags |=DSBCAPS_LOCSOFTWARE;
@ -209,14 +188,18 @@ public:
DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT];
for(int i=0;i<MAX_BUFFER_COUNT;i++)
for(int i=0;i<Config_DSoundOut.NumBuffers;i++)
{
// [Air] note: wfx.nBlockAlign modifier was *10 -- seems excessive to me but maybe
// it was needed for some quirky driver? Theoretically we want the notification as soon
// as possible after the buffer has finished playing.
buffer_events[i]=CreateEvent(NULL,FALSE,FALSE,NULL);
not[i].dwOffset=(wfx.nBlockAlign*10 + BufferSizeBytes*(i+1))%desc.dwBufferBytes;
not[i].dwOffset=(wfx.nBlockAlign*2 + BufferSizeBytes*(i+1))%desc.dwBufferBytes;
not[i].hEventNotify=buffer_events[i];
}
buffer_notify->SetNotificationPositions(MAX_BUFFER_COUNT,not);
buffer_notify->SetNotificationPositions(Config_DSoundOut.NumBuffers,not);
LPVOID p1=0,p2=0;
DWORD s1=0,s2=0;
@ -229,13 +212,10 @@ public:
//Play the buffer !
verifyc(buffer->Play(0,0,DSBPLAY_LOOPING));
tbuffer = new s32[BufferSize];
// Start Thread
dsound_running=true;
thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread,this,0,&tid);
thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread,this,0,&tid);
SetThreadPriority(thread,THREAD_PRIORITY_TIME_CRITICAL);
return 0;
}
@ -257,14 +237,12 @@ public:
//
buffer->Stop();
for(int i=0;i<MAX_BUFFER_COUNT;i++)
for(int i=0;i<Config_DSoundOut.NumBuffers;i++)
CloseHandle(buffer_events[i]);
buffer_notify->Release();
buffer->Release();
dsound->Release();
delete tbuffer;
}
private:
@ -298,7 +276,7 @@ private:
{
case WM_INITDIALOG:
haveGuid = ! FAILED(GUIDFromString(DSoundDevice,&DevGuid));
haveGuid = ! FAILED(GUIDFromString(Config_DSoundOut.Device,&DevGuid));
SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_RESETCONTENT,0,0);
ndevs=0;
@ -319,6 +297,12 @@ private:
SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_SETCURSEL,tSel,0);
}
char temp[128];
INIT_SLIDER( IDC_BUFFERS_SLIDER, 2, MAX_BUFFER_COUNT, 2, 1, 1 );
SendMessage(GetDlgItem(hWnd,IDC_BUFFERS_SLIDER),TBM_SETPOS,TRUE,Config_DSoundOut.NumBuffers);
sprintf_s(temp, 128, "%d (%d ms latency)",Config_DSoundOut.NumBuffers, 1000 / (96000 / (Config_DSoundOut.NumBuffers * BufferSize)));
SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
@ -332,11 +316,11 @@ private:
if(!devices[i].hasGuid)
{
DSoundDevice[0]=0; // clear device name to ""
Config_DSoundOut.Device[0] = 0; // clear device name to ""
}
else
{
sprintf_s(DSoundDevice,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
sprintf_s(Config_DSoundOut.Device,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
devices[i].guid.Data1,
devices[i].guid.Data2,
devices[i].guid.Data3,
@ -350,6 +334,11 @@ private:
devices[i].guid.Data4[7]
);
}
Config_DSoundOut.NumBuffers = (int)SendMessage( GetDlgItem( hWnd, IDC_BUFFERS_SLIDER ), TBM_GETPOS, 0, 0 );
if( Config_DSoundOut.NumBuffers < 2 ) Config_DSoundOut.NumBuffers = 2;
if( Config_DSoundOut.NumBuffers > MAX_BUFFER_COUNT ) Config_DSoundOut.NumBuffers = MAX_BUFFER_COUNT;
}
EndDialog(hWnd,0);
break;
@ -360,6 +349,30 @@ private:
return FALSE;
}
break;
case WM_HSCROLL:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch(wmId) {
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0);
case TB_THUMBTRACK:
if( wmEvent < 2 ) wmEvent = 2;
if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT;
SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent);
sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize)));
SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp);
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
@ -378,12 +391,36 @@ public:
}
}
virtual bool Is51Out() { return false; }
virtual bool Is51Out() const { return false; }
s32 Test()
s32 Test() const
{
return 0;
}
int GetEmptySampleCount() const
{
DWORD play, write;
buffer->GetCurrentPosition( &play, &write );
int filled = play - write;
if( filled < 0 )
filled = -filled;
else
filled = (BufferSizeBytes * Config_DSoundOut.NumBuffers) - filled;
return filled;
}
const char* GetIdent() const
{
return "dsound";
}
const char* GetLongName() const
{
return "DirectSound";
}
} DS;
SndOutModule *DSoundOut=&DS;

View File

@ -232,7 +232,7 @@ static void __forceinline __fastcall GetNextDataBuffered( V_Core& thiscore, V_Vo
VoiceStop(core,voice);
thiscore.Regs.ENDX|=1<<voice;
#ifndef PUBLIC
if(MsgVoiceOff) ConLog(" * SPU2: Voice Off by EndPoint: %d \n", voice);
if(MsgVoiceOff()) ConLog(" * SPU2: Voice Off by EndPoint: %d \n", voice);
DebugCores[core].Voices[voice].lastStopReason = 1;
#endif
}
@ -444,7 +444,7 @@ static void __forceinline CalculateADSR( V_Voice& vc )
if (env.Phase==6) {
#ifndef PUBLIC
if(MsgVoiceOff) ConLog(" * SPU2: Voice Off by ADSR: %d \n", voice);
if(MsgVoiceOff()) ConLog(" * SPU2: Voice Off by ADSR: %d \n", voice);
DebugCores[core].Voices[voice].lastStopReason = 2;
#endif
VoiceStop(core,voice);
@ -665,7 +665,7 @@ void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR)
#ifndef PUBLIC
if(thiscore.InputDataLeft>0)
{
if(MsgAutoDMA) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
#endif
thiscore.InputDataLeft=0;
@ -705,7 +705,7 @@ void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR)
#ifndef PUBLIC
if(thiscore.InputDataLeft>0)
{
if(MsgAutoDMA) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
#endif
thiscore.InputDataLeft=0;
@ -759,7 +759,7 @@ void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR)
#ifndef PUBLIC
if(thiscore.InputDataLeft>0)
{
if(MsgAutoDMA) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
#endif
thiscore.InputDataLeft=0;
@ -1062,14 +1062,11 @@ static void __forceinline MixVoice( V_Core& thiscore, V_Voice& vc, s32& VValL, s
static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR)
{
s32 RVL,RVR;
s32 TDL=0,TDR=0;
s32 SDL=0,SDR=0;
s32 SWL=0,SWR=0;
V_Core& thiscore( Cores[core] );
SDL=SDR=SWL=SWR=(s32)0;
for (voice=0;voice<24;voice++)
{
s32 VValL,VValR;
@ -1089,6 +1086,8 @@ static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR)
spu2M_WriteFast( 0x1400 + (core<<12) + OutPos, (s16)(SWL>>16) );
spu2M_WriteFast( 0x1600 + (core<<12) + OutPos, (s16)(SWR>>16) );
s32 TDL,TDR;
// Mix in the Input data
TDL = OutL * thiscore.InpDryL;
TDR = OutR * thiscore.InpDryR;
@ -1200,13 +1199,11 @@ void __fastcall Mix()
Peak1 = max(Peak1,max(OutL,OutR));
#endif
// [Air] [TODO] : Replace this with MulShr32.
// I haven't done it yet because it would require making the
// VolumeDivisor a constant .. which it should be anyway. The presence
// of VolumeMultiplier more or less negates the need for a variable divisor.
ExtL=MulDiv(OutL,VolumeMultiplier,VolumeDivisor<<6);
ExtR=MulDiv(OutR,VolumeMultiplier,VolumeDivisor<<6);
// [Air] : Removed MulDiv here in favor of a more direct approach
// within the SndOut driver (which ends up having to apply its own
// master volume divisors anyway).
//ExtL=MulDiv(OutL,VolumeMultiplier,1<<6);
//ExtR=MulDiv(OutR,VolumeMultiplier,1<<6);
// Update spdif (called each sample)
if(PlayMode&4)
@ -1215,17 +1212,17 @@ void __fastcall Mix()
}
// AddToBuffer
SndWrite(ExtL,ExtR);
SndWrite(OutL, OutR); //ExtL,ExtR);
OutPos++;
if (OutPos>=0x200) OutPos=0;
#ifndef PUBLIC
// [TODO]: Create an INI option to enable/disable this particular log.
p_cachestat_counter++;
if(p_cachestat_counter > (48000*6) )
if(p_cachestat_counter > (48000*10) )
{
p_cachestat_counter = 0;
ConLog( " * SPU2 > CacheStatistics > Hits: %d Misses: %d Ignores: %d\n",
if( MsgCache() ) ConLog( " * SPU2 > CacheStats > Hits: %d Misses: %d Ignores: %d\n",
g_counter_cache_hits,
g_counter_cache_misses,
g_counter_cache_ignores );

View File

@ -20,6 +20,7 @@
#define IDC_SRATE 1012
#define IDC_OUTPUT 1013
#define IDC_BUFFER 1014
#define IDC_BUFFERS_SLIDER 1014
#define IDC_BSIZE 1016
#define IDC_BCOUNT 1018
#define IDC_TEXT 1019
@ -37,16 +38,26 @@
#define IDC_SLIDER2 1034
#define IDC_SLIDER3 1035
#define IDC_EDIT1 1036
#define IDC_BUTTON1 1037
#define IDC_SHOW_DEBUG 1037
#define IDC_DBG_OVERRUNS 1038
#define IDC_SLIDER4 1039
#define IDC_DBG_CACHE 1039
#define IDC_SLIDER5 1040
#define IDC_DEBUG_GROUP 1040
#define IDC_SLIDER6 1041
#define IDC_LATENCY_SLIDER 1041
#define IDC_SLIDER7 1042
#define IDC_LATENCY_LABEL 1042
#define IDC_EDIT2 1043
#define IDC_EDIT3 1044
#define IDC_SPEEDLIMIT_RUNTIME_TOGGLE 1044
#define IDC_EDIT4 1045
#define IDC_EDIT5 1046
#define IDC_EDIT6 1047
#define IDC_VOLBOOST 1047
#define IDC_EDIT7 1048
#define IDC_LATENCY_LABEL2 1049
// Next default values for new objects
//
@ -54,7 +65,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 110
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1037
#define _APS_NEXT_CONTROL_VALUE 1048
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -19,13 +19,30 @@
#include "SoundTouch/SoundTouch.h"
#include "SoundTouch/WavFile.h"
static int ts_stats_stretchblocks = 0;
static int ts_stats_normalblocks = 0;
static int ts_stats_logcounter = 0;
class NullOutModule: public SndOutModule
{
public:
s32 Init(SndBuffer *) { return 0; }
void Close() { }
s32 Test() { return 0; }
s32 Test() const { return 0; }
void Configure(HWND parent) { }
bool Is51Out() { return false; }
bool Is51Out() const { return false; }
int GetEmptySampleCount() const { return 0; }
const char* GetIdent() const
{
return "nullout";
}
const char* GetLongName() const
{
return "No Sound (Emulate SPU2 only)";
}
} NullOut;
SndOutModule* mods[]=
@ -36,9 +53,39 @@ SndOutModule* mods[]=
DSound51Out,
ASIOOut,
XAudio2Out,
NULL // signals the end of our list
};
const u32 mods_count=sizeof(mods)/sizeof(SndOutModule*);
int FindOutputModuleById( const char* omodid )
{
int modcnt = 0;
while( mods[modcnt] != NULL )
{
if( strcmp( mods[modcnt]->GetIdent(), omodid ) == 0 )
break;
++modcnt;
}
return modcnt;
}
// Overall master volume shift.
// Converts the mixer's 32 bit value into a 16 bit value.
int SndOutVolumeShift = SndOutVolumeShiftBase + 1;
static __forceinline s16 SndScaleVol( s32 inval )
{
return inval >> SndOutVolumeShift;
}
// records last buffer status (fill %, range -100 to 100, with 0 being 50% full)
double lastPct;
float cTempo=1;
soundtouch::SoundTouch* pSoundTouch=NULL;
//usefull when timestretch isn't available
//#define DYNAMIC_BUFFER_LIMITING
@ -52,45 +99,42 @@ private:
s32 wpos;
s32 data;
#ifdef DYNAMIC_BUFFER_LIMITING
s32 buffer_limit;
#endif
// data prediction amount, used to "commit" data that hasn't
// finished timestretch processing.
s32 predictData;
bool pr;
bool pw;
int overflows;
int underflows;
int writewaits;
bool isWaiting;
bool underrun_freeze;
HANDLE hSyncEvent;
CRITICAL_SECTION cs;
u32 datawritten;
u32 dataread;
protected:
int GetAlignedBufferSize( int comp )
{
return (comp + SndOutPacketSize-1) & ~(SndOutPacketSize-1);
}
public:
SndBufferImpl(s32 _size)
SndBufferImpl( double latencyMS )
{
rpos=0;
wpos=0;
data=0;
size=(_size+1)&(~1);
size=GetAlignedBufferSize( (int)(latencyMS * SampleRate / 500.0 ) );
buffer = new s32[size];
pr=false;
pw=false;
isWaiting=false;
underrun_freeze = false;
predictData = 0;
lastPct = 0.0;
#ifdef DYNAMIC_BUFFER_LIMITING
overflows=0;
underflows=0;
writewaits=0;
buffer_limit=size;
#endif
datawritten=0;
dataread=0;
InitializeCriticalSection(&cs);
hSyncEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
}
@ -98,7 +142,7 @@ public:
virtual ~SndBufferImpl()
{
pw=false;
if(isWaiting) PulseEvent(hSyncEvent);
PulseEvent(hSyncEvent);
Sleep(10);
EnterCriticalSection(&cs);
LeaveCriticalSection(&cs);
@ -107,42 +151,24 @@ public:
delete buffer;
}
virtual void WriteSamples(s32 *bData, s32 nSamples)
virtual void WriteSamples(s32 *bData, int nSamples)
{
EnterCriticalSection(&cs);
datawritten+=nSamples;
#ifdef DYNAMIC_BUFFER_LIMITING
int free = buffer_limit-data;
#else
int free = size-data;
#endif
predictData = 0;
if(pw)
jASSUME( data <= size );
if( pw && ( free < nSamples ) )
{
#ifdef DYNAMIC_BUFFER_LIMITING
if(free<nSamples)
writewaits++;
#endif
while((free<nSamples)&&(pw))
{
//isWaiting=true;
LeaveCriticalSection(&cs);
//ConLog( " * SPU2 : Waiting for object... " );
WaitForSingleObject(hSyncEvent,1000);
//ConLog( " Signaled! \n" );
EnterCriticalSection(&cs);
#ifdef DYNAMIC_BUFFER_LIMITING
free = buffer_limit-data;
#else
free = size-data;
#endif
//isWaiting=false;
}
// Wait for a ReadSamples to pull some stuff out of the buffer.
// One SyncEvent will do the trick.
ResetEvent( hSyncEvent );
LeaveCriticalSection(&cs);
WaitForSingleObject(hSyncEvent,20);
EnterCriticalSection(&cs);
}
// either pw=false or free>nSamples
// 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
@ -154,64 +180,106 @@ public:
// The older portion of the buffer is discarded rather than incoming data,
// so that the overall audio synchronization is better.
#ifndef DYNAMIC_BUFFER_LIMITING
if((data+nSamples > size) && !timeStretchEnabled)
if( free < nSamples )
{
// Buffer overrun!
// Dump samples from the read portion of the buffer instead of dropping
// the newly written stuff.
// Toss half the buffer plus whatever's being written anew:
s32 comp = (size / 2) + nSamples;
comp = (comp + 128) & ~127; // probably not important but it makes the log look nicer. :P
if( comp > size ) comp = size;
s32 comp = GetAlignedBufferSize( (size + nSamples ) / 2 );
if( comp > (size-SndOutPacketSize) ) comp = size-SndOutPacketSize;
if( timeStretchEnabled )
{
// If we overran it means the timestretcher failed. We need to speed
// up audio playback.
cTempo += cTempo * 1.5f;
if( cTempo > 5.0f ) cTempo = 5.0f;
pSoundTouch->setTempo( cTempo );
}
data-=comp;
rpos=(rpos+comp)%size;
timeStretchEnabled = true;
ConLog(" * SPU2 > Overrun Compensation (%d samples tossed)\n", size );
ConLog(" * SPU2 Timestretch: ENABLED\n");
if( MsgOverruns() )
ConLog(" * SPU2 > Overrun Compensation (%d packets tossed)\n", comp / SndOutPacketSize );
lastPct = 0.0; // normalize the timestretcher
}
while(data<size && nSamples>0)
// copy in two phases, since there's a chance the packet
// wraps around the buffer (it'd be nice to deal in packets only, but
// the timestretcher and DSP options require flexibility).
const int endPos = wpos + nSamples;
const int secondCopyLen = endPos - size;
s32* wposbuffer = &buffer[wpos];
data += nSamples;
if( secondCopyLen > 0 )
{
buffer[wpos] = *(bData++);
wpos=(wpos+1)%size;
data++;
nSamples--;
nSamples -= secondCopyLen;
memcpy( buffer, &bData[nSamples], secondCopyLen * sizeof( *bData ) );
wpos = secondCopyLen;
}
else
wpos += nSamples;
#elif defined( DYNAMIC_BUFFER_LIMITING )
while(nSamples>0)
{
buffer[wpos] = *(bData++);
wpos=(wpos+1)%size;
data++;
nSamples--;
}
if(data>size)
{
do {
data-=size;
}
while(data>size);
overflows++;
}
#endif
memcpy( wposbuffer, bData, nSamples * sizeof( *bData ) );
LeaveCriticalSection(&cs);
}
virtual void ReadSamples (s32 *bData, s32 nSamples)
protected:
// Returns TRUE if there is data to be output, or false if no data
// is available to be copied.
bool CheckUnderrunStatus( int& nSamples, int& quietSampleCount )
{
static bool underrun_freeze = false;
quietSampleCount = 0;
if( data < nSamples )
{
nSamples = data;
quietSampleCount = SndOutPacketSize - data;
underrun_freeze = true;
if( timeStretchEnabled )
{
// timeStretcher failed it's job. We need to slow down the audio some.
cTempo -= (cTempo * 0.25f);
if( cTempo < 0.2f ) cTempo = 0.2f;
pSoundTouch->setTempo( cTempo );
}
return nSamples != 0;
}
else if( underrun_freeze )
{
int toFill = (int)(size * ( timeStretchEnabled ? 0.45 : 0.70 ) );
toFill = GetAlignedBufferSize( toFill );
// toFill is now aligned to a SndOutPacket
if( data < toFill )
{
quietSampleCount = nSamples;
return false;
}
underrun_freeze = false;
if( MsgOverruns() )
ConLog(" * SPU2 > Underrun compensation (%d packets buffered)\n", toFill / SndOutPacketSize );
lastPct = 0.0; // normalize timestretcher
}
return true;
}
public:
void ReadSamples( s16* bData )
{
int nSamples = SndOutPacketSize;
EnterCriticalSection(&cs);
dataread+=nSamples;
// Problem:
// If the SPU2 gets even the least bit out of sync with the SndOut device,
@ -226,269 +294,219 @@ public:
// This will cause one brief hiccup that can never exceed the user's
// set buffer length in duration.
#ifndef DYNAMIC_BUFFER_LIMITING
if( underrun_freeze && !timeStretchEnabled)
int quietSamples;
if( CheckUnderrunStatus( nSamples, quietSamples ) )
{
// Let's fill up 80% of our buffer.
// (I just picked 80% arbitrarily.. there might be a better value)
jASSUME( nSamples <= SndOutPacketSize );
int toFill = (int)(size * 0.80);
toFill = (toFill + 128) & ~127; // probably not important but it makes the log look nicer. :P
// [Air] [TODO]: This loop is probably a candidiate for SSE2 optimization.
if( data < toFill )
const int endPos = rpos + nSamples;
const int secondCopyLen = endPos - size;
const s32* rposbuffer = &buffer[rpos];
data -= nSamples;
if( secondCopyLen > 0 )
{
while( nSamples>0 )
{
*(bData++) = 0;
nSamples--;
}
LeaveCriticalSection(&cs);
return;
nSamples -= secondCopyLen;
for( int i=0; i<secondCopyLen; i++ )
bData[nSamples+i] = SndScaleVol( buffer[i] );
rpos = secondCopyLen;
}
else
rpos += nSamples;
underrun_freeze = false;
timeStretchEnabled = true;
ConLog(" * SPU2 > Underrun compensation (%d samples buffered)\n", toFill );
ConLog(" * SPU2 Timestretch: ENABLED\n");
}
else underrun_freeze = false;
while(data>0 && nSamples>0)
{
*(bData++) = buffer[rpos];
rpos=(rpos+1)%size;
data--;
nSamples--;
for( int i=0; i<nSamples; i++ )
bData[i] = SndScaleVol( rposbuffer[i] );
}
while( nSamples>0 )
{
// buffer underrun code:
// the contents of this loop only get run if data reached zero
// before nSamples.
// Let's just dull out some silence, because that's usually the least
// painful way of dealing with underruns.
*(bData++) = 0;
nSamples--;
}
if( data == 0 && !pw )
{
underrun_freeze = true;
}
#elif defined( DYNAMIC_BUFFER_LIMITING )
while(nSamples>0)
{
*(bData++) = buffer[rpos];
rpos=(rpos+1)%size;
data--;
nSamples--;
}
if(data<0)
{
do
{
data+=buffer_limit;
}
while(data<0);
underflows++;
}
#else
bool uflow = false;
while(data<0)
{
data+=size;
uflow = true;
}
#endif
PulseEvent(hSyncEvent);
#ifdef DYNAMIC_BUFFER_LIMITING
// will never have BOTH overflows and write waits ;)
while((overflows>0)&&(underflows>0))
{ overflows--; underflows--; }
while((writewaits>0)&&(underflows>0))
{ writewaits--; underflows--; }
int t=buffer_limit;
if(underflows>0)
{
if(buffer_limit<size)
{
buffer_limit=min(size,buffer_limit*2);
underflows=0;
}
if(underflows>3) underflows=3;
}
if(writewaits>0)
{
if(buffer_limit>(3*CurBufferSize))
{
buffer_limit=max(3*CurBufferSize,buffer_limit*3/4);
writewaits=0;
}
if(writewaits>10) writewaits=10;
}
if(overflows>0)
{
if(buffer_limit>(3*CurBufferSize))
{
buffer_limit=max(3*CurBufferSize,buffer_limit*3/4);
overflows=0;
}
if(overflows>3) overflows=3;
}
//printf(" ** SPU2 Dynamic limiter update: Buffer limit set to %d\n",buffer_limit);
#endif
// If quietSamples != 0 it means we have an underrun...
// Let's just dull out some silence, because that's usually the least
// painful way of dealing with underruns:
memset( bData, 0, quietSamples * sizeof(*bData) );
SetEvent( hSyncEvent );
LeaveCriticalSection(&cs);
}
void ReadSamples( s32* bData )
{
int nSamples = SndOutPacketSize;
EnterCriticalSection(&cs);
// 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 ) )
{
// nSamples is garaunteed non-zero if CheckUnderrunStatus
// returned true.
const int endPos = rpos + nSamples;
const int secondCopyLen = endPos - size;
const int oldrpos = rpos;
data -= nSamples;
if( secondCopyLen > 0 )
{
nSamples -= secondCopyLen;
memcpy( &bData[nSamples], buffer, secondCopyLen * sizeof( *bData ) );
rpos = secondCopyLen;
}
else
rpos += nSamples;
memcpy( bData, &buffer[oldrpos], nSamples * sizeof( *bData ) );
}
// If quietSamples != 0 it means we have an underrun...
// Let's just dull out some silence, because that's usually the least
// painful way of dealing with underruns:
memset( bData, 0, quietSamples * sizeof(*bData) );
PulseEvent(hSyncEvent);
LeaveCriticalSection(&cs);
}
void PredictDataWrite( int samples )
{
predictData += samples;
}
virtual void PauseOnWrite(bool doPause) { pw = doPause; }
virtual s32 GetBufferUsage()
{
return data;
}
virtual s32 GetBufferSize()
{
return size;
}
bool GetStats(u32 &w, u32 &r, bool reset)
// Calculate the buffer status percentage.
// Returns range from -1.0 to 1.0
// 1.0 = buffer overflow!
// 0.0 = buffer nominal (50% full)
// -1.0 = buffer underflow!
double GetStatusPct()
{
EnterCriticalSection(&cs);
w = datawritten;
r = dataread;
if(reset) { datawritten=dataread=0; }
// 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;
double result = (data + predictData - drvempty) - (size/2);
result /= (size/2);
LeaveCriticalSection(&cs);
return true;
return result;
}
} *sndBuffer;
};
SndBufferImpl *sndBuffer;
s32* sndTempBuffer;
s32 sndTempProgress;
s32 sndTempSize;
s16* sndTempBuffer16;
float* sndTempBufferFloat;
s32 buffersize=0;
soundtouch::SoundTouch* pSoundTouch=NULL;
u32 inputSamples=0;
u32 oldWritten=0;
u32 oldRead=0;
u32 oldInput=0;
float valAccum1 = 1.0f;
float valAccum2 = 1.0f;
u32 numAccum = 1;
const u32 numUpdates = 160;
float lastTempo=1;
float cTempo=1;
//float* sndTempBufferFloat;
void ResetTempoChange()
{
u32 cWritten;
u32 cRead;
u32 cInput = inputSamples;
sndBuffer->GetStats(cWritten,cRead,false);
oldWritten=cWritten;
oldRead=cRead;
oldInput=cInput;
pSoundTouch->setTempo(1);
}
void UpdateTempoChange()
{
u32 cWritten;
u32 cRead;
u32 cInput = inputSamples;
static short int runs =0;
double statusPct = sndBuffer->GetStatusPct();
double pctChange = statusPct - lastPct;
s32 bufferUsage = sndBuffer->GetBufferUsage();
s32 bufferSize = sndBuffer->GetBufferSize();
//Emergency stretch to compensate for FPS fluctuations and keep the buffers happy
bool a=(bufferUsage < CurBufferSize * 4);
bool b=(bufferUsage >= (bufferSize - CurBufferSize * 4));
double tempoChange;
if(a!=b)
// We have two factors.
// * Distance from nominal buffer status (50% full)
// * The change from previous update to this update.
// The most important factor is the change from update to update.
// But the synchronization between emulator, mixer, and audio driver
// is rarely consistent so drifting away from nominal buffer status (50%)
// is inevitable. So we need to use the nominal buffer status to
// help temper things.
double relation = statusPct / pctChange;
if( relation < 0.0 )
{
if (bufferUsage < CurBufferSize * 2) { cTempo*=0.80f; }
else if(bufferUsage < CurBufferSize * 3) { cTempo*=0.90f; }
else if(bufferUsage < CurBufferSize * 4) { cTempo*=0.96f; }
if (bufferUsage > (bufferSize - CurBufferSize * 2)) { cTempo*=1.20f; }
else if(bufferUsage > (bufferSize - CurBufferSize * 3)) { cTempo*=1.10f; }
else if(bufferUsage >= (bufferSize - CurBufferSize * 4)) { cTempo*=1.04f; }
if (cTempo != lastTempo) {
pSoundTouch->setTempo(cTempo);
}
// The buffer is already shrinking toward
// nominal value, so let's not do "too much"
// We only want to adjust if the shrink rate seems too fast
// or slow compared to our distance from nominal (50%).
tempoChange = ( pow( statusPct, 3.0 ) * 0.33 ) + pctChange * 0.23;
}
else
{
cTempo = cTempo * 0.9f + lastTempo * 0.1f;
tempoChange = pctChange * 0.30;
// 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 formula does that.
// Constants:
// Weight - weights the statusPct's "emergency" consideration.
// higher values here will make the buffer perform more drastic
// compensations.
// 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.
const double weight = 1.55;
const double range = 0.12;
double nominalAdjust = (statusPct * 0.10) + ( pow( statusPct*weight, 3.0 ) * range);
tempoChange = tempoChange + nominalAdjust;
}
//////////////////////////////////////////////////////////////////////////////
sndBuffer->GetStats(cWritten,cRead,false);
valAccum1 += (cRead-oldRead);
valAccum2 += (cInput-oldInput);
numAccum++;
oldRead = cRead;
oldInput = cInput;
// Threshold - Ignore small values between -.005 and +.005.
// We don't need to "pollute" our timestretcher with pointless
// tempo change overhead.
if( abs( tempoChange ) < 0.005 ) return;
//normal stretch, scales sound to game speed
if(numAccum >= numUpdates)
lastPct = statusPct;
// Apply tempoChange as a scale of cTempo. That way the effect is proportional
// to the current tempo. (otherwise tempos would change too slowly/quickly at the extremes)
cTempo += (float)( tempoChange * cTempo );
if( statusPct < -0.20 || statusPct > 0.20 || cTempo < 0.980 || cTempo > 1.020 )
{
float valAccum = 1.0f;
valAccum = valAccum2 / valAccum1;
if( cTempo < 0.20f ) cTempo = 0.20f;
else if( cTempo > 5.0f ) cTempo = 5.0f;
pSoundTouch->setTempo( cTempo );
ts_stats_stretchblocks++;
if((valAccum < 1.04f) && (valAccum > 0.96f) /*&& (valAccum != 1)*/)
{
valAccum = 1.0f;
}
if (valAccum != lastTempo) //only update soundtouch object when needed
pSoundTouch->setTempo(valAccum);
lastTempo = valAccum;
cTempo = valAccum;
if (lastTempo == 1) {
runs++;
if (runs == 5) {
timeStretchEnabled = false;
ConLog( " * SPU2 Timestretch: DISABLED > tempo = %f\n",lastTempo);
runs = 0;
}
}
else runs = 0;
valAccum1 = 1.0f;
valAccum2 = 1.0f;
numAccum = 0;
ConLog(" %s * SPU2: TempoChange by %d%% (tempo: %d%%) (buffer: %d%%)\n",
(relation < 0.0) ? "Normalize" : "",
(int)(tempoChange * 100.0), (int)(cTempo * 100.0),
(int)(statusPct * 100.0)
);
}
else
{
// Nominal operation -- turn off stretching.
pSoundTouch->setTempo( 1.0f );
ts_stats_normalblocks++;
}
}
void soundtouchInit() {
pSoundTouch = new soundtouch::SoundTouch();
pSoundTouch->setSampleRate(SampleRate);
@ -500,18 +518,22 @@ void soundtouchInit() {
s32 SndInit()
{
if(OutputModule>=mods_count)
return -1;
if( mods[OutputModule] == NULL )
{
// force us to the NullOut module if nothing assigned.
OutputModule = FindOutputModuleById( NullOut.GetIdent() );
}
// initialize sound buffer
sndBuffer = new SndBufferImpl(CurBufferSize * MaxBufferCount * 2);
sndTempSize = 512;
// Buffer actually attempts to run ~50%, so allocate near double what
// the requested latency is:
sndBuffer = new SndBufferImpl( SndOutLatencyMS * 1.75 );
sndTempProgress = 0;
sndTempBuffer = new s32[sndTempSize];
sndTempBuffer16 = new s16[sndTempSize];
sndTempBufferFloat = new float[sndTempSize];
buffersize=sndBuffer->GetBufferSize();
sndTempBuffer = new s32[SndOutPacketSize];
sndTempBuffer16 = new s16[SndOutPacketSize];
//sndTempBufferFloat = new float[sndTempSize];
cTempo = 1.0;
soundtouchInit();
ResetTempoChange();
@ -530,15 +552,11 @@ s32 SndInit()
void SndClose()
{
if(OutputModule>=mods_count)
return;
mods[OutputModule]->Close();
delete sndBuffer;
delete sndTempBuffer;
delete sndTempBuffer16;
delete sndTempBufferFloat;
delete pSoundTouch;
}
@ -560,88 +578,108 @@ void SndUpdateLimitMode()
}
bool SndGetStats(u32 *written, u32 *played)
{
return sndBuffer->GetStats(*written,*played,false);
}
s32 SndWrite(s32 ValL, s32 ValR)
{
if(WaveLog && wavedump_ok)
#ifndef PUBLIC
if(WaveLog() && wavedump_ok)
{
wavedump_write(ValL>>8,ValR>>8);
wavedump_write(SndScaleVol(ValL),SndScaleVol(ValR));
}
#endif
if(recording!=0)
RecordWrite(ValL>>8,ValR>>8);
if(OutputModule>=mods_count)
return -1;
RecordWrite(SndScaleVol(ValL),SndScaleVol(ValR));
if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p
return 0;
inputSamples+=2;
//inputSamples+=2;
sndTempBuffer[sndTempProgress++] = ValL;
sndTempBuffer[sndTempProgress++] = ValR;
if(sndTempProgress>=sndTempSize)
// If we haven't accumulated a full packet yet, do nothing more:
if(sndTempProgress < SndOutPacketSize) return 1;
if(dspPluginEnabled)
{
if(dspPluginEnabled)
for(int i=0;i<SndOutPacketSize;i++) { sndTempBuffer16[i] = SndScaleVol( sndTempBuffer[i] ); }
// send to winamp DSP
sndTempProgress = DspProcess(sndTempBuffer16,sndTempProgress>>1)<<1;
for(int i=0;i<sndTempProgress;i++) { sndTempBuffer[i] = sndTempBuffer16[i]<<SndOutVolumeShift; }
}
static int equalized = 0;
if(timeStretchEnabled)
{
bool progress = false;
// data prediction helps keep the tempo adjustments more accurate.
sndBuffer->PredictDataWrite( (int)( sndTempProgress / cTempo ) );
for(int i=0;i<sndTempProgress;i++) { ((float*)sndTempBuffer)[i] = sndTempBuffer[i]/2147483648.0f; }
pSoundTouch->putSamples((float*)sndTempBuffer, sndTempProgress>>1);
while( ( sndTempProgress = pSoundTouch->receiveSamples((float*)sndTempBuffer, sndTempProgress>>1)<<1 ) != 0 )
{
for(int i=0;i<sndTempProgress;i++) { sndTempBuffer16[i] = sndTempBuffer[i]>>8; }
// send to winamp DSP
sndTempProgress = DspProcess(sndTempBuffer16,sndTempProgress>>1)<<1;
for(int i=0;i<sndTempProgress;i++) { sndTempBuffer[i] = sndTempBuffer16[i]<<8; }
}
if(timeStretchEnabled)
{
for(int i=0;i<sndTempProgress;i++) { sndTempBufferFloat[i] = sndTempBuffer[i]/2147483648.0f; }
// send to timestretcher
pSoundTouch->putSamples(sndTempBufferFloat, sndTempProgress>>1);
UpdateTempoChange();
do
// 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. That's
// why we only update the tempo below after a set of blocks has been
// released (otherwise the tempo rates will be skewed by backlogged data)
// [Air] [TODO] : Implement an SSE downsampler to int.
for(int i=0;i<sndTempProgress;i++)
{
sndTempProgress = pSoundTouch->receiveSamples(sndTempBufferFloat, sndTempSize>>1)<<1;
if(sndTempProgress>0)
{
for(int i=0;i<sndTempProgress;i++) { sndTempBuffer[i] = (s32)(sndTempBufferFloat[i]*2147483648.0f); }
sndBuffer->WriteSamples(sndTempBuffer,sndTempProgress);
}
} while (sndTempProgress != 0 );
sndTempBuffer[i] = (s32)(((float*)sndTempBuffer)[i]*2147483648.0f);
}
sndBuffer->WriteSamples(sndTempBuffer, sndTempProgress);
progress = true;
}
else
if( progress )
{
sndBuffer->WriteSamples(sndTempBuffer,sndTempProgress);
sndTempProgress=0;
UpdateTempoChange();
if( MsgOverruns() )
{
if( ++ts_stats_logcounter > 300 )
{
ts_stats_logcounter = 0;
ConLog( " * SPU2 > Timestretch Stats > %d%% of packets stretched.\n",
( ts_stats_stretchblocks * 100 ) / ( ts_stats_normalblocks + ts_stats_stretchblocks ) );
ts_stats_normalblocks = 0;
ts_stats_stretchblocks = 0;
}
}
}
}
else
{
sndBuffer->WriteSamples(sndTempBuffer, sndTempProgress);
sndTempProgress=0;
}
return 1;
}
s32 SndTest()
{
if(OutputModule>=mods_count)
if( mods[OutputModule] == NULL )
return -1;
return mods[OutputModule]->Test();
}
void SndConfigure(HWND parent)
void SndConfigure(HWND parent, u32 module )
{
if(OutputModule>=mods_count)
if( mods[module] == NULL )
return;
mods[OutputModule]->Configure(parent);
mods[module]->Configure(parent);
}
#if 0

View File

@ -18,12 +18,13 @@
#ifndef SNDOUT_H_INCLUDE
#define SNDOUT_H_INCLUDE
#define OUTPUT_NULL 0
#define OUTPUT_WAVEOUT 1
#define OUTPUT_DSOUND 2
#define OUTPUT_DSOUND51 3
#define OUTPUT_ASIO 4
#define OUTPUT_XAUDIO2 5
// Number of stereo samples per SndOut block.
// All drivers must work in units of this size when communicating with
// SndOut.
static const int SndOutPacketSize = 1024;
static const int SndOutVolumeShiftBase = 14;
extern int SndOutVolumeShift;
#define pcmlog
extern FILE *wavelog;
@ -32,32 +33,46 @@ s32 SndInit();
void SndClose();
s32 SndWrite(s32 ValL, s32 ValR);
s32 SndTest();
void SndConfigure(HWND parent);
void SndConfigure(HWND parent, u32 outmodidx );
bool SndGetStats(u32 *written, u32 *played);
int FindOutputModuleById( const char* omodid );
class SndBuffer
{
public:
virtual ~SndBuffer() {}
virtual void WriteSamples(s32 *buffer, s32 nSamples)=0;
virtual void ReadSamples (s32 *buffer, s32 nSamples)=0;
virtual void WriteSamples(s32 *buffer, int nSamples)=0;
virtual void PauseOnWrite(bool doPause)=0;
virtual s32 GetBufferUsage()=0;
virtual s32 GetBufferSize()=0;
virtual void ReadSamples( s16* bData )=0;
virtual void ReadSamples( s32* bData )=0;
//virtual s32 GetBufferUsage()=0;
//virtual s32 GetBufferSize()=0;
};
class SndOutModule
{
public:
// Returns a unique identification string for this driver.
// (usually just matches the driver's cpp filename)
virtual const char* GetIdent() const=0;
// Returns the long name / description for this driver.
// (for use in configuration screen)
virtual const char* GetLongName() const=0;
virtual s32 Init(SndBuffer *buffer)=0;
virtual void Close()=0;
virtual s32 Test()=0;
virtual s32 Test() const=0;
virtual void Configure(HWND parent)=0;
virtual bool Is51Out() const=0;
virtual bool Is51Out()=0;
// Returns the number of empty samples in the output buffer.
// (which is effectively the amount of data played since the last update)
virtual int GetEmptySampleCount() const=0;
};
//internal
@ -69,6 +84,5 @@ extern SndOutModule *XAudio2Out;
extern SndOutModule *DSound51Out;
extern SndOutModule* mods[];
extern const u32 mods_count;
#endif // SNDOUT_H_INCLUDE

View File

@ -42,6 +42,7 @@ static char *libraryName = "GiGaHeRz's SPU2 ("
#endif
")";
DWORD CALLBACK TimeThread(PVOID /* unused param */);
@ -171,11 +172,12 @@ void __inline __fastcall spu2M_Write( u32 addr, s16 value )
// Make sure the cache is invalidated:
// (note to self : addr address WORDs, not bytes)
addr &= 0xfffff;
const u32 nexta = addr >> 3; // 8 words per encoded block.
const u32 flagbitmask = 1ul<<(nexta & 31); // 31 flags per array entry
pcm_cache_flags[nexta>>5] &= ~flagbitmask;
*GetMemPtr( addr & 0xfffff ) = value;
*GetMemPtr( addr ) = value;
}
// writes an unsigned value to the SPU2 ram
@ -271,7 +273,7 @@ s32 CALLBACK SPU2init()
acumCycles=0;
#ifdef SPU2_LOG
if(AccessLog)
if(AccessLog())
{
spu2Log = fopen(AccessLogFileName, "w");
setvbuf(spu2Log, NULL, _IONBF, 0);
@ -325,7 +327,7 @@ s32 CALLBACK SPU2init()
DMALogOpen();
if(WaveLog)
if(WaveLog())
{
if(!wavedump_open())
{
@ -459,7 +461,7 @@ void CALLBACK SPU2shutdown()
fclose(el0);
fclose(el1);
#endif
if(WaveLog && wavedump_ok) wavedump_close();
if(WaveLog() && wavedump_ok) wavedump_close();
DMALogClose();
@ -477,7 +479,7 @@ void CALLBACK SPU2shutdown()
pcm_cache_data = NULL;
#ifdef SPU2_LOG
if(!AccessLog) return;
if(!AccessLog()) return;
FileLog("[%10d] SPU2shutdown\n",Cycles);
if(spu2Log) fclose(spu2Log);
#endif
@ -1895,7 +1897,7 @@ void VoiceStart(int core,int vc)
DebugCores[core].Voices[vc].FirstBlock=1;
if(core==1)
{
if(MsgKeyOnOff) ConLog(" * SPU2: KeyOn: C%dV%02d: SSA: %8x; M: %s%s%s%s; H: %02x%02x; P: %04x V: %04x/%04x; ADSR: %04x%04x\n",
if(MsgKeyOnOff()) ConLog(" * SPU2: KeyOn: C%dV%02d: SSA: %8x; M: %s%s%s%s; H: %02x%02x; P: %04x V: %04x/%04x; ADSR: %04x%04x\n",
core,vc,Cores[core].Voices[vc].StartA,
(Cores[core].Voices[vc].DryL)?"+":"-",(Cores[core].Voices[vc].DryR)?"+":"-",
(Cores[core].Voices[vc].WetL)?"+":"-",(Cores[core].Voices[vc].WetR)?"+":"-",
@ -1944,7 +1946,7 @@ void StopVoices(int core, u32 value)
for (vc=0;vc<24;vc++) {
if ((value>>vc) & 1) {
Cores[core].Voices[vc].ADSR.Releasing=1;
//if(MsgKeyOnOff) ConLog(" * SPU2: KeyOff: Core %d; Voice %d.\n",core,vc);
//if(MsgKeyOnOff()) ConLog(" * SPU2: KeyOff: Core %d; Voice %d.\n",core,vc);
}
}
}

View File

@ -16,21 +16,23 @@
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#include "spu2.h"
#include "dialogs.h"
#include <windows.h>
class WaveOutModule: public SndOutModule
{
private:
# define MAX_BUFFER_COUNT 8
#define MAX_BUFFER_COUNT 5
#define BufferSize (CurBufferSize<<1)
#define BufferSizeBytes (BufferSize<<1)
static const int PacketsPerBuffer = (1024 / SndOutPacketSize);
static const int BufferSize = SndOutPacketSize*PacketsPerBuffer;
static const int BufferSizeBytes = BufferSize << 1;
HWAVEOUT hwodevice;
WAVEFORMATEX wformat;
WAVEHDR whbuffer[MAX_BUFFER_COUNT];
s32* tbuffer;
s16* qbuffer;
#define QBUFFER(x) (qbuffer + BufferSize * (x))
@ -63,14 +65,9 @@ private:
buf->dwBytesRecorded = buf->dwBufferLength;
buff->ReadSamples(tbuffer,BufferSize);
s16 *t = (s16*)buf->lpData;
s32 *s = (s32*)tbuffer;
for(int bleh=0;bleh<BufferSize;bleh++)
{
*(t++) = (s16)((*(s++))>>8);
}
for(int p=0; p<PacketsPerBuffer; p++, t+=SndOutPacketSize )
buff->ReadSamples( t );
whbuffer[i].dwFlags&=~WHDR_DONE;
waveOutWrite(hwodevice,buf,sizeof(WAVEHDR));
@ -94,8 +91,6 @@ public:
if (Test()) return -1;
if(CurBufferSize<1024) CurBufferSize=1024;
wformat.wFormatTag=WAVE_FORMAT_PCM;
wformat.nSamplesPerSec=SampleRate;
wformat.wBitsPerSample=16;
@ -105,7 +100,6 @@ public:
wformat.cbSize=0;
qbuffer=new s16[BufferSize*MAX_BUFFER_COUNT];
tbuffer=new s32[BufferSize];
woores = waveOutOpen(&hwodevice,WAVE_MAPPER,&wformat,0,0,0);
if (woores != MMSYSERR_NOERROR)
@ -161,23 +155,121 @@ public:
}
waveOutClose(hwodevice);
delete tbuffer;
delete qbuffer;
}
private:
virtual void Configure(HWND parent)
static BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
int wmId,wmEvent;
int tSel=0;
switch(uMsg)
{
case WM_INITDIALOG:
char 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);
sprintf_s(temp, 128, "%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 );
if( Config_WaveOut.NumBuffers < 3 ) Config_WaveOut.NumBuffers = 3;
if( Config_WaveOut.NumBuffers > MAX_BUFFER_COUNT ) Config_WaveOut.NumBuffers = MAX_BUFFER_COUNT;
}
EndDialog(hWnd,0);
break;
case IDCANCEL:
EndDialog(hWnd,0);
break;
default:
return FALSE;
}
break;
case WM_HSCROLL:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch(wmId) {
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0);
case TB_THUMBTRACK:
if( wmEvent < 3 ) wmEvent = 3;
if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT;
SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent);
sprintf_s(temp,128,"%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;
}
virtual bool Is51Out() { return false; }
public:
virtual void Configure(HWND parent)
{
INT_PTR ret;
ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_WAVEOUT),GetActiveWindow(),(DLGPROC)ConfigProc,1);
if(ret==-1)
{
MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0);
return;
}
}
s32 Test() {
virtual bool Is51Out() const { return false; }
s32 Test() const
{
if (waveOutGetNumDevs() == 0) {
SysMessage("No waveOut Devices Present\n"); return -1;
}
return 0;
}
int GetEmptySampleCount() const
{
int result = 0;
for(int i=0;i<MAX_BUFFER_COUNT;i++)
{
result += (whbuffer[i].dwFlags & WHDR_DONE) ? BufferSize : 0;
}
return result;
}
const char* GetIdent() const
{
return "waveout";
}
const char* GetLongName() const
{
return "waveOut (Laggy)";
}
} WO;
SndOutModule *WaveOut=&WO;

View File

@ -27,13 +27,11 @@
class XAudio2Mod: public SndOutModule
{
private:
static const int BufferSize = SndOutPacketSize;
static const int BufferSizeBytes = BufferSize * 2;
//#define BufferSize (SndOutPacketSize<<1)
//#define BufferSizeBytes (BufferSize<<1)
//#define PI 3.14159265f
#define BufferSize (CurBufferSize<<1)
#define BufferSizeBytes (BufferSize<<1)
s32* tbuffer;
s16* qbuffer;
s32 out_num;
@ -104,16 +102,9 @@ private:
out_num=(out_num+1)%MAX_BUFFER_COUNT;
XAUDIO2_BUFFER buf = {0};
buff->ReadSamples(tbuffer,BufferSize);
buff->ReadSamples(qb);
buf.AudioBytes = BufferSizeBytes;
s16 *t = qb;
s32 *s = (s32*)tbuffer;
for(int i=0;i<BufferSize;i++)
{
*(t++) = (s16)((*(s++))>>8);
}
buf.pAudioData=(const BYTE*)qb;
pSourceVoice->SubmitSourceBuffer( &buf );
@ -161,7 +152,7 @@ public:
wfx.nChannels=2;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = 2*2;
wfx.nAvgBytesPerSec = SampleRate * 2 * 2;
wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign;
wfx.cbSize=0;
//
@ -175,9 +166,9 @@ public:
}
pSourceVoice->Start( 0, 0 );
tbuffer = new s32[BufferSize];
//tbuffer = new s32[BufferSize];
qbuffer = new s16[BufferSize*MAX_BUFFER_COUNT];
ZeroMemory(qbuffer,BufferSize*MAX_BUFFER_COUNT);
ZeroMemory(qbuffer,BufferSize*MAX_BUFFER_COUNT*2);
// Start Thread
xaudio2_running=true;
@ -218,20 +209,34 @@ public:
SAFE_RELEASE( pXAudio2 );
CoUninitialize();
delete tbuffer;
}
virtual void Configure(HWND parent)
{
}
virtual bool Is51Out() { return false; }
virtual bool Is51Out() const { return false; }
s32 Test()
s32 Test() const
{
return 0;
}
int GetEmptySampleCount() const
{
return 0;
}
const char* GetIdent() const
{
return "xaudio2";
}
const char* GetLongName() const
{
return "XAudio 2 (Experimental)";
}
} XA2;
SndOutModule *XAudio2Out=&XA2;