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

View File

@ -36,8 +36,9 @@ private:
#ifndef __WIN64__ #ifndef __WIN64__
#define BufferSize (CurBufferSize<<1) // [Air] : This needs fixed.
#define BufferSizeBytes (BufferSize<<2) static const int BufferSize = SndOutPacketSize;
static const int BufferSizeBytes = BufferSize << 2;
s32* asio_lbuffer; s32* asio_lbuffer;
@ -175,7 +176,7 @@ private:
#define DBL(t) ((t*)(asioDriverInfo.bufferInfos[0].buffers[index])) #define DBL(t) ((t*)(asioDriverInfo.bufferInfos[0].buffers[index]))
#define DBR(t) ((t*)(asioDriverInfo.bufferInfos[1].buffers[index])) #define DBR(t) ((t*)(asioDriverInfo.bufferInfos[1].buffers[index]))
int BLen=BufferSize*CurBufferCount; int BLen=BufferSize*Config_Asio.NumBuffers;
int ssize=2; int ssize=2;
if(showBufferInfo) if(showBufferInfo)
@ -241,7 +242,11 @@ private:
bufferInfoReady=true; 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; s32 asio_read_num = 0;
// perform the processing // perform the processing
@ -586,7 +591,7 @@ public:
for(int i=0;i<driverMax;i++) for(int i=0;i<driverMax;i++)
{ {
ConLog(" *** %u - %s\n",i+1,driverNames[i]); ConLog(" *** %u - %s\n",i+1,driverNames[i]);
if(stricmp(driverNames[i],AsioDriver)==0) if(_stricmp(driverNames[i],AsioDriver)==0)
{ {
selected=i+1; selected=i+1;
break; break;
@ -670,9 +675,9 @@ public:
{ {
} }
virtual bool Is51Out() { return false; } virtual bool Is51Out() const { return false; }
s32 Test() s32 Test() const
{ {
#ifndef __WIN64__ #ifndef __WIN64__
if(asioDrivers->asioGetNumDev()>0) if(asioDrivers->asioGetNumDev()>0)
@ -680,6 +685,22 @@ public:
#endif #endif
return -1; return -1;
} }
int GetEmptySampleCount() const
{
return 0;
}
const char* GetIdent() const
{
return "asio";
}
const char* GetLongName() const
{
return "ASIO (BROKEN)";
}
} ASIOMod; } ASIOMod;
SndOutModule *ASIOOut=&ASIOMod; SndOutModule *ASIOOut=&ASIOMod;

View File

@ -20,22 +20,31 @@
#include "dialogs.h" #include "dialogs.h"
// Config Vars // Config Vars
static bool VolumeBoostEnabled = false;
static int VolumeShiftModifier = 0;
// DEBUG // DEBUG
bool DebugEnabled=false; bool DebugEnabled=false;
bool MsgToConsole=false; bool _MsgToConsole=false;
bool MsgKeyOnOff=false; bool _MsgKeyOnOff=false;
bool MsgVoiceOff=false; bool _MsgVoiceOff=false;
bool MsgDMA=false; bool _MsgDMA=false;
bool MsgAutoDMA=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 AccessLogFileName[255];
char WaveLogFileName[255]; char WaveLogFileName[255];
@ -59,19 +68,20 @@ int Interpolation=1;
2. cubic interpolation 2. cubic interpolation
*/ */
// EFFECTS
bool EffectsEnabled=false; bool EffectsEnabled=false;
// OUTPUT // OUTPUT
int SampleRate=48000; int SampleRate=48000;
int CurBufferSize=1024; int SndOutLatencyMS=60;
int MaxBufferCount=8; //int SndOutLatency=1024;
int CurBufferCount=MaxBufferCount; //int MaxBufferCount=8;
//int CurBufferCount=MaxBufferCount;
bool timeStretchEnabled=false;
int OutputModule=OUTPUT_DSOUND; u32 OutputModule=0; //OUTPUT_DSOUND;
int VolumeMultiplier=1; //int VolumeMultiplier=1;
int VolumeDivisor=1; //int VolumeDivisor=1;
int LimitMode=0; int LimitMode=0;
/* values: /* values:
@ -80,17 +90,14 @@ int LimitMode=0;
2. Hard limiter -- more cpu-intensive while limiting, but should give better (constant) speeds 2. Hard limiter -- more cpu-intensive while limiting, but should give better (constant) speeds
*/ */
u32 GainL =256;
u32 GainR =256; CONFIG_DSOUNDOUT Config_DSoundOut;
u32 GainSL =200; CONFIG_DSOUND51 Config_DSound51;
u32 GainSR =200; CONFIG_WAVEOUT Config_WaveOut;
u32 GainC =200; CONFIG_ASIO Config_Asio;
u32 GainLFE=256;
u32 AddCLR = 56;
u32 LowpassLFE=80;
// MISC // MISC
bool LimiterToggleEnabled=true; bool LimiterToggleEnabled=false;
int LimiterToggle=VK_SUBTRACT; int LimiterToggle=VK_SUBTRACT;
// DSP // DSP
@ -98,19 +105,15 @@ bool dspPluginEnabled=false;
char dspPlugin[256]; char dspPlugin[256];
int dspPluginModule=0; int dspPluginModule=0;
bool timeStretchEnabled=false;
// OUTPUT MODULES // OUTPUT MODULES
char AsioDriver[129]=""; 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: |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*\ /*| 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"; char *Data=Value?"TRUE":"FALSE";
WritePrivateProfileString(Section,Name,Data,CfgFile); 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]; char Data[255];
_itoa(Value,Data,10); _itoa(Value,Data,10);
WritePrivateProfileString(Section,Name,Data,CfgFile); 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); 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]=""; char Data[255]="";
GetPrivateProfileString(Section,Name,"",Data,255,CfgFile); GetPrivateProfileString(Section,Name,"",Data,255,CfgFile);
Data[254]=0; Data[254]=0;
@ -164,7 +167,8 @@ bool CfgReadBool(char *Section,char *Name,bool Default) {
return false; return false;
} }
int CfgReadInt(char *Section, char*Name,int Default) {
int CfgReadInt(const char *Section, const char*Name,int Default) {
char Data[255]=""; char Data[255]="";
GetPrivateProfileString(Section,Name,"",Data,255,CfgFile); GetPrivateProfileString(Section,Name,"",Data,255,CfgFile);
Data[254]=0; Data[254]=0;
@ -177,7 +181,8 @@ int CfgReadInt(char *Section, char*Name,int Default) {
return atoi(Data); 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; int sl;
GetPrivateProfileString(Section,Name,"",Data,DataSize,CfgFile); 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() void ReadSettings()
{ {
DebugEnabled=CfgReadBool("DEBUG","Global_Debug_Enabled",0); DebugEnabled=CfgReadBool("DEBUG","Global_Debug_Enabled",0);
MsgToConsole=DebugEnabled&CfgReadBool("DEBUG","Show_Messages",0); _MsgToConsole=CfgReadBool("DEBUG","Show_Messages",0);
MsgKeyOnOff =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_Key_On_Off",0); _MsgKeyOnOff =CfgReadBool("DEBUG","Show_Messages_Key_On_Off",0);
MsgVoiceOff =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_Voice_Off",0); _MsgVoiceOff =CfgReadBool("DEBUG","Show_Messages_Voice_Off",0);
MsgDMA =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_DMA_Transfer",0); _MsgDMA =CfgReadBool("DEBUG","Show_Messages_DMA_Transfer",0);
MsgAutoDMA =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_AutoDMA",0); _MsgAutoDMA =CfgReadBool("DEBUG","Show_Messages_AutoDMA",0);
AccessLog =DebugEnabled&CfgReadBool("DEBUG","Log_Register_Access",0); _MsgOverruns =CfgReadBool("DEBUG","Show_Messages_Overruns",0);
DMALog =DebugEnabled&CfgReadBool("DEBUG","Log_DMA_Transfers",0); _MsgCache =CfgReadBool("DEBUG","Show_Messages_CacheStats",0);
WaveLog =DebugEnabled&CfgReadBool("DEBUG","Log_WAVE_Output",0);
CoresDump =DebugEnabled&CfgReadBool("DEBUG","Dump_Info",0); _AccessLog =CfgReadBool("DEBUG","Log_Register_Access",0);
MemDump =DebugEnabled&CfgReadBool("DEBUG","Dump_Memory",0); _DMALog =CfgReadBool("DEBUG","Log_DMA_Transfers",0);
RegDump =DebugEnabled&CfgReadBool("DEBUG","Dump_Regs",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","Access_Log_Filename",AccessLogFileName,255,"logs\\SPU2Log.txt");
CfgReadStr("DEBUG","WaveLog_Filename", WaveLogFileName, 255,"logs\\SPU2log.wav"); CfgReadStr("DEBUG","WaveLog_Filename", WaveLogFileName, 255,"logs\\SPU2log.wav");
@ -219,54 +238,81 @@ void ReadSettings()
WaveDumpFormat=CfgReadInt("DEBUG","Wave_Log_Format",0); WaveDumpFormat=CfgReadInt("DEBUG","Wave_Log_Format",0);
Interpolation=CfgReadInt("MIXING","Interpolation",1);
AutoDMAPlayRate[0]=CfgReadInt("MIXING","AutoDMA_Play_Rate_0",0); AutoDMAPlayRate[0]=CfgReadInt("MIXING","AutoDMA_Play_Rate_0",0);
AutoDMAPlayRate[1]=CfgReadInt("MIXING","AutoDMA_Play_Rate_1",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); SampleRate=CfgReadInt("OUTPUT","Sample_Rate",48000);
SndOutLatencyMS=CfgReadInt("OUTPUT","Latency",120);
CurBufferSize=CfgReadInt("OUTPUT","Buffer_Size",1024); //OutputModule = CfgReadInt("OUTPUT","Output_Module", OUTPUT_DSOUND );
MaxBufferCount=CfgReadInt("OUTPUT","Buffer_Count",10); char omodid[128];
if(MaxBufferCount<3) MaxBufferCount=3; CfgReadStr( "OUTPUT", "Output_Module", omodid, 127, DSoundOut->GetIdent() );
CurBufferCount=MaxBufferCount;
OutputModule=CfgReadInt("OUTPUT","Output_Module",OUTPUT_DSOUND); // find the driver index of this module:
OutputModule = FindOutputModuleById( omodid );
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);
VolumeShiftModifier = CfgReadInt( "OUTPUT","Volume_Shift", 0 );
LimitMode=CfgReadInt("OUTPUT","Speed_Limit_Mode",0); LimitMode=CfgReadInt("OUTPUT","Speed_Limit_Mode",0);
CfgReadStr("OUTPUT","Asio_Driver_Name",AsioDriver,128,"");
CfgReadStr("DSP PLUGIN","Filename",dspPlugin,255,""); CfgReadStr("DSP PLUGIN","Filename",dspPlugin,255,"");
dspPluginModule = CfgReadInt("DSP PLUGIN","ModuleNum",0); dspPluginModule = CfgReadInt("DSP PLUGIN","ModuleNum",0);
dspPluginEnabled= CfgReadBool("DSP PLUGIN","Enabled",false); 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); LimiterToggleEnabled = CfgReadBool("KEYS","Limiter_Toggle_Enabled",false);
LimiterToggle = CfgReadInt ("KEYS","Limiter_Toggle",VK_SUBTRACT); 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; // Read DSOUND51 config:
else if(VolumeMultiplier==0) VolumeMultiplier=1; 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); CfgWriteBool("DEBUG","Global_Debug_Enabled",DebugEnabled);
if(DebugEnabled) { // [Air] : Commented out so that we retain debug settings even if disabled...
CfgWriteBool("DEBUG","Show_Messages", MsgToConsole); //if(DebugEnabled)
CfgWriteBool("DEBUG","Show_Messages_Key_On_Off", MsgKeyOnOff); {
CfgWriteBool("DEBUG","Show_Messages_Voice_Off", MsgVoiceOff); CfgWriteBool("DEBUG","Show_Messages", _MsgToConsole);
CfgWriteBool("DEBUG","Show_Messages_DMA_Transfer",MsgDMA); CfgWriteBool("DEBUG","Show_Messages_Key_On_Off", _MsgKeyOnOff);
CfgWriteBool("DEBUG","Show_Messages_AutoDMA", MsgAutoDMA); 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_Register_Access",_AccessLog);
CfgWriteBool("DEBUG","Log_DMA_Transfers", DMALog); CfgWriteBool("DEBUG","Log_DMA_Transfers", _DMALog);
CfgWriteBool("DEBUG","Log_WAVE_Output", WaveLog); CfgWriteBool("DEBUG","Log_WAVE_Output", _WaveLog);
CfgWriteBool("DEBUG","Dump_Info", CoresDump); CfgWriteBool("DEBUG","Dump_Info", _CoresDump);
CfgWriteBool("DEBUG","Dump_Memory",MemDump); CfgWriteBool("DEBUG","Dump_Memory",_MemDump);
CfgWriteBool("DEBUG","Dump_Regs", RegDump); CfgWriteBool("DEBUG","Dump_Regs", _RegDump);
CfgWriteStr("DEBUG","Access_Log_Filename",AccessLogFileName); CfgWriteStr("DEBUG","Access_Log_Filename",AccessLogFileName);
CfgWriteStr("DEBUG","WaveLog_Filename", WaveLogFileName); CfgWriteStr("DEBUG","WaveLog_Filename", WaveLogFileName);
@ -308,67 +358,83 @@ void WriteSettings()
CfgWriteInt("MIXING","AutoDMA_Play_Rate_0",AutoDMAPlayRate[0]); CfgWriteInt("MIXING","AutoDMA_Play_Rate_0",AutoDMAPlayRate[0]);
CfgWriteInt("MIXING","AutoDMA_Play_Rate_1",AutoDMAPlayRate[1]); 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","Sample_Rate",SampleRate);
CfgWriteInt("OUTPUT","Buffer_Size",CurBufferSize); CfgWriteInt("OUTPUT","Latency",SndOutLatencyMS);
CfgWriteInt("OUTPUT","Buffer_Count",MaxBufferCount); CfgWriteBool("OUTPUT","Timestretch_Enable",timeStretchEnabled);
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","Speed_Limit_Mode",LimitMode); 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); CfgWriteStr("DSP PLUGIN","Filename",dspPlugin);
CfgWriteInt("DSP PLUGIN","ModuleNum",dspPluginModule); CfgWriteInt("DSP PLUGIN","ModuleNum",dspPluginModule);
CfgWriteBool("DSP PLUGIN","Enabled",dspPluginEnabled); CfgWriteBool("DSP PLUGIN","Enabled",dspPluginEnabled);
CfgWriteBool("DSP","Timestretch_Enable",timeStretchEnabled);
CfgWriteBool("KEYS","Limiter_Toggle_Enabled",LimiterToggleEnabled); CfgWriteBool("KEYS","Limiter_Toggle_Enabled",LimiterToggleEnabled);
CfgWriteInt ("KEYS","Limiter_Toggle",LimiterToggle); 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) BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{ {
int wmId,wmEvent; 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) switch(uMsg)
{ {
case WM_PAINT: 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; return FALSE;
case WM_INITDIALOG: 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_RESETCONTENT,0,0);
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"16000"); SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"16000");
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"22050"); 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)"44100");
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"48000"); 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); SetDlgItemText(hWnd,IDC_SRATE,temp);
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_RESETCONTENT,0,0); 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)"0 - Nearest (none/fast)");
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"1 - Linear (mid)"); SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"1 - Linear (recommended)");
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"2 - Cubic (good)"); 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_INTERPOLATE),CB_SETCURSEL,Interpolation,0);
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_RESETCONTENT,0,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)"); int modidx = 0;
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"3 - DSound 5.1 (Experimental)"); while( mods[modidx] != NULL )
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)"); 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); 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); SendMessage(GetDlgItem(hWnd,IDC_LATENCY_SLIDER),TBM_SETPOS,TRUE,SndOutLatencyMS);
sprintf(temp,"%d",CurBufferSize); sprintf_s(temp,80,"%d ms (avg)",SndOutLatencyMS);
SetWindowText(GetDlgItem(hWnd,IDC_BSIZE),temp); SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp);
sprintf(temp,"%d",MaxBufferCount); EnableDebugControls( hWnd );
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);
// Debugging / Logging Flags:
SET_CHECK(IDC_EFFECTS, EffectsEnabled); SET_CHECK(IDC_EFFECTS, EffectsEnabled);
SET_CHECK(IDC_DEBUG, DebugEnabled); SET_CHECK(IDC_DEBUG, DebugEnabled);
SET_CHECK(IDC_MSGSHOW, MsgToConsole); SET_CHECK(IDC_MSGKEY, _MsgToConsole);
SET_CHECK(IDC_MSGKEY, MsgKeyOnOff); SET_CHECK(IDC_MSGKEY, _MsgKeyOnOff);
SET_CHECK(IDC_MSGVOICE,MsgVoiceOff); SET_CHECK(IDC_MSGVOICE,_MsgVoiceOff);
SET_CHECK(IDC_MSGDMA, MsgDMA); SET_CHECK(IDC_MSGDMA, _MsgDMA);
SET_CHECK(IDC_MSGADMA, MsgAutoDMA); SET_CHECK(IDC_MSGADMA, _MsgAutoDMA);
SET_CHECK(IDC_LOGREGS, AccessLog); SET_CHECK(IDC_DBG_OVERRUNS, _MsgOverruns );
SET_CHECK(IDC_LOGDMA, DMALog); SET_CHECK(IDC_DBG_CACHE, _MsgCache );
SET_CHECK(IDC_LOGWAVE, WaveLog); SET_CHECK(IDC_LOGREGS, _AccessLog);
SET_CHECK(IDC_DUMPCORE,CoresDump); SET_CHECK(IDC_LOGDMA, _DMALog);
SET_CHECK(IDC_DUMPMEM, MemDump); SET_CHECK(IDC_LOGWAVE, _WaveLog);
SET_CHECK(IDC_DUMPREGS,RegDump); SET_CHECK(IDC_DUMPCORE,_CoresDump);
SET_CHECK(IDC_DUMPMEM, _MemDump);
SET_CHECK(IDC_DUMPREGS,_RegDump);
SET_CHECK(IDC_SPEEDLIMIT,LimitMode); SET_CHECK(IDC_SPEEDLIMIT,LimitMode);
SET_CHECK(IDC_SPEEDLIMIT_RUNTIME_TOGGLE,LimiterToggleEnabled);
SET_CHECK(IDC_DSP_ENABLE,dspPluginEnabled); SET_CHECK(IDC_DSP_ENABLE,dspPluginEnabled);
SET_CHECK(IDC_TS_ENABLE,timeStretchEnabled); SET_CHECK(IDC_TS_ENABLE,timeStretchEnabled);
VolumeBoostEnabled = ( VolumeShiftModifier > 0 ) ? true : false;
SET_CHECK(IDC_VOLBOOST, VolumeBoostEnabled );
break; break;
case WM_COMMAND: case WM_COMMAND:
wmId = LOWORD(wParam); wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam); wmEvent = HIWORD(wParam);
@ -444,49 +512,14 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
temp[19]=0; temp[19]=0;
SampleRate=atoi(temp); SampleRate=atoi(temp);
GetDlgItemText(hWnd,IDC_BSIZE,temp,20); SndOutLatencyMS = (int)SendMessage( GetDlgItem( hWnd, IDC_LATENCY_SLIDER ), TBM_GETPOS, 0, 0 );
temp[19]=0;
CurBufferSize=atoi(temp);
if(CurBufferSize<512) CurBufferSize=512; if( SndOutLatencyMS > 420 ) SndOutLatencyMS = 420;
if(CurBufferSize>16384) CurBufferSize=16384; if( SndOutLatencyMS < 20 ) SndOutLatencyMS = 20;
GetDlgItemText(hWnd,IDC_BCOUNT,temp,20);
temp[19]=0;
MaxBufferCount=atoi(temp);
if(MaxBufferCount<4) MaxBufferCount=4;
if(MaxBufferCount>50) MaxBufferCount=50;
Interpolation=(int)SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_GETCURSEL,0,0); Interpolation=(int)SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_GETCURSEL,0,0);
OutputModule=(int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),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(); WriteSettings();
EndDialog(hWnd,0); EndDialog(hWnd,0);
break; break;
@ -495,45 +528,41 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
break; break;
case IDC_OUTCONF: case IDC_OUTCONF:
SndConfigure(hWnd); SndConfigure( hWnd,
(int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0)
);
break; break;
HANDLE_CHECKNB( IDC_VOLBOOST, VolumeBoostEnabled );
VolumeShiftModifier = (VolumeBoostEnabled ? 1 : 0 );
SndOutVolumeShift = SndOutVolumeShiftBase - VolumeShiftModifier;
break;
HANDLE_CHECK(IDC_EFFECTS,EffectsEnabled); HANDLE_CHECK(IDC_EFFECTS,EffectsEnabled);
HANDLE_CHECKNB(IDC_DEBUG,DebugEnabled); HANDLE_CHECKNB(IDC_DEBUG,DebugEnabled);
ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled); EnableDebugControls( hWnd );
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);
break; break;
HANDLE_CHECKNB(IDC_MSGSHOW,MsgToConsole); HANDLE_CHECKNB(IDC_MSGSHOW,_MsgToConsole);
ENABLE_CONTROL(IDC_MSGKEY, DebugEnabled&MsgToConsole); EnableDebugMessages( hWnd );
ENABLE_CONTROL(IDC_MSGVOICE,DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGDMA, DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA);
break; break;
HANDLE_CHECK(IDC_MSGKEY,MsgKeyOnOff); HANDLE_CHECK(IDC_MSGKEY,_MsgKeyOnOff);
HANDLE_CHECK(IDC_MSGVOICE,MsgVoiceOff); HANDLE_CHECK(IDC_MSGVOICE,_MsgVoiceOff);
HANDLE_CHECKNB(IDC_MSGDMA,MsgDMA); HANDLE_CHECKNB(IDC_MSGDMA,_MsgDMA);
ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA); ENABLE_CONTROL(IDC_MSGADMA, MsgDMA());
break; break;
HANDLE_CHECK(IDC_MSGADMA,MsgAutoDMA); HANDLE_CHECK(IDC_MSGADMA,_MsgAutoDMA);
HANDLE_CHECK(IDC_LOGREGS,AccessLog); HANDLE_CHECK(IDC_DBG_OVERRUNS,_MsgOverruns);
HANDLE_CHECK(IDC_LOGDMA, DMALog); HANDLE_CHECK(IDC_DBG_CACHE,_MsgCache);
HANDLE_CHECK(IDC_LOGWAVE,WaveLog); HANDLE_CHECK(IDC_LOGREGS,_AccessLog);
HANDLE_CHECK(IDC_DUMPCORE,CoresDump); HANDLE_CHECK(IDC_LOGDMA, _DMALog);
HANDLE_CHECK(IDC_DUMPMEM, MemDump); HANDLE_CHECK(IDC_LOGWAVE,_WaveLog);
HANDLE_CHECK(IDC_DUMPREGS,RegDump); HANDLE_CHECK(IDC_DUMPCORE,_CoresDump);
HANDLE_CHECK(IDC_SPEEDLIMIT,LimitMode); HANDLE_CHECK(IDC_DUMPMEM, _MemDump);
HANDLE_CHECK(IDC_DUMPREGS,_RegDump);
HANDLE_CHECK(IDC_DSP_ENABLE,dspPluginEnabled); HANDLE_CHECK(IDC_DSP_ENABLE,dspPluginEnabled);
HANDLE_CHECK(IDC_TS_ENABLE,timeStretchEnabled); HANDLE_CHECK(IDC_TS_ENABLE,timeStretchEnabled);
HANDLE_CHECK(IDC_SPEEDLIMIT,LimitMode);
HANDLE_CHECK(IDC_SPEEDLIMIT_RUNTIME_TOGGLE,LimiterToggleEnabled);
default: default:
return FALSE; return FALSE;
} }
@ -550,11 +579,11 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
case TB_PAGEDOWN: case TB_PAGEDOWN:
wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0);
case TB_THUMBTRACK: case TB_THUMBTRACK:
if(wmEvent<512) wmEvent=512; if(wmEvent<20) wmEvent=20;
if(wmEvent>24000) wmEvent=24000; if(wmEvent>420) wmEvent=420;
SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent);
sprintf(temp,"%d",wmEvent); sprintf_s(temp,80,"%d ms (avg)",wmEvent);
SetDlgItemText(hWnd,IDC_BSIZE,temp); SetDlgItemText(hWnd,IDC_LATENCY_LABEL,temp);
break; break;
default: default:
return FALSE; return FALSE;

View File

@ -21,19 +21,39 @@
extern bool DebugEnabled; extern bool DebugEnabled;
extern bool MsgToConsole; extern bool _MsgToConsole;
extern bool MsgKeyOnOff; extern bool _MsgKeyOnOff;
extern bool MsgVoiceOff; extern bool _MsgVoiceOff;
extern bool MsgDMA; extern bool _MsgDMA;
extern bool MsgAutoDMA; extern bool _MsgAutoDMA;
extern bool _MsgOverruns;
extern bool _MsgCache;
extern bool AccessLog; extern bool _AccessLog;
extern bool DMALog; extern bool _DMALog;
extern bool WaveLog; 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 AccessLogFileName[255];
extern char WaveLogFileName[255]; extern char WaveLogFileName[255];
@ -55,27 +75,16 @@ extern bool EffectsEnabled;
extern int AutoDMAPlayRate[2]; extern int AutoDMAPlayRate[2];
extern int OutputModule; extern u32 OutputModule;
extern int CurBufferSize; extern int SndOutLatencyMS;
extern int CurBufferCount;
extern int MaxBufferCount;
extern int VolumeMultiplier; //extern int VolumeMultiplier;
extern int VolumeDivisor; //extern int VolumeDivisor;
extern int LimitMode; extern int LimitMode;
extern char AsioDriver[129]; 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 char dspPlugin[];
extern int dspPluginModule; extern int dspPluginModule;
@ -85,9 +94,82 @@ extern bool timeStretchEnabled;
extern bool LimiterToggleEnabled; extern bool LimiterToggleEnabled;
extern int LimiterToggle; 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;
////// //////

View File

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

View File

@ -34,7 +34,7 @@ u16* MBASE[2] = {0,0};
u16* DMABaseAddr; u16* DMABaseAddr;
void DMALogOpen() { void DMALogOpen() {
if(!DMALog) return; if(!DMALog()) return;
DMA4LogFile=fopen(DMA4LogFileName,"wb"); DMA4LogFile=fopen(DMA4LogFileName,"wb");
DMA7LogFile=fopen(DMA7LogFileName,"wb"); DMA7LogFile=fopen(DMA7LogFileName,"wb");
ADMA4LogFile=fopen("logs/adma4.raw","wb"); ADMA4LogFile=fopen("logs/adma4.raw","wb");
@ -44,42 +44,42 @@ void DMALogOpen() {
//REGWRTLogFile[1]=fopen("logs/RegWrite1.raw","wb"); //REGWRTLogFile[1]=fopen("logs/RegWrite1.raw","wb");
} }
void DMA4LogWrite(void *lpData, u32 ulSize) { void DMA4LogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return; if(!DMALog()) return;
if (!DMA4LogFile) return; if (!DMA4LogFile) return;
fwrite(lpData,ulSize,1,DMA4LogFile); fwrite(lpData,ulSize,1,DMA4LogFile);
} }
void DMA7LogWrite(void *lpData, u32 ulSize) { void DMA7LogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return; if(!DMALog()) return;
if (!DMA7LogFile) return; if (!DMA7LogFile) return;
fwrite(lpData,ulSize,1,DMA7LogFile); fwrite(lpData,ulSize,1,DMA7LogFile);
} }
void ADMA4LogWrite(void *lpData, u32 ulSize) { void ADMA4LogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return; if(!DMALog()) return;
if (!ADMA4LogFile) return; if (!ADMA4LogFile) return;
fwrite(lpData,ulSize,1,ADMA4LogFile); fwrite(lpData,ulSize,1,ADMA4LogFile);
} }
void ADMA7LogWrite(void *lpData, u32 ulSize) { void ADMA7LogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return; if(!DMALog()) return;
if (!ADMA7LogFile) return; if (!ADMA7LogFile) return;
fwrite(lpData,ulSize,1,ADMA7LogFile); fwrite(lpData,ulSize,1,ADMA7LogFile);
} }
void ADMAOutLogWrite(void *lpData, u32 ulSize) { void ADMAOutLogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return; if(!DMALog()) return;
if (!ADMAOutLogFile) return; if (!ADMAOutLogFile) return;
fwrite(lpData,ulSize,1,ADMAOutLogFile); fwrite(lpData,ulSize,1,ADMAOutLogFile);
} }
void RegWriteLog(u32 core,u16 value) void RegWriteLog(u32 core,u16 value)
{ {
if(!DMALog) return; if(!DMALog()) return;
if (!REGWRTLogFile[core]) return; if (!REGWRTLogFile[core]) return;
fwrite(&value,2,1,REGWRTLogFile[core]); fwrite(&value,2,1,REGWRTLogFile[core]);
} }
void DMALogClose() { void DMALogClose() {
if(!DMALog) return; if(!DMALog()) return;
if (DMA4LogFile) fclose(DMA4LogFile); if (DMA4LogFile) fclose(DMA4LogFile);
if (DMA7LogFile) fclose(DMA7LogFile); if (DMA7LogFile) fclose(DMA7LogFile);
if (REGWRTLogFile[0]) fclose(REGWRTLogFile[0]); 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) void StartADMAWrite(int core,u16 *pMem, u32 sz)
{ {
int size=(sz)&(~511); 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; Cores[core].InputDataProgress=0;
if((Cores[core].AutoDMACtrl&(core+1))==0) if((Cores[core].AutoDMACtrl&(core+1))==0)
@ -202,7 +202,7 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
else else
DMA7LogWrite(pMem,size<<1); 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; Cores[core].TDA=Cores[core].TSA;
for (i=0;i<size;i++) { for (i=0;i<size;i++) {

View File

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

View File

@ -68,12 +68,11 @@ HRESULT GUIDFromString(const char *str, LPGUID guid)
class DSound: public SndOutModule class DSound: public SndOutModule
{ {
private: private:
# define PI 3.14159265f # define MAX_BUFFER_COUNT 8
# define BufferSize (CurBufferSize<<1) static const int PacketsPerBuffer = (1024 / SndOutPacketSize);
# define BufferSizeBytes (BufferSize<<1) static const int BufferSize = SndOutPacketSize * PacketsPerBuffer;
static const int BufferSizeBytes = BufferSize << 1;
# define TBufferSize (BufferSize*CurBufferCount)
FILE *voicelog; FILE *voicelog;
@ -83,8 +82,6 @@ private:
HANDLE thread; HANDLE thread;
DWORD tid; DWORD tid;
# define MAX_BUFFER_COUNT 5
IDirectSound8* dsound; IDirectSound8* dsound;
IDirectSoundBuffer8* buffer; IDirectSoundBuffer8* buffer;
IDirectSoundNotify8* buffer_notify; IDirectSoundNotify8* buffer_notify;
@ -96,10 +93,7 @@ private:
SndBuffer *buff; SndBuffer *buff;
s32 *tbuffer;
# define STRFY(x) #x # define STRFY(x) #x
# define verifyc(x) if(Verifyc(x,STRFY(x))) return -1; # define verifyc(x) if(Verifyc(x,STRFY(x))) return -1;
int __forceinline Verifyc(HRESULT hr,const char* fn) int __forceinline Verifyc(HRESULT hr,const char* fn)
@ -122,36 +116,21 @@ private:
while( dsound_running ) 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; DWORD s1,s2;
u32 poffset=BufferSizeBytes * rv; u32 poffset=BufferSizeBytes * rv;
//DWORD play, write; verifyc(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0));
//buffer->GetCurrentPosition( &play, &write ); oldp1 = p1;
//ConLog( " * SPU2 > Play: %d Write: %d poffset: %d\n", play, write, poffset );
buff->ReadSamples(tbuffer,BufferSize); for(int p=0; p<PacketsPerBuffer; p++, p1+=SndOutPacketSize )
buff->ReadSamples( p1 );
verifyc(buffer->Lock(poffset,BufferSizeBytes,&p1,&s1,&p2,&s2,0)); verifyc(buffer->Unlock(oldp1,s1,p2,s2));
{
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));
} }
return 0; return 0;
} }
@ -166,7 +145,7 @@ public:
// //
GUID cGuid; 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)); verifyc(DirectSoundCreate8(&cGuid,&dsound,NULL));
} }
@ -187,7 +166,7 @@ public:
wfx.nChannels=2; wfx.nChannels=2;
wfx.wBitsPerSample = 16; wfx.wBitsPerSample = 16;
wfx.nBlockAlign = 2*2; wfx.nBlockAlign = 2*2;
wfx.nAvgBytesPerSec = SampleRate * 2 * 2; wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign;
wfx.cbSize=0; wfx.cbSize=0;
// Set up DSBUFFERDESC structure. // Set up DSBUFFERDESC structure.
@ -195,7 +174,7 @@ public:
memset(&desc, 0, sizeof(DSBUFFERDESC)); memset(&desc, 0, sizeof(DSBUFFERDESC));
desc.dwSize = sizeof(DSBUFFERDESC); desc.dwSize = sizeof(DSBUFFERDESC);
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; 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.lpwfxFormat = &wfx;
desc.dwFlags |=DSBCAPS_LOCSOFTWARE; desc.dwFlags |=DSBCAPS_LOCSOFTWARE;
@ -209,14 +188,18 @@ public:
DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT]; 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); 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]; 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; LPVOID p1=0,p2=0;
DWORD s1=0,s2=0; DWORD s1=0,s2=0;
@ -229,14 +212,11 @@ public:
//Play the buffer ! //Play the buffer !
verifyc(buffer->Play(0,0,DSBPLAY_LOOPING)); verifyc(buffer->Play(0,0,DSBPLAY_LOOPING));
tbuffer = new s32[BufferSize];
// Start Thread // Start Thread
dsound_running=true; 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); SetThreadPriority(thread,THREAD_PRIORITY_TIME_CRITICAL);
return 0; return 0;
} }
@ -257,14 +237,12 @@ public:
// //
buffer->Stop(); buffer->Stop();
for(int i=0;i<MAX_BUFFER_COUNT;i++) for(int i=0;i<Config_DSoundOut.NumBuffers;i++)
CloseHandle(buffer_events[i]); CloseHandle(buffer_events[i]);
buffer_notify->Release(); buffer_notify->Release();
buffer->Release(); buffer->Release();
dsound->Release(); dsound->Release();
delete tbuffer;
} }
private: private:
@ -298,7 +276,7 @@ private:
{ {
case WM_INITDIALOG: 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); SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_RESETCONTENT,0,0);
ndevs=0; ndevs=0;
@ -319,6 +297,12 @@ private:
SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_SETCURSEL,tSel,0); 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; break;
case WM_COMMAND: case WM_COMMAND:
wmId = LOWORD(wParam); wmId = LOWORD(wParam);
@ -332,11 +316,11 @@ private:
if(!devices[i].hasGuid) if(!devices[i].hasGuid)
{ {
DSoundDevice[0]=0; // clear device name to "" Config_DSoundOut.Device[0] = 0; // clear device name to ""
} }
else 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.Data1,
devices[i].guid.Data2, devices[i].guid.Data2,
devices[i].guid.Data3, devices[i].guid.Data3,
@ -350,6 +334,11 @@ private:
devices[i].guid.Data4[7] 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); EndDialog(hWnd,0);
break; break;
@ -360,6 +349,30 @@ private:
return FALSE; return FALSE;
} }
break; 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: default:
return FALSE; 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; 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; } DS;
SndOutModule *DSoundOut=&DS; SndOutModule *DSoundOut=&DS;

View File

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

View File

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

View File

@ -19,13 +19,30 @@
#include "SoundTouch/SoundTouch.h" #include "SoundTouch/SoundTouch.h"
#include "SoundTouch/WavFile.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 class NullOutModule: public SndOutModule
{ {
public:
s32 Init(SndBuffer *) { return 0; } s32 Init(SndBuffer *) { return 0; }
void Close() { } void Close() { }
s32 Test() { return 0; } s32 Test() const { return 0; }
void Configure(HWND parent) { } 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; } NullOut;
SndOutModule* mods[]= SndOutModule* mods[]=
@ -36,9 +53,39 @@ SndOutModule* mods[]=
DSound51Out, DSound51Out,
ASIOOut, ASIOOut,
XAudio2Out, 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 //usefull when timestretch isn't available
//#define DYNAMIC_BUFFER_LIMITING //#define DYNAMIC_BUFFER_LIMITING
@ -52,45 +99,42 @@ private:
s32 wpos; s32 wpos;
s32 data; s32 data;
#ifdef DYNAMIC_BUFFER_LIMITING // data prediction amount, used to "commit" data that hasn't
s32 buffer_limit; // finished timestretch processing.
#endif s32 predictData;
bool pr;
bool pw; bool pw;
int overflows; bool underrun_freeze;
int underflows;
int writewaits;
bool isWaiting;
HANDLE hSyncEvent; HANDLE hSyncEvent;
CRITICAL_SECTION cs; CRITICAL_SECTION cs;
u32 datawritten; protected:
u32 dataread; int GetAlignedBufferSize( int comp )
{
return (comp + SndOutPacketSize-1) & ~(SndOutPacketSize-1);
}
public: public:
SndBufferImpl(s32 _size) SndBufferImpl( double latencyMS )
{ {
rpos=0; rpos=0;
wpos=0; wpos=0;
data=0; data=0;
size=(_size+1)&(~1); size=GetAlignedBufferSize( (int)(latencyMS * SampleRate / 500.0 ) );
buffer = new s32[size]; buffer = new s32[size];
pr=false;
pw=false; pw=false;
isWaiting=false; underrun_freeze = false;
predictData = 0;
lastPct = 0.0;
#ifdef DYNAMIC_BUFFER_LIMITING #ifdef DYNAMIC_BUFFER_LIMITING
overflows=0; overflows=0;
underflows=0; underflows=0;
writewaits=0; writewaits=0;
buffer_limit=size; buffer_limit=size;
#endif #endif
datawritten=0;
dataread=0;
InitializeCriticalSection(&cs); InitializeCriticalSection(&cs);
hSyncEvent = CreateEvent(NULL,FALSE,FALSE,NULL); hSyncEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
} }
@ -98,7 +142,7 @@ public:
virtual ~SndBufferImpl() virtual ~SndBufferImpl()
{ {
pw=false; pw=false;
if(isWaiting) PulseEvent(hSyncEvent); PulseEvent(hSyncEvent);
Sleep(10); Sleep(10);
EnterCriticalSection(&cs); EnterCriticalSection(&cs);
LeaveCriticalSection(&cs); LeaveCriticalSection(&cs);
@ -107,41 +151,23 @@ public:
delete buffer; delete buffer;
} }
virtual void WriteSamples(s32 *bData, s32 nSamples) virtual void WriteSamples(s32 *bData, int nSamples)
{ {
EnterCriticalSection(&cs); EnterCriticalSection(&cs);
datawritten+=nSamples;
#ifdef DYNAMIC_BUFFER_LIMITING
int free = buffer_limit-data;
#else
int free = size-data; int free = size-data;
#endif predictData = 0;
if(pw) jASSUME( data <= size );
if( pw && ( free < nSamples ) )
{ {
#ifdef DYNAMIC_BUFFER_LIMITING // Wait for a ReadSamples to pull some stuff out of the buffer.
if(free<nSamples) // One SyncEvent will do the trick.
writewaits++; ResetEvent( hSyncEvent );
#endif
while((free<nSamples)&&(pw))
{
//isWaiting=true;
LeaveCriticalSection(&cs); LeaveCriticalSection(&cs);
//ConLog( " * SPU2 : Waiting for object... " ); WaitForSingleObject(hSyncEvent,20);
WaitForSingleObject(hSyncEvent,1000);
//ConLog( " Signaled! \n" );
EnterCriticalSection(&cs); EnterCriticalSection(&cs);
#ifdef DYNAMIC_BUFFER_LIMITING
free = buffer_limit-data;
#else
free = size-data;
#endif
//isWaiting=false;
} }
}
// either pw=false or free>nSamples
// Problem: // Problem:
// If the SPU2 gets out of sync with the SndOut device, the writepos of the // If the SPU2 gets out of sync with the SndOut device, the writepos of the
@ -154,64 +180,106 @@ public:
// The older portion of the buffer is discarded rather than incoming data, // The older portion of the buffer is discarded rather than incoming data,
// so that the overall audio synchronization is better. // so that the overall audio synchronization is better.
#ifndef DYNAMIC_BUFFER_LIMITING if( free < nSamples )
if((data+nSamples > size) && !timeStretchEnabled)
{ {
// Buffer overrun! // Buffer overrun!
// Dump samples from the read portion of the buffer instead of dropping // Dump samples from the read portion of the buffer instead of dropping
// the newly written stuff. // the newly written stuff.
// Toss half the buffer plus whatever's being written anew: // Toss half the buffer plus whatever's being written anew:
s32 comp = (size / 2) + nSamples; s32 comp = GetAlignedBufferSize( (size + nSamples ) / 2 );
comp = (comp + 128) & ~127; // probably not important but it makes the log look nicer. :P if( comp > (size-SndOutPacketSize) ) comp = size-SndOutPacketSize;
if( comp > size ) comp = size;
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; data-=comp;
rpos=(rpos+comp)%size; rpos=(rpos+comp)%size;
timeStretchEnabled = true; if( MsgOverruns() )
ConLog(" * SPU2 > Overrun Compensation (%d samples tossed)\n", size ); ConLog(" * SPU2 > Overrun Compensation (%d packets tossed)\n", comp / SndOutPacketSize );
ConLog(" * SPU2 Timestretch: ENABLED\n"); 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++); nSamples -= secondCopyLen;
wpos=(wpos+1)%size; memcpy( buffer, &bData[nSamples], secondCopyLen * sizeof( *bData ) );
data++; wpos = secondCopyLen;
nSamples--;
} }
else
wpos += nSamples;
#elif defined( DYNAMIC_BUFFER_LIMITING ) memcpy( wposbuffer, bData, nSamples * sizeof( *bData ) );
while(nSamples>0)
{
buffer[wpos] = *(bData++);
wpos=(wpos+1)%size;
data++;
nSamples--;
}
if(data>size)
{
do {
data-=size;
}
while(data>size);
overflows++;
}
#endif
LeaveCriticalSection(&cs); 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); EnterCriticalSection(&cs);
dataread+=nSamples;
// Problem: // Problem:
// If the SPU2 gets even the least bit out of sync with the SndOut device, // If the SPU2 gets even the least bit out of sync with the SndOut device,
@ -226,268 +294,218 @@ public:
// This will cause one brief hiccup that can never exceed the user's // This will cause one brief hiccup that can never exceed the user's
// set buffer length in duration. // set buffer length in duration.
#ifndef DYNAMIC_BUFFER_LIMITING int quietSamples;
if( underrun_freeze && !timeStretchEnabled) if( CheckUnderrunStatus( nSamples, quietSamples ) )
{ {
// Let's fill up 80% of our buffer. jASSUME( nSamples <= SndOutPacketSize );
// (I just picked 80% arbitrarily.. there might be a better value)
int toFill = (int)(size * 0.80); // [Air] [TODO]: This loop is probably a candidiate for SSE2 optimization.
toFill = (toFill + 128) & ~127; // probably not important but it makes the log look nicer. :P
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 ) nSamples -= secondCopyLen;
{ for( int i=0; i<secondCopyLen; i++ )
*(bData++) = 0; bData[nSamples+i] = SndScaleVol( buffer[i] );
nSamples--; rpos = secondCopyLen;
} }
LeaveCriticalSection(&cs); else
return; rpos += nSamples;
for( int i=0; i<nSamples; i++ )
bData[i] = SndScaleVol( rposbuffer[i] );
} }
underrun_freeze = false; // If quietSamples != 0 it means we have an underrun...
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--;
}
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 // Let's just dull out some silence, because that's usually the least
// painful way of dealing with underruns. // painful way of dealing with underruns:
memset( bData, 0, quietSamples * sizeof(*bData) );
*(bData++) = 0; SetEvent( hSyncEvent );
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
LeaveCriticalSection(&cs); 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 void PauseOnWrite(bool doPause) { pw = doPause; }
virtual s32 GetBufferUsage() // Calculate the buffer status percentage.
{ // Returns range from -1.0 to 1.0
return data; // 1.0 = buffer overflow!
} // 0.0 = buffer nominal (50% full)
// -1.0 = buffer underflow!
virtual s32 GetBufferSize() double GetStatusPct()
{
return size;
}
bool GetStats(u32 &w, u32 &r, bool reset)
{ {
EnterCriticalSection(&cs); EnterCriticalSection(&cs);
w = datawritten;
r = dataread; // Get the buffer status of the output driver too, so that we can
if(reset) { datawritten=dataread=0; } // 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); LeaveCriticalSection(&cs);
return true; return result;
} }
} *sndBuffer;
};
SndBufferImpl *sndBuffer;
s32* sndTempBuffer; s32* sndTempBuffer;
s32 sndTempProgress; s32 sndTempProgress;
s32 sndTempSize;
s16* sndTempBuffer16; s16* sndTempBuffer16;
float* sndTempBufferFloat; //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;
void ResetTempoChange() void ResetTempoChange()
{ {
u32 cWritten;
u32 cRead;
u32 cInput = inputSamples;
sndBuffer->GetStats(cWritten,cRead,false);
oldWritten=cWritten;
oldRead=cRead;
oldInput=cInput;
pSoundTouch->setTempo(1); pSoundTouch->setTempo(1);
} }
void UpdateTempoChange() void UpdateTempoChange()
{ {
u32 cWritten; double statusPct = sndBuffer->GetStatusPct();
u32 cRead; double pctChange = statusPct - lastPct;
u32 cInput = inputSamples;
static short int runs =0;
s32 bufferUsage = sndBuffer->GetBufferUsage(); double tempoChange;
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));
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; } // The buffer is already shrinking toward
else if(bufferUsage < CurBufferSize * 3) { cTempo*=0.90f; } // nominal value, so let's not do "too much"
else if(bufferUsage < CurBufferSize * 4) { cTempo*=0.96f; } // We only want to adjust if the shrink rate seems too fast
// or slow compared to our distance from nominal (50%).
if (bufferUsage > (bufferSize - CurBufferSize * 2)) { cTempo*=1.20f; } tempoChange = ( pow( statusPct, 3.0 ) * 0.33 ) + pctChange * 0.23;
else if(bufferUsage > (bufferSize - CurBufferSize * 3)) { cTempo*=1.10f; }
else if(bufferUsage >= (bufferSize - CurBufferSize * 4)) { cTempo*=1.04f; }
if (cTempo != lastTempo) {
pSoundTouch->setTempo(cTempo);
}
} }
else 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); // 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;
valAccum1 += (cRead-oldRead); lastPct = statusPct;
valAccum2 += (cInput-oldInput);
numAccum++;
oldRead = cRead; // Apply tempoChange as a scale of cTempo. That way the effect is proportional
oldInput = cInput; // to the current tempo. (otherwise tempos would change too slowly/quickly at the extremes)
cTempo += (float)( tempoChange * cTempo );
//normal stretch, scales sound to game speed if( statusPct < -0.20 || statusPct > 0.20 || cTempo < 0.980 || cTempo > 1.020 )
if(numAccum >= numUpdates)
{ {
float valAccum = 1.0f; if( cTempo < 0.20f ) cTempo = 0.20f;
else if( cTempo > 5.0f ) cTempo = 5.0f;
pSoundTouch->setTempo( cTempo );
ts_stats_stretchblocks++;
valAccum = valAccum2 / valAccum1; ConLog(" %s * SPU2: TempoChange by %d%% (tempo: %d%%) (buffer: %d%%)\n",
(relation < 0.0) ? "Normalize" : "",
if((valAccum < 1.04f) && (valAccum > 0.96f) /*&& (valAccum != 1)*/) (int)(tempoChange * 100.0), (int)(cTempo * 100.0),
(int)(statusPct * 100.0)
);
}
else
{ {
valAccum = 1.0f; // Nominal operation -- turn off stretching.
} pSoundTouch->setTempo( 1.0f );
ts_stats_normalblocks++;
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;
}
}
void soundtouchInit() { void soundtouchInit() {
pSoundTouch = new soundtouch::SoundTouch(); pSoundTouch = new soundtouch::SoundTouch();
@ -500,18 +518,22 @@ void soundtouchInit() {
s32 SndInit() s32 SndInit()
{ {
if(OutputModule>=mods_count) if( mods[OutputModule] == NULL )
return -1; {
// force us to the NullOut module if nothing assigned.
OutputModule = FindOutputModuleById( NullOut.GetIdent() );
}
// initialize sound buffer // initialize sound buffer
sndBuffer = new SndBufferImpl(CurBufferSize * MaxBufferCount * 2); // Buffer actually attempts to run ~50%, so allocate near double what
sndTempSize = 512; // the requested latency is:
sndBuffer = new SndBufferImpl( SndOutLatencyMS * 1.75 );
sndTempProgress = 0; sndTempProgress = 0;
sndTempBuffer = new s32[sndTempSize]; sndTempBuffer = new s32[SndOutPacketSize];
sndTempBuffer16 = new s16[sndTempSize]; sndTempBuffer16 = new s16[SndOutPacketSize];
sndTempBufferFloat = new float[sndTempSize]; //sndTempBufferFloat = new float[sndTempSize];
buffersize=sndBuffer->GetBufferSize();
cTempo = 1.0;
soundtouchInit(); soundtouchInit();
ResetTempoChange(); ResetTempoChange();
@ -530,15 +552,11 @@ s32 SndInit()
void SndClose() void SndClose()
{ {
if(OutputModule>=mods_count)
return;
mods[OutputModule]->Close(); mods[OutputModule]->Close();
delete sndBuffer; delete sndBuffer;
delete sndTempBuffer; delete sndTempBuffer;
delete sndTempBuffer16; delete sndTempBuffer16;
delete sndTempBufferFloat;
delete pSoundTouch; 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) 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) if(recording!=0)
RecordWrite(ValL>>8,ValR>>8); RecordWrite(SndScaleVol(ValL),SndScaleVol(ValR));
if(OutputModule>=mods_count)
return -1;
if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p
return 0; return 0;
inputSamples+=2; //inputSamples+=2;
sndTempBuffer[sndTempProgress++] = ValL; sndTempBuffer[sndTempProgress++] = ValL;
sndTempBuffer[sndTempProgress++] = ValR; 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<sndTempProgress;i++) { sndTempBuffer16[i] = sndTempBuffer[i]>>8; } for(int i=0;i<SndOutPacketSize;i++) { sndTempBuffer16[i] = SndScaleVol( sndTempBuffer[i] ); }
// send to winamp DSP // send to winamp DSP
sndTempProgress = DspProcess(sndTempBuffer16,sndTempProgress>>1)<<1; sndTempProgress = DspProcess(sndTempBuffer16,sndTempProgress>>1)<<1;
for(int i=0;i<sndTempProgress;i++) { sndTempBuffer[i] = sndTempBuffer16[i]<<8; } for(int i=0;i<sndTempProgress;i++) { sndTempBuffer[i] = sndTempBuffer16[i]<<SndOutVolumeShift; }
} }
static int equalized = 0;
if(timeStretchEnabled) if(timeStretchEnabled)
{ {
for(int i=0;i<sndTempProgress;i++) { sndTempBufferFloat[i] = sndTempBuffer[i]/2147483648.0f; } bool progress = false;
// send to timestretcher // data prediction helps keep the tempo adjustments more accurate.
pSoundTouch->putSamples(sndTempBufferFloat, sndTempProgress>>1); sndBuffer->PredictDataWrite( (int)( sndTempProgress / cTempo ) );
UpdateTempoChange(); for(int i=0;i<sndTempProgress;i++) { ((float*)sndTempBuffer)[i] = sndTempBuffer[i]/2147483648.0f; }
do
pSoundTouch->putSamples((float*)sndTempBuffer, sndTempProgress>>1);
while( ( sndTempProgress = pSoundTouch->receiveSamples((float*)sndTempBuffer, sndTempProgress>>1)<<1 ) != 0 )
{ {
sndTempProgress = pSoundTouch->receiveSamples(sndTempBufferFloat, sndTempSize>>1)<<1; // 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)
if(sndTempProgress>0) // [Air] [TODO] : Implement an SSE downsampler to int.
for(int i=0;i<sndTempProgress;i++)
{ {
sndTempBuffer[i] = (s32)(((float*)sndTempBuffer)[i]*2147483648.0f);
for(int i=0;i<sndTempProgress;i++) { sndTempBuffer[i] = (s32)(sndTempBufferFloat[i]*2147483648.0f); } }
sndBuffer->WriteSamples(sndTempBuffer, sndTempProgress); sndBuffer->WriteSamples(sndTempBuffer, sndTempProgress);
progress = true;
} }
} while (sndTempProgress != 0 ); if( progress )
{
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 else
{ {
sndBuffer->WriteSamples(sndTempBuffer, sndTempProgress); sndBuffer->WriteSamples(sndTempBuffer, sndTempProgress);
sndTempProgress=0; sndTempProgress=0;
} }
}
return 1; return 1;
} }
s32 SndTest() s32 SndTest()
{ {
if(OutputModule>=mods_count) if( mods[OutputModule] == NULL )
return -1; return -1;
return mods[OutputModule]->Test(); return mods[OutputModule]->Test();
} }
void SndConfigure(HWND parent) void SndConfigure(HWND parent, u32 module )
{ {
if(OutputModule>=mods_count) if( mods[module] == NULL )
return; return;
mods[OutputModule]->Configure(parent); mods[module]->Configure(parent);
} }
#if 0 #if 0

View File

@ -18,12 +18,13 @@
#ifndef SNDOUT_H_INCLUDE #ifndef SNDOUT_H_INCLUDE
#define SNDOUT_H_INCLUDE #define SNDOUT_H_INCLUDE
#define OUTPUT_NULL 0 // Number of stereo samples per SndOut block.
#define OUTPUT_WAVEOUT 1 // All drivers must work in units of this size when communicating with
#define OUTPUT_DSOUND 2 // SndOut.
#define OUTPUT_DSOUND51 3 static const int SndOutPacketSize = 1024;
#define OUTPUT_ASIO 4
#define OUTPUT_XAUDIO2 5 static const int SndOutVolumeShiftBase = 14;
extern int SndOutVolumeShift;
#define pcmlog #define pcmlog
extern FILE *wavelog; extern FILE *wavelog;
@ -32,32 +33,46 @@ s32 SndInit();
void SndClose(); void SndClose();
s32 SndWrite(s32 ValL, s32 ValR); s32 SndWrite(s32 ValL, s32 ValR);
s32 SndTest(); s32 SndTest();
void SndConfigure(HWND parent); void SndConfigure(HWND parent, u32 outmodidx );
bool SndGetStats(u32 *written, u32 *played); bool SndGetStats(u32 *written, u32 *played);
int FindOutputModuleById( const char* omodid );
class SndBuffer class SndBuffer
{ {
public: public:
virtual ~SndBuffer() {} virtual ~SndBuffer() {}
virtual void WriteSamples(s32 *buffer, s32 nSamples)=0; virtual void WriteSamples(s32 *buffer, int nSamples)=0;
virtual void ReadSamples (s32 *buffer, s32 nSamples)=0;
virtual void PauseOnWrite(bool doPause)=0; virtual void PauseOnWrite(bool doPause)=0;
virtual s32 GetBufferUsage()=0; virtual void ReadSamples( s16* bData )=0;
virtual s32 GetBufferSize()=0; virtual void ReadSamples( s32* bData )=0;
//virtual s32 GetBufferUsage()=0;
//virtual s32 GetBufferSize()=0;
}; };
class SndOutModule class SndOutModule
{ {
public: 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 s32 Init(SndBuffer *buffer)=0;
virtual void Close()=0; virtual void Close()=0;
virtual s32 Test()=0; virtual s32 Test() const=0;
virtual void Configure(HWND parent)=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 //internal
@ -69,6 +84,5 @@ extern SndOutModule *XAudio2Out;
extern SndOutModule *DSound51Out; extern SndOutModule *DSound51Out;
extern SndOutModule* mods[]; extern SndOutModule* mods[];
extern const u32 mods_count;
#endif // SNDOUT_H_INCLUDE #endif // SNDOUT_H_INCLUDE

View File

@ -42,6 +42,7 @@ static char *libraryName = "GiGaHeRz's SPU2 ("
#endif #endif
")"; ")";
DWORD CALLBACK TimeThread(PVOID /* unused param */); 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: // Make sure the cache is invalidated:
// (note to self : addr address WORDs, not bytes) // (note to self : addr address WORDs, not bytes)
addr &= 0xfffff;
const u32 nexta = addr >> 3; // 8 words per encoded block. const u32 nexta = addr >> 3; // 8 words per encoded block.
const u32 flagbitmask = 1ul<<(nexta & 31); // 31 flags per array entry const u32 flagbitmask = 1ul<<(nexta & 31); // 31 flags per array entry
pcm_cache_flags[nexta>>5] &= ~flagbitmask; pcm_cache_flags[nexta>>5] &= ~flagbitmask;
*GetMemPtr( addr & 0xfffff ) = value; *GetMemPtr( addr ) = value;
} }
// writes an unsigned value to the SPU2 ram // writes an unsigned value to the SPU2 ram
@ -271,7 +273,7 @@ s32 CALLBACK SPU2init()
acumCycles=0; acumCycles=0;
#ifdef SPU2_LOG #ifdef SPU2_LOG
if(AccessLog) if(AccessLog())
{ {
spu2Log = fopen(AccessLogFileName, "w"); spu2Log = fopen(AccessLogFileName, "w");
setvbuf(spu2Log, NULL, _IONBF, 0); setvbuf(spu2Log, NULL, _IONBF, 0);
@ -325,7 +327,7 @@ s32 CALLBACK SPU2init()
DMALogOpen(); DMALogOpen();
if(WaveLog) if(WaveLog())
{ {
if(!wavedump_open()) if(!wavedump_open())
{ {
@ -459,7 +461,7 @@ void CALLBACK SPU2shutdown()
fclose(el0); fclose(el0);
fclose(el1); fclose(el1);
#endif #endif
if(WaveLog && wavedump_ok) wavedump_close(); if(WaveLog() && wavedump_ok) wavedump_close();
DMALogClose(); DMALogClose();
@ -477,7 +479,7 @@ void CALLBACK SPU2shutdown()
pcm_cache_data = NULL; pcm_cache_data = NULL;
#ifdef SPU2_LOG #ifdef SPU2_LOG
if(!AccessLog) return; if(!AccessLog()) return;
FileLog("[%10d] SPU2shutdown\n",Cycles); FileLog("[%10d] SPU2shutdown\n",Cycles);
if(spu2Log) fclose(spu2Log); if(spu2Log) fclose(spu2Log);
#endif #endif
@ -1895,7 +1897,7 @@ void VoiceStart(int core,int vc)
DebugCores[core].Voices[vc].FirstBlock=1; DebugCores[core].Voices[vc].FirstBlock=1;
if(core==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, core,vc,Cores[core].Voices[vc].StartA,
(Cores[core].Voices[vc].DryL)?"+":"-",(Cores[core].Voices[vc].DryR)?"+":"-", (Cores[core].Voices[vc].DryL)?"+":"-",(Cores[core].Voices[vc].DryR)?"+":"-",
(Cores[core].Voices[vc].WetL)?"+":"-",(Cores[core].Voices[vc].WetR)?"+":"-", (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++) { for (vc=0;vc<24;vc++) {
if ((value>>vc) & 1) { if ((value>>vc) & 1) {
Cores[core].Voices[vc].ADSR.Releasing=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 //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
#include "spu2.h" #include "spu2.h"
#include "dialogs.h"
#include <windows.h>
class WaveOutModule: public SndOutModule class WaveOutModule: public SndOutModule
{ {
private: private:
# define MAX_BUFFER_COUNT 8
#define MAX_BUFFER_COUNT 5 static const int PacketsPerBuffer = (1024 / SndOutPacketSize);
static const int BufferSize = SndOutPacketSize*PacketsPerBuffer;
#define BufferSize (CurBufferSize<<1) static const int BufferSizeBytes = BufferSize << 1;
#define BufferSizeBytes (BufferSize<<1)
HWAVEOUT hwodevice; HWAVEOUT hwodevice;
WAVEFORMATEX wformat; WAVEFORMATEX wformat;
WAVEHDR whbuffer[MAX_BUFFER_COUNT]; WAVEHDR whbuffer[MAX_BUFFER_COUNT];
s32* tbuffer;
s16* qbuffer; s16* qbuffer;
#define QBUFFER(x) (qbuffer + BufferSize * (x)) #define QBUFFER(x) (qbuffer + BufferSize * (x))
@ -63,14 +65,9 @@ private:
buf->dwBytesRecorded = buf->dwBufferLength; buf->dwBytesRecorded = buf->dwBufferLength;
buff->ReadSamples(tbuffer,BufferSize);
s16 *t = (s16*)buf->lpData; s16 *t = (s16*)buf->lpData;
s32 *s = (s32*)tbuffer; for(int p=0; p<PacketsPerBuffer; p++, t+=SndOutPacketSize )
buff->ReadSamples( t );
for(int bleh=0;bleh<BufferSize;bleh++)
{
*(t++) = (s16)((*(s++))>>8);
}
whbuffer[i].dwFlags&=~WHDR_DONE; whbuffer[i].dwFlags&=~WHDR_DONE;
waveOutWrite(hwodevice,buf,sizeof(WAVEHDR)); waveOutWrite(hwodevice,buf,sizeof(WAVEHDR));
@ -94,8 +91,6 @@ public:
if (Test()) return -1; if (Test()) return -1;
if(CurBufferSize<1024) CurBufferSize=1024;
wformat.wFormatTag=WAVE_FORMAT_PCM; wformat.wFormatTag=WAVE_FORMAT_PCM;
wformat.nSamplesPerSec=SampleRate; wformat.nSamplesPerSec=SampleRate;
wformat.wBitsPerSample=16; wformat.wBitsPerSample=16;
@ -105,7 +100,6 @@ public:
wformat.cbSize=0; wformat.cbSize=0;
qbuffer=new s16[BufferSize*MAX_BUFFER_COUNT]; qbuffer=new s16[BufferSize*MAX_BUFFER_COUNT];
tbuffer=new s32[BufferSize];
woores = waveOutOpen(&hwodevice,WAVE_MAPPER,&wformat,0,0,0); woores = waveOutOpen(&hwodevice,WAVE_MAPPER,&wformat,0,0,0);
if (woores != MMSYSERR_NOERROR) if (woores != MMSYSERR_NOERROR)
@ -161,23 +155,121 @@ public:
} }
waveOutClose(hwodevice); waveOutClose(hwodevice);
delete tbuffer;
delete qbuffer; 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) { if (waveOutGetNumDevs() == 0) {
SysMessage("No waveOut Devices Present\n"); return -1; SysMessage("No waveOut Devices Present\n"); return -1;
} }
return 0; 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; } WO;
SndOutModule *WaveOut=&WO; SndOutModule *WaveOut=&WO;

View File

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