From 0e1f871606fb67b601e4cedc7ebb9d654aeb551d Mon Sep 17 00:00:00 2001 From: ramapcsx2 Date: Tue, 28 Oct 2008 11:17:17 +0000 Subject: [PATCH] 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 --- plugins/spu2ghz/SPU2ghz.rc | 204 +++++---- plugins/spu2ghz/asioout.cpp | 35 +- plugins/spu2ghz/config.cpp | 513 ++++++++++++---------- plugins/spu2ghz/config.h | 140 ++++-- plugins/spu2ghz/debug.cpp | 12 +- plugins/spu2ghz/dma.cpp | 20 +- plugins/spu2ghz/dsound51.cpp | 143 ++++-- plugins/spu2ghz/dsoundout.cpp | 139 +++--- plugins/spu2ghz/mixer.cpp | 33 +- plugins/spu2ghz/resource.h | 13 +- plugins/spu2ghz/sndout.cpp | 778 +++++++++++++++++---------------- plugins/spu2ghz/sndout.h | 44 +- plugins/spu2ghz/spu2.cpp | 16 +- plugins/spu2ghz/waveout.cpp | 130 +++++- plugins/spu2ghz/xaudio2out.cpp | 47 +- 15 files changed, 1329 insertions(+), 938 deletions(-) diff --git a/plugins/spu2ghz/SPU2ghz.rc b/plugins/spu2ghz/SPU2ghz.rc index ec4ca77fc4..b581a6e8cc 100644 --- a/plugins/spu2ghz/SPU2ghz.rc +++ b/plugins/spu2ghz/SPU2ghz.rc @@ -52,51 +52,57 @@ END // Dialog // -IDD_CONFIG DIALOGEX 3, 1, 414, 217 +IDD_CONFIG DIALOGEX 3, 1, 410, 237 STYLE DS_SETFONT | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "SPU2ghz Settings" FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN - PUSHBUTTON "OK",IDOK,300,198,54,15,NOT WS_TABSTOP - PUSHBUTTON "Cancel",IDCANCEL,354,198,54,15,NOT WS_TABSTOP - GROUPBOX "Effects (Reverb) Settings",IDC_STATIC,6,156,119,30 - CHECKBOX "Enable Effect Processing",IDC_EFFECTS,12,168,95,10,NOT WS_TABSTOP - GROUPBOX "Output Settings",IDC_STATIC,132,6,119,103 - LTEXT "Buffer Size",IDC_STATIC,138,35,35,8,NOT WS_GROUP - LTEXT "Sample Rate",IDC_STATIC,139,19,42,8,NOT WS_GROUP - GROUPBOX "Mixing Settings",IDC_STATIC,6,6,119,80 - LTEXT "Interpolation:",IDC_STATIC,11,58,42,8,NOT WS_GROUP - GROUPBOX "",IDC_STATIC,264,18,135,61 - GROUPBOX "Dumps (on close)",IDC_STATIC,264,131,135,51 - CHECKBOX "Dump Register Data",IDC_DUMPREGS,270,169,80,10,NOT WS_TABSTOP - CHECKBOX "Dump Memory Contents",IDC_DUMPMEM,270,156,91,10,NOT WS_TABSTOP - CHECKBOX "Dump Core and Voice State",IDC_DUMPCORE,270,145,104,10,NOT WS_TABSTOP - GROUPBOX "Logging",IDC_STATIC,263,80,136,50 - CHECKBOX "Log Audio Output",IDC_LOGWAVE,269,116,71,10,NOT WS_TABSTOP - CHECKBOX "Log DMA Writes",IDC_LOGDMA,269,104,68,10,NOT WS_TABSTOP - CHECKBOX "Log Register/DMA Actions",IDC_LOGREGS,269,92,101,10,NOT WS_TABSTOP - CHECKBOX "KeyOn/Off Events",IDC_MSGKEY,276,30,74,10,NOT WS_TABSTOP - COMBOBOX IDC_INTERPOLATE,12,66,108,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_SRATE,192,18,54,201,CBS_DROPDOWN | WS_DISABLED | WS_TABSTOP,WS_EX_RIGHT - CONTROL "Slider2",IDC_BUFFER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,138,42,65,10 - EDITTEXT IDC_BSIZE,204,42,42,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER - LTEXT "Output Module:",IDC_STATIC,12,16,50,8,NOT WS_GROUP - COMBOBOX IDC_OUTPUT,12,24,108,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Number of Buffers:",IDC_STATIC,139,62,60,8 - EDITTEXT IDC_BCOUNT,204,60,42,12,ES_RIGHT | ES_AUTOHSCROLL - GROUPBOX "",IDC_STATIC,258,6,150,180 - CHECKBOX "Enable Debug Options",IDC_DEBUG,264,6,87,10,NOT WS_TABSTOP - CONTROL "DMA Operations",IDC_MSGDMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,54,68,10 - CONTROL "AutoDMA Operations",IDC_MSGADMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,282,66,83,10 - CONTROL "Voice Stop Events",IDC_MSGVOICE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,42,75,10 - CONTROL "Show In Console",IDC_MSGSHOW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,270,18,69,10 - LTEXT "Size = 1024, Numbers = 10",IDC_STATIC,137,94,108,12 - PUSHBUTTON "Configure...",IDC_OUTCONF,72,42,48,12 - LTEXT "WARNING: The effects processing is experimental and _could_ hurt your ears .\n If that happens, tell me about what game, so I can fix it!",IDC_STATIC,20,191,255,21 - GROUPBOX "DSP",IDC_STATIC,6,87,119,68 - CONTROL "Enable Winamp DSP plugin",IDC_DSP_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,100,103,10 - LTEXT "(configure in the .ini)",IDC_STATIC,43,110,64,8 - LTEXT "Recommended:",IDC_STATIC,137,80,108,9 + PUSHBUTTON "OK",IDOK,291,219,54,15,NOT WS_TABSTOP + PUSHBUTTON "Cancel",IDCANCEL,351,219,54,15,NOT WS_TABSTOP + GROUPBOX "Mixing Settings",IDC_STATIC,6,6,119,116 + GROUPBOX "Speed Limiter (obsolete)",IDC_STATIC,6,127,120,98 + GROUPBOX "Output Settings",IDC_STATIC,132,6,119,182 + GROUPBOX "",IDC_DEBUG_GROUP,257,7,148,208 + GROUPBOX "",IDC_STATIC,264,19,135,85 + GROUPBOX "Logging",IDC_STATIC,264,107,136,50 + GROUPBOX "Dumps (on close)",IDC_STATIC,264,160,135,49 + COMBOBOX IDC_OUTPUT,138,27,108,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure...",IDC_OUTCONF,198,42,48,12 + COMBOBOX IDC_INTERPOLATE,12,28,108,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Enable at start-up",IDC_SPEEDLIMIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,176,106,12 + COMBOBOX IDC_SRATE,188,62,58,201,CBS_DROPDOWN | WS_DISABLED | WS_TABSTOP,WS_EX_RIGHT + CONTROL "Slider2",IDC_LATENCY_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,177,94,72,10 + CONTROL "Use Time-stretching",IDC_TS_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,138,114,79,11 + CONTROL "Use a Winamp DSP plugin",IDC_DSP_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,138,160,103,11 + CHECKBOX "Enable Debug Options",IDC_DEBUG,264,7,87,10,NOT WS_TABSTOP + CONTROL "Show In Console",IDC_MSGSHOW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,270,19,69,10 + CHECKBOX "KeyOn/Off Events",IDC_MSGKEY,276,31,74,10,NOT WS_TABSTOP + CONTROL "Voice Stop Events",IDC_MSGVOICE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,43,75,10 + CONTROL "DMA Operations",IDC_MSGDMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,55,68,10 + CONTROL "AutoDMA Operations",IDC_MSGADMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,283,67,83,10 + CONTROL "Buffer Over/Underruns",IDC_DBG_OVERRUNS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,79,97,11 + CONTROL "ADPCM Cache Statistics",IDC_DBG_CACHE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,91,114,9 + CHECKBOX "Dump Core and Voice State",IDC_DUMPCORE,270,172,104,10,NOT WS_TABSTOP + CHECKBOX "Dump Memory Contents",IDC_DUMPMEM,270,184,91,10,NOT WS_TABSTOP + CHECKBOX "Dump Register Data",IDC_DUMPREGS,270,196,80,10,NOT WS_TABSTOP + CHECKBOX "Enable Effects Processing",IDC_EFFECTS,12,49,99,10,NOT WS_TABSTOP + LTEXT "Latency:",IDC_STATIC,138,89,33,8,NOT WS_GROUP + LTEXT "Sample Rate:",IDC_STATIC,137,63,44,8,NOT WS_GROUP + LTEXT "Interpolation:",IDC_STATIC,12,18,42,10,NOT WS_GROUP + LTEXT "Module:",IDC_STATIC,138,17,50,9,NOT WS_GROUP + LTEXT "Experimental: Enabling this could break sound badly.",IDC_STATIC,24,61,96,17 + LTEXT "(configure in the .ini)",IDC_STATIC,150,172,64,8 + LTEXT "Uses the SPU2 to limit framerate for games that cause buffer overruns. Use Timestretching instead.",IDC_STATIC,11,138,109,34 + CTEXT "100 ms (avg)",IDC_LATENCY_LABEL,185,84,58,10 + LTEXT "Helps reduce latency and usually eliminates audio skips. Uses a little extra CPU.",IDC_STATIC,150,127,96,25 + CHECKBOX "Log Register/DMA Actions",IDC_LOGREGS,269,119,101,10,WS_GROUP | NOT WS_TABSTOP + CHECKBOX "Log DMA Writes",IDC_LOGDMA,269,131,68,10,NOT WS_TABSTOP + CHECKBOX "Log Audio Output",IDC_LOGWAVE,269,143,71,10,NOT WS_TABSTOP + CONTROL "Enable runtime toggle",IDC_SPEEDLIMIT_RUNTIME_TOGGLE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,190,110,10 + LTEXT "Allows speed limiter to be toggled with the minus (-) key.",IDC_STATIC,23,202,95,17 + CONTROL "Volume Boost",IDC_VOLBOOST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,86,85,11 + LTEXT "Can break sound in games that are already loud.",IDC_STATIC,24,99,96,17 END IDD_DEBUG DIALOGEX 0, 0, 326, 525 @@ -107,49 +113,58 @@ BEGIN DEFPUSHBUTTON "Close",IDOK,269,504,50,14 END -IDD_DSOUND DIALOGEX 0, 0, 186, 58 +IDD_DSOUND DIALOGEX 0, 0, 170, 122 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "DirectSound Output Module Settings" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,75,37,50,14 - PUSHBUTTON "Cancel",IDCANCEL,129,37,50,14 - COMBOBOX IDC_DS_DEVICE,7,17,172,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "DirectSound Device",IDC_STATIC,7,7,63,8 + DEFPUSHBUTTON "OK",IDOK,52,104,50,14 + PUSHBUTTON "Cancel",IDCANCEL,115,104,50,14 + COMBOBOX IDC_DS_DEVICE,4,15,161,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "DirectSound Device",IDC_STATIC,4,3,63,8 + LTEXT "Number of Buffers",IDC_STATIC,4,40,61,11 + CONTROL "",IDC_BUFFERS_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,71,48,94,10 + LTEXT "Use extra buffers if you are experiencing loopy or studdery audio even when games run at high FPS.",IDC_STATIC,8,66,151,27 + CTEXT "8 (80 ms latency)",IDC_LATENCY_LABEL,70,37,95,11 END -IDD_DSOUND51 DIALOGEX 0, 0, 265, 182 +IDD_DSOUND51 DIALOGEX 0, 0, 336, 180 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "DirectSound 5.1 Output Module Settings" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,154,161,50,14 - PUSHBUTTON "Cancel",IDCANCEL,208,161,50,14 - COMBOBOX IDC_DS_DEVICE,7,17,251,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "DirectSound Device",IDC_STATIC,7,7,63,8 - CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,18,54,30,36 - CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,60,56,30,34 - CONTROL "",IDC_SLIDER3,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,102,56,30,34 - GROUPBOX "Surround Volume Correction",IDC_STATIC,7,36,142,139 - CTEXT "Center",IDC_STATIC,54,48,42,8 - CTEXT "Left",IDC_STATIC,12,48,42,8 - CTEXT "Right",IDC_STATIC,96,48,42,8 - CONTROL "",IDC_SLIDER4,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,18,116,30,40 - CONTROL "",IDC_SLIDER5,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,60,116,30,40 - CONTROL "",IDC_SLIDER6,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,102,116,30,40 - CTEXT "LFE (sub)",IDC_STATIC,54,108,42,8 - CTEXT "Rear Left",IDC_STATIC,12,108,42,8 - CTEXT "Rear Right",IDC_STATIC,96,108,42,8 - GROUPBOX "Other Tweaks",IDC_STATIC,155,36,103,120 - CONTROL "",IDC_SLIDER7,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,168,56,30,49 - CTEXT "Center in LR",IDC_STATIC,162,48,42,8 - EDITTEXT IDC_EDIT1,18,90,30,14,ES_AUTOHSCROLL - EDITTEXT IDC_EDIT2,60,90,30,14,ES_AUTOHSCROLL - EDITTEXT IDC_EDIT3,102,90,30,14,ES_AUTOHSCROLL - EDITTEXT IDC_EDIT4,18,156,30,14,ES_AUTOHSCROLL - EDITTEXT IDC_EDIT5,60,156,30,14,ES_AUTOHSCROLL - EDITTEXT IDC_EDIT6,102,156,30,14,ES_AUTOHSCROLL - EDITTEXT IDC_EDIT7,168,108,30,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,228,161,50,14 + PUSHBUTTON "Cancel",IDCANCEL,281,161,50,14 + COMBOBOX IDC_DS_DEVICE,5,17,142,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "DirectSound Device",IDC_STATIC,5,5,63,8 + CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,15,53,30,36 + CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,57,54,30,34 + CONTROL "",IDC_SLIDER3,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,99,54,30,34 + GROUPBOX "Surround Volume Correction",IDC_STATIC,5,35,138,139 + CTEXT "Center",IDC_STATIC,51,46,42,8 + CTEXT "Left",IDC_STATIC,9,46,42,8 + CTEXT "Right",IDC_STATIC,93,46,42,8 + CONTROL "",IDC_SLIDER4,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,15,115,30,40 + CONTROL "",IDC_SLIDER5,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,57,115,30,40 + CONTROL "",IDC_SLIDER6,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,99,115,30,40 + CTEXT "LFE (sub)",IDC_STATIC,51,107,42,8 + CTEXT "Rear Left",IDC_STATIC,9,107,42,8 + CTEXT "Rear Right",IDC_STATIC,93,107,42,8 + GROUPBOX "Other Tweaks",IDC_STATIC,153,77,63,97 + CONTROL "",IDC_SLIDER7,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,169,98,30,49 + CTEXT "Center in LR",IDC_STATIC,163,90,42,8 + EDITTEXT IDC_EDIT1,15,88,30,14,ES_AUTOHSCROLL + EDITTEXT IDC_EDIT2,57,88,30,14,ES_AUTOHSCROLL + EDITTEXT IDC_EDIT3,99,88,30,14,ES_AUTOHSCROLL + EDITTEXT IDC_EDIT4,15,155,30,14,ES_AUTOHSCROLL + EDITTEXT IDC_EDIT5,57,155,30,14,ES_AUTOHSCROLL + EDITTEXT IDC_EDIT6,99,155,30,14,ES_AUTOHSCROLL + EDITTEXT IDC_EDIT7,169,150,30,14,ES_AUTOHSCROLL + LTEXT "Number of Buffers",IDC_STATIC,160,32,61,11 + CONTROL "",IDC_BUFFERS_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,229,40,94,10 + LTEXT "Use extra buffers if you are experiencing loopy or studdery audio even when games run at high FPS.",IDC_STATIC,226,69,102,46 + CTEXT "8 (80 ms latency)",IDC_LATENCY_LABEL2,227,29,95,11 + GROUPBOX "Latency",IDC_STATIC,154,13,174,48 END IDD_ASIO DIALOGEX 0, 0, 186, 58 @@ -163,15 +178,19 @@ BEGIN LTEXT "ASIO Driver",IDC_STATIC,7,7,39,8 END -IDD_WAVEOUT DIALOGEX 0, 0, 186, 58 +IDD_WAVEOUT DIALOGEX 0, 0, 170, 122 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "waveOut Output Module Settings" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,75,37,50,14 - PUSHBUTTON "Cancel",IDCANCEL,129,37,50,14 - COMBOBOX IDC_DS_DEVICE,7,17,172,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "waveOut Device",IDC_STATIC,7,7,54,8 + DEFPUSHBUTTON "OK",IDOK,52,104,50,14 + PUSHBUTTON "Cancel",IDCANCEL,115,104,50,14 + COMBOBOX IDC_DS_DEVICE,4,15,161,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "waveOut Device",IDC_STATIC,4,3,54,8 + LTEXT "Number of Buffers",IDC_STATIC,4,39,61,11 + CONTROL "",IDC_BUFFERS_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,71,48,94,10 + LTEXT "Use extra buffers if you are experiencing loopy or studdery audio even when games run at high FPS.",IDC_STATIC,8,66,151,27 + CTEXT "8 (80 ms latency)",IDC_LATENCY_LABEL,70,37,95,11 END @@ -186,9 +205,8 @@ BEGIN IDD_CONFIG, DIALOG BEGIN LEFTMARGIN, 6 - RIGHTMARGIN, 408 - TOPMARGIN, 5 - BOTTOMMARGIN, 212 + RIGHTMARGIN, 405 + BOTTOMMARGIN, 234 END IDD_DEBUG, DIALOG @@ -201,17 +219,17 @@ BEGIN IDD_DSOUND, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 51 + LEFTMARGIN, 4 + RIGHTMARGIN, 165 + TOPMARGIN, 3 + BOTTOMMARGIN, 118 END IDD_DSOUND51, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 258 - TOPMARGIN, 7 + LEFTMARGIN, 5 + RIGHTMARGIN, 331 + TOPMARGIN, 5 BOTTOMMARGIN, 175 END @@ -225,10 +243,10 @@ BEGIN IDD_WAVEOUT, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 51 + LEFTMARGIN, 4 + RIGHTMARGIN, 165 + TOPMARGIN, 3 + BOTTOMMARGIN, 118 END END #endif // APSTUDIO_INVOKED diff --git a/plugins/spu2ghz/asioout.cpp b/plugins/spu2ghz/asioout.cpp index 4515d4321c..d28d174f5b 100644 --- a/plugins/spu2ghz/asioout.cpp +++ b/plugins/spu2ghz/asioout.cpp @@ -36,8 +36,9 @@ private: #ifndef __WIN64__ - #define BufferSize (CurBufferSize<<1) - #define BufferSizeBytes (BufferSize<<2) + // [Air] : This needs fixed. + static const int BufferSize = SndOutPacketSize; + static const int BufferSizeBytes = BufferSize << 2; s32* asio_lbuffer; @@ -175,7 +176,7 @@ private: #define DBL(t) ((t*)(asioDriverInfo.bufferInfos[0].buffers[index])) #define DBR(t) ((t*)(asioDriverInfo.bufferInfos[1].buffers[index])) - int BLen=BufferSize*CurBufferCount; + int BLen=BufferSize*Config_Asio.NumBuffers; int ssize=2; if(showBufferInfo) @@ -241,7 +242,11 @@ private: bufferInfoReady=true; } - buff->ReadSamples(asio_lbuffer,buffSize<<1); + // [Air] : Dunno if this is right... + // Maybe there shouldn't be 2 packets? (doesn't make sense for low + // latency drivers, but then again using ASIO at all doesn't make sense). + buff->ReadSamples(asio_lbuffer); + buff->ReadSamples(&asio_lbuffer[SndOutPacketSize]); s32 asio_read_num = 0; // perform the processing @@ -586,7 +591,7 @@ public: for(int i=0;iasioGetNumDev()>0) @@ -680,6 +685,22 @@ public: #endif return -1; } + + int GetEmptySampleCount() const + { + return 0; + } + + const char* GetIdent() const + { + return "asio"; + } + + const char* GetLongName() const + { + return "ASIO (BROKEN)"; + } + } ASIOMod; SndOutModule *ASIOOut=&ASIOMod; diff --git a/plugins/spu2ghz/config.cpp b/plugins/spu2ghz/config.cpp index bcf2805749..3e622f18bc 100644 --- a/plugins/spu2ghz/config.cpp +++ b/plugins/spu2ghz/config.cpp @@ -20,22 +20,31 @@ #include "dialogs.h" // Config Vars + +static bool VolumeBoostEnabled = false; +static int VolumeShiftModifier = 0; + + // DEBUG bool DebugEnabled=false; -bool MsgToConsole=false; -bool MsgKeyOnOff=false; -bool MsgVoiceOff=false; -bool MsgDMA=false; -bool MsgAutoDMA=false; +bool _MsgToConsole=false; +bool _MsgKeyOnOff=false; +bool _MsgVoiceOff=false; +bool _MsgDMA=false; +bool _MsgAutoDMA=false; +bool _MsgOverruns=false; +bool _MsgCache=false; + +bool _AccessLog=false; +bool _DMALog=false; +bool _WaveLog=false; + +bool _CoresDump=false; +bool _MemDump=false; +bool _RegDump=false; -bool AccessLog=false; -bool DMALog=false; -bool WaveLog=false; -bool CoresDump=false; -bool MemDump=false; -bool RegDump=false; char AccessLogFileName[255]; char WaveLogFileName[255]; @@ -59,19 +68,20 @@ int Interpolation=1; 2. cubic interpolation */ -// EFFECTS bool EffectsEnabled=false; // OUTPUT int SampleRate=48000; -int CurBufferSize=1024; -int MaxBufferCount=8; -int CurBufferCount=MaxBufferCount; +int SndOutLatencyMS=60; +//int SndOutLatency=1024; +//int MaxBufferCount=8; +//int CurBufferCount=MaxBufferCount; +bool timeStretchEnabled=false; -int OutputModule=OUTPUT_DSOUND; +u32 OutputModule=0; //OUTPUT_DSOUND; -int VolumeMultiplier=1; -int VolumeDivisor=1; +//int VolumeMultiplier=1; +//int VolumeDivisor=1; int LimitMode=0; /* values: @@ -80,17 +90,14 @@ int LimitMode=0; 2. Hard limiter -- more cpu-intensive while limiting, but should give better (constant) speeds */ -u32 GainL =256; -u32 GainR =256; -u32 GainSL =200; -u32 GainSR =200; -u32 GainC =200; -u32 GainLFE=256; -u32 AddCLR = 56; -u32 LowpassLFE=80; + +CONFIG_DSOUNDOUT Config_DSoundOut; +CONFIG_DSOUND51 Config_DSound51; +CONFIG_WAVEOUT Config_WaveOut; +CONFIG_ASIO Config_Asio; // MISC -bool LimiterToggleEnabled=true; +bool LimiterToggleEnabled=false; int LimiterToggle=VK_SUBTRACT; // DSP @@ -98,19 +105,15 @@ bool dspPluginEnabled=false; char dspPlugin[256]; int dspPluginModule=0; -bool timeStretchEnabled=false; - // OUTPUT MODULES char AsioDriver[129]=""; -/// module-specific settings - -char DSoundDevice[255]; - ////// -char CfgFile[]="inis\\SPU2Ghz.ini"; +const char NewCfgFile[]="inis\\SPU2Ghz-v2.ini"; +const char LegacyCfgFile[]="inis\\SPU2Ghz.ini"; +const char* CfgFile=NewCfgFile; /*| Config File Format: |ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ*\ @@ -128,26 +131,26 @@ char CfgFile[]="inis\\SPU2Ghz.ini"; \*_____________________________________________*/ -void CfgWriteBool(char *Section, char*Name, bool Value) { +void CfgWriteBool(const char *Section, const char*Name, bool Value) { char *Data=Value?"TRUE":"FALSE"; WritePrivateProfileString(Section,Name,Data,CfgFile); } -void CfgWriteInt(char *Section, char*Name, int Value) { +void CfgWriteInt(const char *Section, const char*Name, int Value) { char Data[255]; _itoa(Value,Data,10); WritePrivateProfileString(Section,Name,Data,CfgFile); } -void CfgWriteStr(char *Section, char*Name,char *Data) { +void CfgWriteStr(const char *Section, const char* Name, const char *Data) { WritePrivateProfileString(Section,Name,Data,CfgFile); } /*****************************************************************************/ -bool CfgReadBool(char *Section,char *Name,bool Default) { +bool CfgReadBool(const char *Section,const char *Name,bool Default) { char Data[255]=""; GetPrivateProfileString(Section,Name,"",Data,255,CfgFile); Data[254]=0; @@ -164,7 +167,8 @@ bool CfgReadBool(char *Section,char *Name,bool Default) { return false; } -int CfgReadInt(char *Section, char*Name,int Default) { + +int CfgReadInt(const char *Section, const char*Name,int Default) { char Data[255]=""; GetPrivateProfileString(Section,Name,"",Data,255,CfgFile); Data[254]=0; @@ -177,7 +181,8 @@ int CfgReadInt(char *Section, char*Name,int Default) { return atoi(Data); } -void CfgReadStr(char *Section, char*Name,char *Data,int DataSize,char *Default) { + +void CfgReadStr(const char *Section, const char* Name, char *Data, int DataSize, const char *Default) { int sl; GetPrivateProfileString(Section,Name,"",Data,DataSize,CfgFile); @@ -188,24 +193,38 @@ void CfgReadStr(char *Section, char*Name,char *Data,int DataSize,char *Default) } } +// Tries to read the requested value. +// Returns FALSE if the value isn't found. +bool CfgFindName( const char *Section, const char* Name) +{ + // Only load 24 characters. No need to load more. + char Data[24]=""; + GetPrivateProfileString(Section,Name,"",Data,24,CfgFile); + Data[23]=0; + + if(strlen(Data)==0) return false; + return true; +} /*****************************************************************************/ void ReadSettings() { - DebugEnabled=CfgReadBool("DEBUG","Global_Debug_Enabled",0); - MsgToConsole=DebugEnabled&CfgReadBool("DEBUG","Show_Messages",0); - MsgKeyOnOff =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_Key_On_Off",0); - MsgVoiceOff =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_Voice_Off",0); - MsgDMA =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_DMA_Transfer",0); - MsgAutoDMA =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_AutoDMA",0); - AccessLog =DebugEnabled&CfgReadBool("DEBUG","Log_Register_Access",0); - DMALog =DebugEnabled&CfgReadBool("DEBUG","Log_DMA_Transfers",0); - WaveLog =DebugEnabled&CfgReadBool("DEBUG","Log_WAVE_Output",0); + _MsgToConsole=CfgReadBool("DEBUG","Show_Messages",0); + _MsgKeyOnOff =CfgReadBool("DEBUG","Show_Messages_Key_On_Off",0); + _MsgVoiceOff =CfgReadBool("DEBUG","Show_Messages_Voice_Off",0); + _MsgDMA =CfgReadBool("DEBUG","Show_Messages_DMA_Transfer",0); + _MsgAutoDMA =CfgReadBool("DEBUG","Show_Messages_AutoDMA",0); + _MsgOverruns =CfgReadBool("DEBUG","Show_Messages_Overruns",0); + _MsgCache =CfgReadBool("DEBUG","Show_Messages_CacheStats",0); - CoresDump =DebugEnabled&CfgReadBool("DEBUG","Dump_Info",0); - MemDump =DebugEnabled&CfgReadBool("DEBUG","Dump_Memory",0); - RegDump =DebugEnabled&CfgReadBool("DEBUG","Dump_Regs",0); + _AccessLog =CfgReadBool("DEBUG","Log_Register_Access",0); + _DMALog =CfgReadBool("DEBUG","Log_DMA_Transfers",0); + _WaveLog =CfgReadBool("DEBUG","Log_WAVE_Output",0); + + _CoresDump =CfgReadBool("DEBUG","Dump_Info",0); + _MemDump =CfgReadBool("DEBUG","Dump_Memory",0); + _RegDump =CfgReadBool("DEBUG","Dump_Regs",0); CfgReadStr("DEBUG","Access_Log_Filename",AccessLogFileName,255,"logs\\SPU2Log.txt"); CfgReadStr("DEBUG","WaveLog_Filename", WaveLogFileName, 255,"logs\\SPU2log.wav"); @@ -218,55 +237,82 @@ void ReadSettings() WaveDumpFormat=CfgReadInt("DEBUG","Wave_Log_Format",0); - - Interpolation=CfgReadInt("MIXING","Interpolation",1); AutoDMAPlayRate[0]=CfgReadInt("MIXING","AutoDMA_Play_Rate_0",0); AutoDMAPlayRate[1]=CfgReadInt("MIXING","AutoDMA_Play_Rate_1",0); - EffectsEnabled=CfgReadBool("EFFECTS","Enable_Effects",0); + Interpolation=CfgReadInt("MIXING","Interpolation",1); + + // Moved Timestretch from DSP to Output + timeStretchEnabled = CfgReadBool( + CfgFindName( "OUTPUT", "Timestretch_Enable" ) ? "OUTPUT" : "DSP", + "Timestretch_Enable", true + ); + + // Moved Effects_Enable from Effects to Mixing + EffectsEnabled = CfgReadBool( + CfgFindName( "MIXING", "Enable_Effects" ) ? "MIXING" : "EFFECTS", + "Enable_Effects", false + ); SampleRate=CfgReadInt("OUTPUT","Sample_Rate",48000); + SndOutLatencyMS=CfgReadInt("OUTPUT","Latency",120); - CurBufferSize=CfgReadInt("OUTPUT","Buffer_Size",1024); - MaxBufferCount=CfgReadInt("OUTPUT","Buffer_Count",10); - if(MaxBufferCount<3) MaxBufferCount=3; - CurBufferCount=MaxBufferCount; + //OutputModule = CfgReadInt("OUTPUT","Output_Module", OUTPUT_DSOUND ); + char omodid[128]; + CfgReadStr( "OUTPUT", "Output_Module", omodid, 127, DSoundOut->GetIdent() ); - OutputModule=CfgReadInt("OUTPUT","Output_Module",OUTPUT_DSOUND); - - VolumeMultiplier=CfgReadInt("OUTPUT","Volume_Multiplier",1); - VolumeDivisor =CfgReadInt("OUTPUT","Volume_Divisor",1); - - GainL =CfgReadInt("OUTPUT","Channel_Gain_L", 256); - GainR =CfgReadInt("OUTPUT","Channel_Gain_R", 256); - GainC =CfgReadInt("OUTPUT","Channel_Gain_C", 256); - GainLFE=CfgReadInt("OUTPUT","Channel_Gain_LFE",256); - GainSL =CfgReadInt("OUTPUT","Channel_Gain_SL", 200); - GainSR =CfgReadInt("OUTPUT","Channel_Gain_SR", 200); - AddCLR =CfgReadInt("OUTPUT","Channel_Center_In_LR", 56); - LowpassLFE = CfgReadInt("OUTPUT","LFE_Lowpass_Frequency", 80); + // find the driver index of this module: + OutputModule = FindOutputModuleById( omodid ); + VolumeShiftModifier = CfgReadInt( "OUTPUT","Volume_Shift", 0 ); LimitMode=CfgReadInt("OUTPUT","Speed_Limit_Mode",0); - CfgReadStr("OUTPUT","Asio_Driver_Name",AsioDriver,128,""); - CfgReadStr("DSP PLUGIN","Filename",dspPlugin,255,""); dspPluginModule = CfgReadInt("DSP PLUGIN","ModuleNum",0); dspPluginEnabled= CfgReadBool("DSP PLUGIN","Enabled",false); - timeStretchEnabled = false; /*CfgReadBool("DSP","Timestretch_Enable",false);*/ //has to be false at init - LimiterToggleEnabled = CfgReadBool("KEYS","Limiter_Toggle_Enabled",false); LimiterToggle = CfgReadInt ("KEYS","Limiter_Toggle",VK_SUBTRACT); - CfgReadStr("DirectSound Output (Stereo)","Device",DSoundDevice,255,""); + // Read DSOUNDOUT and WAVEOUT configs: + CfgReadStr( "DSOUNDOUT", "Device", Config_DSoundOut.Device, 254, "default" ); + CfgReadStr( "WAVEOUT", "Device", Config_WaveOut.Device, 254, "default" ); + Config_DSoundOut.NumBuffers = CfgReadInt( "DSOUNDOUT", "Buffer_Count", 3 ); + Config_WaveOut.NumBuffers = CfgReadInt( "WAVEOUT", "Buffer_Count", 4 ); - if(VolumeMultiplier<0) VolumeMultiplier=-VolumeMultiplier; - else if(VolumeMultiplier==0) VolumeMultiplier=1; + // Read DSOUND51 config: + Config_DSound51.GainL =CfgReadInt("DSOUND51","Channel_Gain_L", 256); + Config_DSound51.GainR =CfgReadInt("DSOUND51","Channel_Gain_R", 256); + Config_DSound51.GainC =CfgReadInt("DSOUND51","Channel_Gain_C", 256); + Config_DSound51.GainLFE=CfgReadInt("DSOUND51","Channel_Gain_LFE",256); + Config_DSound51.GainSL =CfgReadInt("DSOUND51","Channel_Gain_SL", 200); + Config_DSound51.GainSR =CfgReadInt("DSOUND51","Channel_Gain_SR", 200); + Config_DSound51.AddCLR =CfgReadInt("DSOUND51","Channel_Center_In_LR", 56); + Config_DSound51.LowpassLFE = CfgReadInt("DSOUND51","LFE_Lowpass_Frequency", 80); + + // Read ASIOOUT config: + CfgReadStr("ASIO","Asio_Driver_Name",AsioDriver,128,""); + + // Sanity Checks + // ------------- + + SampleRate = 48000; // Yup nothing else is supported for now. + VolumeShiftModifier = min( max( VolumeShiftModifier, -2 ), 2 ); + SndOutVolumeShift = SndOutVolumeShiftBase - VolumeShiftModifier; + SndOutLatencyMS = min( max( SndOutLatencyMS, 20 ), 420 ); + + Config_DSoundOut.NumBuffers = min( max( Config_DSoundOut.NumBuffers, 2 ), 8 ); + Config_WaveOut.NumBuffers = min( max( Config_DSoundOut.NumBuffers, 3 ), 8 ); + + if( mods[OutputModule] == NULL ) + { + // Unsupported or legacy module. + fprintf( stderr, " * SPU2: Unknown output module '%s' specified in configuration file.\n", omodid ); + fprintf( stderr, " * SPU2: Defaulting to DirectSound (%s).\n", DSoundOut->GetIdent() ); + OutputModule = FindOutputModuleById( DSoundOut->GetIdent() ); + } - if(VolumeDivisor<0) VolumeDivisor=-VolumeDivisor; - else if(VolumeDivisor==0) VolumeDivisor=1; } @@ -276,20 +322,24 @@ void WriteSettings() { CfgWriteBool("DEBUG","Global_Debug_Enabled",DebugEnabled); - if(DebugEnabled) { - CfgWriteBool("DEBUG","Show_Messages", MsgToConsole); - CfgWriteBool("DEBUG","Show_Messages_Key_On_Off", MsgKeyOnOff); - CfgWriteBool("DEBUG","Show_Messages_Voice_Off", MsgVoiceOff); - CfgWriteBool("DEBUG","Show_Messages_DMA_Transfer",MsgDMA); - CfgWriteBool("DEBUG","Show_Messages_AutoDMA", MsgAutoDMA); + // [Air] : Commented out so that we retain debug settings even if disabled... + //if(DebugEnabled) + { + CfgWriteBool("DEBUG","Show_Messages", _MsgToConsole); + CfgWriteBool("DEBUG","Show_Messages_Key_On_Off", _MsgKeyOnOff); + CfgWriteBool("DEBUG","Show_Messages_Voice_Off", _MsgVoiceOff); + CfgWriteBool("DEBUG","Show_Messages_DMA_Transfer",_MsgDMA); + CfgWriteBool("DEBUG","Show_Messages_AutoDMA", _MsgAutoDMA); + CfgWriteBool("DEBUG","Show_Messages_Overruns", _MsgOverruns); + CfgWriteBool("DEBUG","Show_Messages_CacheStats", _MsgCache); - CfgWriteBool("DEBUG","Log_Register_Access",AccessLog); - CfgWriteBool("DEBUG","Log_DMA_Transfers", DMALog); - CfgWriteBool("DEBUG","Log_WAVE_Output", WaveLog); + CfgWriteBool("DEBUG","Log_Register_Access",_AccessLog); + CfgWriteBool("DEBUG","Log_DMA_Transfers", _DMALog); + CfgWriteBool("DEBUG","Log_WAVE_Output", _WaveLog); - CfgWriteBool("DEBUG","Dump_Info", CoresDump); - CfgWriteBool("DEBUG","Dump_Memory",MemDump); - CfgWriteBool("DEBUG","Dump_Regs", RegDump); + CfgWriteBool("DEBUG","Dump_Info", _CoresDump); + CfgWriteBool("DEBUG","Dump_Memory",_MemDump); + CfgWriteBool("DEBUG","Dump_Regs", _RegDump); CfgWriteStr("DEBUG","Access_Log_Filename",AccessLogFileName); CfgWriteStr("DEBUG","WaveLog_Filename", WaveLogFileName); @@ -308,67 +358,83 @@ void WriteSettings() CfgWriteInt("MIXING","AutoDMA_Play_Rate_0",AutoDMAPlayRate[0]); CfgWriteInt("MIXING","AutoDMA_Play_Rate_1",AutoDMAPlayRate[1]); - CfgWriteBool("EFFECTS","Enable_Effects",EffectsEnabled); + CfgWriteBool("MIXING","Enable_Effects",EffectsEnabled); - CfgWriteInt("OUTPUT","Output_Module",OutputModule); + CfgWriteStr("OUTPUT","Output_Module",mods[OutputModule]->GetIdent() ); CfgWriteInt("OUTPUT","Sample_Rate",SampleRate); - CfgWriteInt("OUTPUT","Buffer_Size",CurBufferSize); - CfgWriteInt("OUTPUT","Buffer_Count",MaxBufferCount); - - CfgWriteInt("OUTPUT","Volume_Multiplier",VolumeMultiplier); - CfgWriteInt("OUTPUT","Volume_Divisor",VolumeDivisor); - - CfgWriteInt("OUTPUT","Channel_Gain_L", GainL); - CfgWriteInt("OUTPUT","Channel_Gain_R", GainR); - CfgWriteInt("OUTPUT","Channel_Gain_C", GainC); - CfgWriteInt("OUTPUT","Channel_Gain_LFE",GainLFE); - CfgWriteInt("OUTPUT","Channel_Gain_SL", GainSL); - CfgWriteInt("OUTPUT","Channel_Gain_SR", GainSR); - CfgWriteInt("OUTPUT","Channel_Center_In_LR", AddCLR); - CfgWriteInt("OUTPUT","LFE_Lowpass_Frequency", LowpassLFE); - + CfgWriteInt("OUTPUT","Latency",SndOutLatencyMS); + CfgWriteBool("OUTPUT","Timestretch_Enable",timeStretchEnabled); CfgWriteInt("OUTPUT","Speed_Limit_Mode",LimitMode); - CfgWriteStr("OUTPUT","Asio_Driver_Name",AsioDriver); + CfgWriteInt("OUTPUT","Volume_Shift",SndOutVolumeShiftBase - SndOutVolumeShift); + + CfgWriteStr("DSOUNDOUT","Device",Config_DSoundOut.Device); + CfgWriteInt("DSOUNDOUT","Buffer_Count",Config_DSoundOut.NumBuffers); + + CfgWriteStr("WAVEOUT","Device",Config_WaveOut.Device); + CfgWriteInt("WAVEOUT","Buffer_Count",Config_WaveOut.NumBuffers); + + CfgWriteInt("DSOUND51","Channel_Gain_L", Config_DSound51.GainL); + CfgWriteInt("DSOUND51","Channel_Gain_R", Config_DSound51.GainR); + CfgWriteInt("DSOUND51","Channel_Gain_C", Config_DSound51.GainC); + CfgWriteInt("DSOUND51","Channel_Gain_LFE",Config_DSound51.GainLFE); + CfgWriteInt("DSOUND51","Channel_Gain_SL", Config_DSound51.GainSL); + CfgWriteInt("DSOUND51","Channel_Gain_SR", Config_DSound51.GainSR); + CfgWriteInt("DSOUND51","Channel_Center_In_LR", Config_DSound51.AddCLR); + CfgWriteInt("DSOUND51","LFE_Lowpass_Frequency", Config_DSound51.LowpassLFE); + + CfgWriteStr("ASIO","Asio_Driver_Name",AsioDriver); CfgWriteStr("DSP PLUGIN","Filename",dspPlugin); CfgWriteInt("DSP PLUGIN","ModuleNum",dspPluginModule); CfgWriteBool("DSP PLUGIN","Enabled",dspPluginEnabled); - CfgWriteBool("DSP","Timestretch_Enable",timeStretchEnabled); - CfgWriteBool("KEYS","Limiter_Toggle_Enabled",LimiterToggleEnabled); CfgWriteInt ("KEYS","Limiter_Toggle",LimiterToggle); - - CfgWriteStr("DirectSound Output (Stereo)","Device",DSoundDevice); } +static void EnableDebugMessages( HWND hWnd ) +{ + ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled); + ENABLE_CONTROL(IDC_MSGKEY, MsgToConsole()); + ENABLE_CONTROL(IDC_MSGVOICE,MsgToConsole()); + ENABLE_CONTROL(IDC_MSGDMA, MsgToConsole()); + ENABLE_CONTROL(IDC_MSGADMA, MsgDMA()); + ENABLE_CONTROL(IDC_DBG_OVERRUNS, MsgToConsole()); + ENABLE_CONTROL(IDC_DBG_CACHE, MsgToConsole()); +} + +static void EnableDebugControls( HWND hWnd ) +{ + EnableDebugMessages( hWnd ); + ENABLE_CONTROL(IDC_LOGREGS, DebugEnabled); + ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled); + ENABLE_CONTROL(IDC_LOGWAVE, DebugEnabled); + ENABLE_CONTROL(IDC_DUMPCORE,DebugEnabled); + ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled); + ENABLE_CONTROL(IDC_DUMPREGS,DebugEnabled); +} + +static int myWidth, myDebugWidth; +static int myHeight; +static bool debugShow = false; + BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { int wmId,wmEvent; - char temp[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + char temp[384]={0}; switch(uMsg) { case WM_PAINT: - SET_CHECK(IDC_EFFECTS, EffectsEnabled); - SET_CHECK(IDC_DEBUG, DebugEnabled); - SET_CHECK(IDC_MSGKEY, DebugEnabled&MsgToConsole); - SET_CHECK(IDC_MSGKEY, DebugEnabled&MsgKeyOnOff); - SET_CHECK(IDC_MSGVOICE,DebugEnabled&MsgVoiceOff); - SET_CHECK(IDC_MSGDMA, DebugEnabled&MsgDMA); - SET_CHECK(IDC_MSGADMA, DebugEnabled&MsgDMA&MsgAutoDMA); - SET_CHECK(IDC_LOGREGS, AccessLog); - SET_CHECK(IDC_LOGDMA, DMALog); - SET_CHECK(IDC_LOGWAVE, WaveLog); - SET_CHECK(IDC_DUMPCORE,CoresDump); - SET_CHECK(IDC_DUMPMEM, MemDump); - SET_CHECK(IDC_DUMPREGS,RegDump); - SET_CHECK(IDC_SPEEDLIMIT,LimitMode); return FALSE; + case WM_INITDIALOG: + // If debugging is enabled, show the debug box by default: + debugShow = DebugEnabled; + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_RESETCONTENT,0,0); SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"16000"); SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"22050"); @@ -377,62 +443,64 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"44100"); SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"48000"); - sprintf(temp,"%d",SampleRate); + sprintf_s(temp,48,"%d",SampleRate); SetDlgItemText(hWnd,IDC_SRATE,temp); SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_RESETCONTENT,0,0); - SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"0 - Nearest (none)"); - SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"1 - Linear (mid)"); - SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"2 - Cubic (good)"); + SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"0 - Nearest (none/fast)"); + SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"1 - Linear (recommended)"); + SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"2 - Cubic (better/slower)"); SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_SETCURSEL,Interpolation,0); - SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_RESETCONTENT,0,0); - SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"0 - Disabled (Emulate only)"); - SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"1 - waveOut (Slow/Laggy)"); - SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"2 - DSound (Typical)"); - SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"3 - DSound 5.1 (Experimental)"); - SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"4 - ASIO (Low Latency, BROKEN)"); - SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"5 - XAudio2 (Experimental)"); + SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_RESETCONTENT,0,0); + + { + int modidx = 0; + while( mods[modidx] != NULL ) + { + sprintf_s( temp, 72, "%d - %s", modidx, mods[modidx]->GetLongName() ); + SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)temp); + ++modidx; + } SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_SETCURSEL,OutputModule,0); + } - INIT_SLIDER(IDC_BUFFER,512,16384,4096,2048,512); + //INIT_SLIDER(IDC_BUFFER,512,16384,4096,2048,512); + INIT_SLIDER( IDC_LATENCY_SLIDER, 20, 420, 100, 20, 5 ); - SendMessage(GetDlgItem(hWnd,IDC_BUFFER),TBM_SETPOS,TRUE,CurBufferSize); - sprintf(temp,"%d",CurBufferSize); - SetWindowText(GetDlgItem(hWnd,IDC_BSIZE),temp); + SendMessage(GetDlgItem(hWnd,IDC_LATENCY_SLIDER),TBM_SETPOS,TRUE,SndOutLatencyMS); + sprintf_s(temp,80,"%d ms (avg)",SndOutLatencyMS); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); - sprintf(temp,"%d",MaxBufferCount); - SetWindowText(GetDlgItem(hWnd,IDC_BCOUNT),temp); - - ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled); - ENABLE_CONTROL(IDC_MSGKEY, DebugEnabled&MsgToConsole); - ENABLE_CONTROL(IDC_MSGVOICE,DebugEnabled&MsgToConsole); - ENABLE_CONTROL(IDC_MSGDMA, DebugEnabled&MsgToConsole); - ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA); - ENABLE_CONTROL(IDC_LOGREGS, DebugEnabled); - ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled); - ENABLE_CONTROL(IDC_LOGWAVE, DebugEnabled); - ENABLE_CONTROL(IDC_DUMPCORE,DebugEnabled); - ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled); - ENABLE_CONTROL(IDC_DUMPREGS,DebugEnabled); + EnableDebugControls( hWnd ); + // Debugging / Logging Flags: SET_CHECK(IDC_EFFECTS, EffectsEnabled); SET_CHECK(IDC_DEBUG, DebugEnabled); - SET_CHECK(IDC_MSGSHOW, MsgToConsole); - SET_CHECK(IDC_MSGKEY, MsgKeyOnOff); - SET_CHECK(IDC_MSGVOICE,MsgVoiceOff); - SET_CHECK(IDC_MSGDMA, MsgDMA); - SET_CHECK(IDC_MSGADMA, MsgAutoDMA); - SET_CHECK(IDC_LOGREGS, AccessLog); - SET_CHECK(IDC_LOGDMA, DMALog); - SET_CHECK(IDC_LOGWAVE, WaveLog); - SET_CHECK(IDC_DUMPCORE,CoresDump); - SET_CHECK(IDC_DUMPMEM, MemDump); - SET_CHECK(IDC_DUMPREGS,RegDump); + SET_CHECK(IDC_MSGKEY, _MsgToConsole); + SET_CHECK(IDC_MSGKEY, _MsgKeyOnOff); + SET_CHECK(IDC_MSGVOICE,_MsgVoiceOff); + SET_CHECK(IDC_MSGDMA, _MsgDMA); + SET_CHECK(IDC_MSGADMA, _MsgAutoDMA); + SET_CHECK(IDC_DBG_OVERRUNS, _MsgOverruns ); + SET_CHECK(IDC_DBG_CACHE, _MsgCache ); + SET_CHECK(IDC_LOGREGS, _AccessLog); + SET_CHECK(IDC_LOGDMA, _DMALog); + SET_CHECK(IDC_LOGWAVE, _WaveLog); + SET_CHECK(IDC_DUMPCORE,_CoresDump); + SET_CHECK(IDC_DUMPMEM, _MemDump); + SET_CHECK(IDC_DUMPREGS,_RegDump); + SET_CHECK(IDC_SPEEDLIMIT,LimitMode); + SET_CHECK(IDC_SPEEDLIMIT_RUNTIME_TOGGLE,LimiterToggleEnabled); SET_CHECK(IDC_DSP_ENABLE,dspPluginEnabled); SET_CHECK(IDC_TS_ENABLE,timeStretchEnabled); + + VolumeBoostEnabled = ( VolumeShiftModifier > 0 ) ? true : false; + SET_CHECK(IDC_VOLBOOST, VolumeBoostEnabled ); + break; + case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); @@ -444,49 +512,14 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) temp[19]=0; SampleRate=atoi(temp); - GetDlgItemText(hWnd,IDC_BSIZE,temp,20); - temp[19]=0; - CurBufferSize=atoi(temp); + SndOutLatencyMS = (int)SendMessage( GetDlgItem( hWnd, IDC_LATENCY_SLIDER ), TBM_GETPOS, 0, 0 ); - if(CurBufferSize<512) CurBufferSize=512; - if(CurBufferSize>16384) CurBufferSize=16384; - - GetDlgItemText(hWnd,IDC_BCOUNT,temp,20); - temp[19]=0; - MaxBufferCount=atoi(temp); - - if(MaxBufferCount<4) MaxBufferCount=4; - if(MaxBufferCount>50) MaxBufferCount=50; + if( SndOutLatencyMS > 420 ) SndOutLatencyMS = 420; + if( SndOutLatencyMS < 20 ) SndOutLatencyMS = 20; Interpolation=(int)SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_GETCURSEL,0,0); OutputModule=(int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0); - /* - if((BufferSize*CurBufferCount)<9600) - { - int ret=MessageBoxEx(hWnd,"The total buffer space is too small and might cause problems.\n" - "Press [Cancel] to go back and increase the buffer size or number.", - "WARNING",MB_OKCANCEL | MB_ICONEXCLAMATION, 0); - if(ret==IDCANCEL) - break; - } - */ - - DebugEnabled=DebugEnabled; - MsgToConsole=DebugEnabled&MsgToConsole; - MsgKeyOnOff =DebugEnabled&MsgToConsole&MsgKeyOnOff; - MsgVoiceOff =DebugEnabled&MsgToConsole&MsgVoiceOff; - MsgDMA =DebugEnabled&MsgToConsole&MsgDMA; - MsgAutoDMA =DebugEnabled&MsgToConsole&MsgAutoDMA; - AccessLog =DebugEnabled&AccessLog; - DMALog =DebugEnabled&DMALog; - WaveLog =DebugEnabled&WaveLog; - - CoresDump =DebugEnabled&CoresDump; - MemDump =DebugEnabled&MemDump; - RegDump =DebugEnabled&RegDump; - - WriteSettings(); EndDialog(hWnd,0); break; @@ -495,45 +528,41 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) break; case IDC_OUTCONF: - SndConfigure(hWnd); + SndConfigure( hWnd, + (int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0) + ); + break; + + HANDLE_CHECKNB( IDC_VOLBOOST, VolumeBoostEnabled ); + VolumeShiftModifier = (VolumeBoostEnabled ? 1 : 0 ); + SndOutVolumeShift = SndOutVolumeShiftBase - VolumeShiftModifier; break; - HANDLE_CHECK(IDC_EFFECTS,EffectsEnabled); HANDLE_CHECKNB(IDC_DEBUG,DebugEnabled); - ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled); - ENABLE_CONTROL(IDC_MSGKEY, DebugEnabled&MsgToConsole); - ENABLE_CONTROL(IDC_MSGVOICE,DebugEnabled&MsgToConsole); - ENABLE_CONTROL(IDC_MSGDMA, DebugEnabled&MsgToConsole); - ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA); - ENABLE_CONTROL(IDC_LOGREGS, DebugEnabled); - ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled); - ENABLE_CONTROL(IDC_LOGWAVE, DebugEnabled); - ENABLE_CONTROL(IDC_DUMPCORE,DebugEnabled); - ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled); - ENABLE_CONTROL(IDC_DUMPREGS,DebugEnabled); + EnableDebugControls( hWnd ); break; - HANDLE_CHECKNB(IDC_MSGSHOW,MsgToConsole); - ENABLE_CONTROL(IDC_MSGKEY, DebugEnabled&MsgToConsole); - ENABLE_CONTROL(IDC_MSGVOICE,DebugEnabled&MsgToConsole); - ENABLE_CONTROL(IDC_MSGDMA, DebugEnabled&MsgToConsole); - ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA); + HANDLE_CHECKNB(IDC_MSGSHOW,_MsgToConsole); + EnableDebugMessages( hWnd ); break; - HANDLE_CHECK(IDC_MSGKEY,MsgKeyOnOff); - HANDLE_CHECK(IDC_MSGVOICE,MsgVoiceOff); - HANDLE_CHECKNB(IDC_MSGDMA,MsgDMA); - ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA); + HANDLE_CHECK(IDC_MSGKEY,_MsgKeyOnOff); + HANDLE_CHECK(IDC_MSGVOICE,_MsgVoiceOff); + HANDLE_CHECKNB(IDC_MSGDMA,_MsgDMA); + ENABLE_CONTROL(IDC_MSGADMA, MsgDMA()); break; - HANDLE_CHECK(IDC_MSGADMA,MsgAutoDMA); - HANDLE_CHECK(IDC_LOGREGS,AccessLog); - HANDLE_CHECK(IDC_LOGDMA, DMALog); - HANDLE_CHECK(IDC_LOGWAVE,WaveLog); - HANDLE_CHECK(IDC_DUMPCORE,CoresDump); - HANDLE_CHECK(IDC_DUMPMEM, MemDump); - HANDLE_CHECK(IDC_DUMPREGS,RegDump); - HANDLE_CHECK(IDC_SPEEDLIMIT,LimitMode); + HANDLE_CHECK(IDC_MSGADMA,_MsgAutoDMA); + HANDLE_CHECK(IDC_DBG_OVERRUNS,_MsgOverruns); + HANDLE_CHECK(IDC_DBG_CACHE,_MsgCache); + HANDLE_CHECK(IDC_LOGREGS,_AccessLog); + HANDLE_CHECK(IDC_LOGDMA, _DMALog); + HANDLE_CHECK(IDC_LOGWAVE,_WaveLog); + HANDLE_CHECK(IDC_DUMPCORE,_CoresDump); + HANDLE_CHECK(IDC_DUMPMEM, _MemDump); + HANDLE_CHECK(IDC_DUMPREGS,_RegDump); HANDLE_CHECK(IDC_DSP_ENABLE,dspPluginEnabled); HANDLE_CHECK(IDC_TS_ENABLE,timeStretchEnabled); + HANDLE_CHECK(IDC_SPEEDLIMIT,LimitMode); + HANDLE_CHECK(IDC_SPEEDLIMIT_RUNTIME_TOGGLE,LimiterToggleEnabled); default: return FALSE; } @@ -550,11 +579,11 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) case TB_PAGEDOWN: wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); case TB_THUMBTRACK: - if(wmEvent<512) wmEvent=512; - if(wmEvent>24000) wmEvent=24000; + if(wmEvent<20) wmEvent=20; + if(wmEvent>420) wmEvent=420; SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); - sprintf(temp,"%d",wmEvent); - SetDlgItemText(hWnd,IDC_BSIZE,temp); + sprintf_s(temp,80,"%d ms (avg)",wmEvent); + SetDlgItemText(hWnd,IDC_LATENCY_LABEL,temp); break; default: return FALSE; diff --git a/plugins/spu2ghz/config.h b/plugins/spu2ghz/config.h index 0abee4bf1c..082df50474 100644 --- a/plugins/spu2ghz/config.h +++ b/plugins/spu2ghz/config.h @@ -21,19 +21,39 @@ extern bool DebugEnabled; -extern bool MsgToConsole; -extern bool MsgKeyOnOff; -extern bool MsgVoiceOff; -extern bool MsgDMA; -extern bool MsgAutoDMA; +extern bool _MsgToConsole; +extern bool _MsgKeyOnOff; +extern bool _MsgVoiceOff; +extern bool _MsgDMA; +extern bool _MsgAutoDMA; +extern bool _MsgOverruns; +extern bool _MsgCache; -extern bool AccessLog; -extern bool DMALog; -extern bool WaveLog; +extern bool _AccessLog; +extern bool _DMALog; +extern bool _WaveLog; + +extern bool _CoresDump; +extern bool _MemDump; +extern bool _RegDump; + +static __forceinline bool MsgToConsole() { return _MsgToConsole & DebugEnabled; } + +static __forceinline bool MsgKeyOnOff() { return _MsgKeyOnOff & MsgToConsole(); } +static __forceinline bool MsgVoiceOff() { return _MsgVoiceOff & MsgToConsole(); } +static __forceinline bool MsgDMA() { return _MsgDMA & MsgToConsole(); } +static __forceinline bool MsgAutoDMA() { return _MsgAutoDMA & MsgToConsole(); } +static __forceinline bool MsgOverruns() { return _MsgOverruns & MsgToConsole(); } +static __forceinline bool MsgCache() { return _MsgCache & MsgToConsole(); } + +static __forceinline bool AccessLog() { return _AccessLog & DebugEnabled; } +static __forceinline bool DMALog() { return _DMALog & DebugEnabled; } +static __forceinline bool WaveLog() { return _WaveLog & DebugEnabled; } + +static __forceinline bool CoresDump() { return _CoresDump & DebugEnabled; } +static __forceinline bool MemDump() { return _MemDump & DebugEnabled; } +static __forceinline bool RegDump() { return _RegDump & DebugEnabled; } -extern bool CoresDump; -extern bool MemDump; -extern bool RegDump; extern char AccessLogFileName[255]; extern char WaveLogFileName[255]; @@ -55,27 +75,16 @@ extern bool EffectsEnabled; extern int AutoDMAPlayRate[2]; -extern int OutputModule; -extern int CurBufferSize; -extern int CurBufferCount; -extern int MaxBufferCount; +extern u32 OutputModule; +extern int SndOutLatencyMS; -extern int VolumeMultiplier; -extern int VolumeDivisor; +//extern int VolumeMultiplier; +//extern int VolumeDivisor; extern int LimitMode; extern char AsioDriver[129]; -extern u32 GainL; -extern u32 GainR; -extern u32 GainC; -extern u32 GainLFE; -extern u32 GainSL; -extern u32 GainSR; -extern u32 AddCLR; -extern u32 LowpassLFE; - extern char dspPlugin[]; extern int dspPluginModule; @@ -85,9 +94,82 @@ extern bool timeStretchEnabled; extern bool LimiterToggleEnabled; extern int LimiterToggle; -/// module-specific settings +// *** BEGIN DRIVER-SPECIFIC CONFIGURATION *** +// ------------------------------------------- -extern char DSoundDevice[]; +// DSOUND +struct CONFIG_DSOUNDOUT +{ + char Device[256]; + s8 NumBuffers; + + CONFIG_DSOUNDOUT() : + NumBuffers( 3 ) + { + memset( Device, 0, sizeof( Device ) ); + } +}; + +// WAVEOUT +struct CONFIG_WAVEOUT +{ + char Device[255]; + s8 NumBuffers; + + CONFIG_WAVEOUT() : + NumBuffers( 4 ) + { + memset( Device, 0, sizeof( Device ) ); + } +}; + +// DSOUND51 +struct CONFIG_DSOUND51 +{ + char Device[256]; + u32 NumBuffers; + + u32 GainL; + u32 GainR; + u32 GainSL; + u32 GainSR; + u32 GainC; + u32 GainLFE; + u32 AddCLR; + u32 LowpassLFE; + + // C++ style struct/class initializer + CONFIG_DSOUND51() : + NumBuffers( 4 ) + , GainL( 256 ) + , GainR( 256 ) + , GainSL( 200 ) + , GainSR( 200 ) + , GainC( 200 ) + , GainLFE( 256 ) + , AddCLR( 56 ) + , LowpassLFE( 80 ) + { + memset( Device, 0, sizeof( Device ) ); + } +}; + +struct CONFIG_ASIO +{ + s8 NumBuffers; + + CONFIG_ASIO() : + NumBuffers( 8 ) + { + //memset( Device, 0, sizeof( Device ) ); + } +}; + + +extern CONFIG_DSOUNDOUT Config_DSoundOut; +extern CONFIG_DSOUND51 Config_DSound51; +extern CONFIG_WAVEOUT Config_WaveOut; +extern CONFIG_ASIO Config_Asio; ////// @@ -96,4 +178,4 @@ void ReadSettings(); void WriteSettings(); void configure(); -#endif // CONFIG_H_INCLUDED \ No newline at end of file +#endif // CONFIG_H_INCLUDED diff --git a/plugins/spu2ghz/debug.cpp b/plugins/spu2ghz/debug.cpp index cb4e9c615c..8bd687dfa8 100644 --- a/plugins/spu2ghz/debug.cpp +++ b/plugins/spu2ghz/debug.cpp @@ -29,8 +29,7 @@ void FileLog(const char *fmt, ...) { int n; va_list list; - if(!DebugEnabled) return; - if(!AccessLog) return; + if(!AccessLog()) return; if(!spu2Log) return; va_start(list, fmt); @@ -55,8 +54,7 @@ void ConLog(const char *fmt, ...) { int n; va_list list; - if(!DebugEnabled) return; - if(!MsgToConsole) return; + if(!MsgToConsole()) return; va_start(list, fmt); n=vsprintf(s,fmt, list); @@ -78,14 +76,14 @@ void DoFullDump() { FILE *dump; u8 c=0, v=0; - if(MemDump) { + if(MemDump()) { dump=fopen(MemDumpFileName,"wb"); if (dump) { fwrite(_spu2mem,0x200000,1,dump); fclose(dump); } } - if(RegDump) { + if(RegDump()) { dump=fopen(RegDumpFileName,"wb"); if (dump) { fwrite(spu2regs,0x2000,1,dump); @@ -93,7 +91,7 @@ void DoFullDump() { } } - if(!CoresDump) return; + if(!CoresDump()) return; dump=fopen(CoresDumpFileName,"wt"); if (dump) { for(c=0;c<2;c++) { diff --git a/plugins/spu2ghz/dma.cpp b/plugins/spu2ghz/dma.cpp index 0bb3e7a451..2bf9acfe64 100644 --- a/plugins/spu2ghz/dma.cpp +++ b/plugins/spu2ghz/dma.cpp @@ -34,7 +34,7 @@ u16* MBASE[2] = {0,0}; u16* DMABaseAddr; void DMALogOpen() { - if(!DMALog) return; + if(!DMALog()) return; DMA4LogFile=fopen(DMA4LogFileName,"wb"); DMA7LogFile=fopen(DMA7LogFileName,"wb"); ADMA4LogFile=fopen("logs/adma4.raw","wb"); @@ -44,42 +44,42 @@ void DMALogOpen() { //REGWRTLogFile[1]=fopen("logs/RegWrite1.raw","wb"); } void DMA4LogWrite(void *lpData, u32 ulSize) { - if(!DMALog) return; + if(!DMALog()) return; if (!DMA4LogFile) return; fwrite(lpData,ulSize,1,DMA4LogFile); } void DMA7LogWrite(void *lpData, u32 ulSize) { - if(!DMALog) return; + if(!DMALog()) return; if (!DMA7LogFile) return; fwrite(lpData,ulSize,1,DMA7LogFile); } void ADMA4LogWrite(void *lpData, u32 ulSize) { - if(!DMALog) return; + if(!DMALog()) return; if (!ADMA4LogFile) return; fwrite(lpData,ulSize,1,ADMA4LogFile); } void ADMA7LogWrite(void *lpData, u32 ulSize) { - if(!DMALog) return; + if(!DMALog()) return; if (!ADMA7LogFile) return; fwrite(lpData,ulSize,1,ADMA7LogFile); } void ADMAOutLogWrite(void *lpData, u32 ulSize) { - if(!DMALog) return; + if(!DMALog()) return; if (!ADMAOutLogFile) return; fwrite(lpData,ulSize,1,ADMAOutLogFile); } void RegWriteLog(u32 core,u16 value) { - if(!DMALog) return; + if(!DMALog()) return; if (!REGWRTLogFile[core]) return; fwrite(&value,2,1,REGWRTLogFile[core]); } void DMALogClose() { - if(!DMALog) return; + if(!DMALog()) return; if (DMA4LogFile) fclose(DMA4LogFile); if (DMA7LogFile) fclose(DMA7LogFile); if (REGWRTLogFile[0]) fclose(REGWRTLogFile[0]); @@ -142,7 +142,7 @@ void AutoDMAReadBuffer(int core, int mode) //mode: 0= split stereo; 1 = do not s void StartADMAWrite(int core,u16 *pMem, u32 sz) { int size=(sz)&(~511); - if(MsgAutoDMA) ConLog(" * SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff); + if(MsgAutoDMA()) ConLog(" * SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff); Cores[core].InputDataProgress=0; if((Cores[core].AutoDMACtrl&(core+1))==0) @@ -202,7 +202,7 @@ void DoDMAWrite(int core,u16 *pMem,u32 size) else DMA7LogWrite(pMem,size<<1); - if(MsgDMA) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff); + if(MsgDMA()) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff); Cores[core].TDA=Cores[core].TSA; for (i=0;i>8; //16.0 SR = (SRd * 209 + SC * 148)>>8; //16.0 - obuffer[0]=spdif_data[0] + (((L * GainL ) + (C * AddCLR))>>8); - obuffer[1]=spdif_data[1] + (((R * GainR ) + (C * AddCLR))>>8); - obuffer[2]=spdif_data[2] + (((C * GainC ))>>8); - obuffer[3]=spdif_data[3] + (((LFE * GainLFE))>>8); - obuffer[4]=spdif_data[4] + (((SL * GainSL ))>>8); - obuffer[5]=spdif_data[5] + (((SR * GainSR ))>>8); + obuffer[0]=spdif_data[0] + (((L * Config_DSound51.GainL ) + (C * Config_DSound51.AddCLR))>>8); + obuffer[1]=spdif_data[1] + (((R * Config_DSound51.GainR ) + (C * Config_DSound51.AddCLR))>>8); + obuffer[2]=spdif_data[2] + (((C * Config_DSound51.GainC ))>>8); + obuffer[3]=spdif_data[3] + (((LFE * Config_DSound51.GainLFE))>>8); + obuffer[4]=spdif_data[4] + (((SL * Config_DSound51.GainSL ))>>8); + obuffer[5]=spdif_data[5] + (((SR * Config_DSound51.GainSR ))>>8); #else obuffer[0]=spdif_data[0]+(ValL>>8); obuffer[1]=spdif_data[1]+(ValR>>8); @@ -245,33 +243,35 @@ private: { while( dsound_running ) { - u32 rv = WaitForMultipleObjects(MAX_BUFFER_COUNT,buffer_events,FALSE,400); + u32 rv = WaitForMultipleObjects(Config_DSound51.NumBuffers,buffer_events,FALSE,200); - LPVOID p1,p2; + s16* p1, *oldp1; + LPVOID p2; DWORD s1,s2; - for(int i=0;iLock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0)); + oldp1 = p1; + + for(int p=0; pReadSamples( temp ); + for(int j=0;jReadSamples(tbuffer,CurBufferSize*2); - - verifyc(buffer->Lock(poffset,BufferSizeBytes,&p1,&s1,&p2,&s2,0)); - s16 *t = (s16*)p1; - s32 *s = tbuffer; - for(int j=0;jUnlock(p1,s1,p2,s2)); - } + t+=6; + s+=2; + } } + + verifyc(buffer->Unlock(oldp1,s1,p2,s2)); } return 0; } @@ -279,8 +279,6 @@ private: public: s32 Init(SndBuffer *sb) { - if(CurBufferSize<1024) CurBufferSize=1024; - buff = sb; // @@ -313,7 +311,7 @@ public: memset(&desc, 0, sizeof(DSBUFFERDESC)); desc.dwSize = sizeof(DSBUFFERDESC); desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; - desc.dwBufferBytes = BufferSizeBytes * MAX_BUFFER_COUNT; + desc.dwBufferBytes = BufferSizeBytes * Config_DSound51.NumBuffers; desc.lpwfxFormat = &wfx.Format; desc.dwFlags |=DSBCAPS_LOCSOFTWARE; @@ -327,14 +325,14 @@ public: DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT]; - for(int i=0;iSetNotificationPositions(MAX_BUFFER_COUNT,not); + buffer_notify->SetNotificationPositions(Config_DSound51.NumBuffers,not); LPVOID p1=0,p2=0; DWORD s1=0,s2=0; @@ -344,13 +342,13 @@ public: memset(p1,0,s1); verifyc(buffer->Unlock(p1,s1,p2,s2)); - LPF_init(&lpf_l,LowpassLFE,SampleRate); - LPF_init(&lpf_r,LowpassLFE,SampleRate); + LPF_init(&lpf_l,Config_DSound51.LowpassLFE,SampleRate); + LPF_init(&lpf_r,Config_DSound51.LowpassLFE,SampleRate); //Play the buffer ! verifyc(buffer->Play(0,0,DSBPLAY_LOOPING)); - tbuffer = new s32[BufferSize]; + tbuffer = new s32[SndOutPacketSize]; // Start Thread dsound_running=true; @@ -376,7 +374,7 @@ public: // buffer->Stop(); - for(int i=0;iRelease(); @@ -425,7 +423,7 @@ private: if(wmEventvmax) wmEvent=vmax; SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); - sprintf(temp,"%d",vmax-wmEvent); + sprintf_s(temp,1024,"%d",vmax-wmEvent); SetWindowText(hwndDisplay,temp); break; default: @@ -445,7 +443,7 @@ private: { case WM_INITDIALOG: - haveGuid = ! FAILED(GUIDFromString(DSoundDevice,&DevGuid)); + haveGuid = ! FAILED(GUIDFromString(Config_DSound51.Device,&DevGuid)); SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_RESETCONTENT,0,0); ndevs=0; @@ -474,6 +472,12 @@ private: INIT_SLIDER(IDC_SLIDER6,0,512,64,16,8); INIT_SLIDER(IDC_SLIDER7,0,512,64,16,8); + char temp[128]; + INIT_SLIDER( IDC_BUFFERS_SLIDER, 2, MAX_BUFFER_COUNT, 2, 1, 1 ); + SendMessage(GetDlgItem(hWnd,IDC_BUFFERS_SLIDER),TBM_SETPOS,TRUE,Config_DSound51.NumBuffers); + sprintf_s(temp, 128, "%d (%d ms latency)",Config_DSound51.NumBuffers, 1000 / (96000 / (Config_DSound51.NumBuffers * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + break; case WM_COMMAND: wmId = LOWORD(wParam); @@ -487,11 +491,11 @@ private: if(!devices[i].hasGuid) { - DSoundDevice[0]=0; // clear device name to "" + Config_DSound51.Device[0]=0; // clear device name to "" } else { - sprintf_s(DSoundDevice,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + sprintf_s(Config_DSound51.Device,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", devices[i].guid.Data1, devices[i].guid.Data2, devices[i].guid.Data3, @@ -504,6 +508,11 @@ private: devices[i].guid.Data4[6], devices[i].guid.Data4[7] ); + + Config_DSound51.NumBuffers = (int)SendMessage( GetDlgItem( hWnd, IDC_BUFFERS_SLIDER ), TBM_GETPOS, 0, 0 ); + + if( Config_DSound51.NumBuffers < 2 ) Config_DSound51.NumBuffers = 2; + if( Config_DSound51.NumBuffers > MAX_BUFFER_COUNT ) Config_DSound51.NumBuffers = MAX_BUFFER_COUNT; } } EndDialog(hWnd,0); @@ -515,6 +524,30 @@ private: return FALSE; } break; + + case WM_HSCROLL: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + switch(wmId) { + //case TB_ENDTRACK: + //case TB_THUMBPOSITION: + case TB_LINEUP: + case TB_LINEDOWN: + case TB_PAGEUP: + case TB_PAGEDOWN: + wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); + case TB_THUMBTRACK: + if( wmEvent < 2 ) wmEvent = 2; + if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT; + SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); + sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + break; + default: + return FALSE; + } + break; + case WM_VSCROLL: HANDLE_SCROLL_MESSAGE(IDC_SLIDER1,0,512,IDC_EDIT1); HANDLE_SCROLL_MESSAGE(IDC_SLIDER2,0,512,IDC_EDIT2); @@ -542,13 +575,27 @@ public: } } - s32 Test() + s32 Test() const { return 0; } - bool Is51Out() { return true; } + bool Is51Out() const { return true; } + int GetEmptySampleCount() const + { + return 0; + } + + const char* GetIdent() const + { + return "dsound51"; + } + + const char* GetLongName() const + { + return "DSound 5.1 (Experimental)"; + } } DS51; -SndOutModule *DSound51Out=&DS51; \ No newline at end of file +SndOutModule *DSound51Out=&DS51; diff --git a/plugins/spu2ghz/dsoundout.cpp b/plugins/spu2ghz/dsoundout.cpp index 768f3be322..42e5590660 100644 --- a/plugins/spu2ghz/dsoundout.cpp +++ b/plugins/spu2ghz/dsoundout.cpp @@ -68,12 +68,11 @@ HRESULT GUIDFromString(const char *str, LPGUID guid) class DSound: public SndOutModule { private: -# define PI 3.14159265f + # define MAX_BUFFER_COUNT 8 -# define BufferSize (CurBufferSize<<1) -# define BufferSizeBytes (BufferSize<<1) - -# define TBufferSize (BufferSize*CurBufferCount) + static const int PacketsPerBuffer = (1024 / SndOutPacketSize); + static const int BufferSize = SndOutPacketSize * PacketsPerBuffer; + static const int BufferSizeBytes = BufferSize << 1; FILE *voicelog; @@ -83,8 +82,6 @@ private: HANDLE thread; DWORD tid; -# define MAX_BUFFER_COUNT 5 - IDirectSound8* dsound; IDirectSoundBuffer8* buffer; IDirectSoundNotify8* buffer_notify; @@ -96,10 +93,7 @@ private: SndBuffer *buff; - s32 *tbuffer; - # define STRFY(x) #x - # define verifyc(x) if(Verifyc(x,STRFY(x))) return -1; int __forceinline Verifyc(HRESULT hr,const char* fn) @@ -122,36 +116,21 @@ private: while( dsound_running ) { - u32 rv = WaitForMultipleObjects(MAX_BUFFER_COUNT,buffer_events,FALSE,400); + u32 rv = WaitForMultipleObjects(Config_DSoundOut.NumBuffers,buffer_events,FALSE,200); - LPVOID p1,p2; + s16* p1, *oldp1; + LPVOID p2; DWORD s1,s2; u32 poffset=BufferSizeBytes * rv; - //DWORD play, write; - //buffer->GetCurrentPosition( &play, &write ); - //ConLog( " * SPU2 > Play: %d Write: %d poffset: %d\n", play, write, poffset ); + verifyc(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0)); + oldp1 = p1; - buff->ReadSamples(tbuffer,BufferSize); - - verifyc(buffer->Lock(poffset,BufferSizeBytes,&p1,&s1,&p2,&s2,0)); + for(int p=0; pReadSamples( p1 ); - { - s16 *t = (s16*)p1; - s32 *s = (s32*)tbuffer; - for(int j=0;j>8); - } - } - - /*if( p2 != NULL ) - { - ConLog( " * SPU2 > DSound Driver Loop-Around Occured. Length: %d", s2 ); - }*/ - - verifyc(buffer->Unlock(p1,s1,p2,s2)); + verifyc(buffer->Unlock(oldp1,s1,p2,s2)); } return 0; } @@ -166,7 +145,7 @@ public: // GUID cGuid; - if((strlen(DSoundDevice)>0)&&(!FAILED(GUIDFromString(DSoundDevice,&cGuid)))) + if((strlen(Config_DSoundOut.Device)>0)&&(!FAILED(GUIDFromString(Config_DSoundOut.Device,&cGuid)))) { verifyc(DirectSoundCreate8(&cGuid,&dsound,NULL)); } @@ -187,7 +166,7 @@ public: wfx.nChannels=2; wfx.wBitsPerSample = 16; wfx.nBlockAlign = 2*2; - wfx.nAvgBytesPerSec = SampleRate * 2 * 2; + wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign; wfx.cbSize=0; // Set up DSBUFFERDESC structure. @@ -195,7 +174,7 @@ public: memset(&desc, 0, sizeof(DSBUFFERDESC)); desc.dwSize = sizeof(DSBUFFERDESC); desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; - desc.dwBufferBytes = BufferSizeBytes * MAX_BUFFER_COUNT; + desc.dwBufferBytes = BufferSizeBytes * Config_DSoundOut.NumBuffers; desc.lpwfxFormat = &wfx; desc.dwFlags |=DSBCAPS_LOCSOFTWARE; @@ -209,14 +188,18 @@ public: DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT]; - for(int i=0;iSetNotificationPositions(MAX_BUFFER_COUNT,not); + buffer_notify->SetNotificationPositions(Config_DSoundOut.NumBuffers,not); LPVOID p1=0,p2=0; DWORD s1=0,s2=0; @@ -229,13 +212,10 @@ public: //Play the buffer ! verifyc(buffer->Play(0,0,DSBPLAY_LOOPING)); - tbuffer = new s32[BufferSize]; - // Start Thread dsound_running=true; - thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread,this,0,&tid); + thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread,this,0,&tid); SetThreadPriority(thread,THREAD_PRIORITY_TIME_CRITICAL); - return 0; } @@ -257,14 +237,12 @@ public: // buffer->Stop(); - for(int i=0;iRelease(); buffer->Release(); dsound->Release(); - - delete tbuffer; } private: @@ -298,7 +276,7 @@ private: { case WM_INITDIALOG: - haveGuid = ! FAILED(GUIDFromString(DSoundDevice,&DevGuid)); + haveGuid = ! FAILED(GUIDFromString(Config_DSoundOut.Device,&DevGuid)); SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_RESETCONTENT,0,0); ndevs=0; @@ -319,6 +297,12 @@ private: SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_SETCURSEL,tSel,0); } + char temp[128]; + INIT_SLIDER( IDC_BUFFERS_SLIDER, 2, MAX_BUFFER_COUNT, 2, 1, 1 ); + SendMessage(GetDlgItem(hWnd,IDC_BUFFERS_SLIDER),TBM_SETPOS,TRUE,Config_DSoundOut.NumBuffers); + sprintf_s(temp, 128, "%d (%d ms latency)",Config_DSoundOut.NumBuffers, 1000 / (96000 / (Config_DSoundOut.NumBuffers * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + break; case WM_COMMAND: wmId = LOWORD(wParam); @@ -332,11 +316,11 @@ private: if(!devices[i].hasGuid) { - DSoundDevice[0]=0; // clear device name to "" + Config_DSoundOut.Device[0] = 0; // clear device name to "" } else { - sprintf_s(DSoundDevice,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + sprintf_s(Config_DSoundOut.Device,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", devices[i].guid.Data1, devices[i].guid.Data2, devices[i].guid.Data3, @@ -350,6 +334,11 @@ private: devices[i].guid.Data4[7] ); } + + Config_DSoundOut.NumBuffers = (int)SendMessage( GetDlgItem( hWnd, IDC_BUFFERS_SLIDER ), TBM_GETPOS, 0, 0 ); + + if( Config_DSoundOut.NumBuffers < 2 ) Config_DSoundOut.NumBuffers = 2; + if( Config_DSoundOut.NumBuffers > MAX_BUFFER_COUNT ) Config_DSoundOut.NumBuffers = MAX_BUFFER_COUNT; } EndDialog(hWnd,0); break; @@ -360,6 +349,30 @@ private: return FALSE; } break; + + case WM_HSCROLL: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + switch(wmId) { + //case TB_ENDTRACK: + //case TB_THUMBPOSITION: + case TB_LINEUP: + case TB_LINEDOWN: + case TB_PAGEUP: + case TB_PAGEDOWN: + wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); + case TB_THUMBTRACK: + if( wmEvent < 2 ) wmEvent = 2; + if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT; + SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); + sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + break; + default: + return FALSE; + } + break; + default: return FALSE; } @@ -378,12 +391,36 @@ public: } } - virtual bool Is51Out() { return false; } + virtual bool Is51Out() const { return false; } - s32 Test() + s32 Test() const { return 0; } + + int GetEmptySampleCount() const + { + DWORD play, write; + buffer->GetCurrentPosition( &play, &write ); + int filled = play - write; + if( filled < 0 ) + filled = -filled; + else + filled = (BufferSizeBytes * Config_DSoundOut.NumBuffers) - filled; + + return filled; + } + + const char* GetIdent() const + { + return "dsound"; + } + + const char* GetLongName() const + { + return "DirectSound"; + } + } DS; SndOutModule *DSoundOut=&DS; diff --git a/plugins/spu2ghz/mixer.cpp b/plugins/spu2ghz/mixer.cpp index df7df7f720..5d7d4b4e89 100644 --- a/plugins/spu2ghz/mixer.cpp +++ b/plugins/spu2ghz/mixer.cpp @@ -232,7 +232,7 @@ static void __forceinline __fastcall GetNextDataBuffered( V_Core& thiscore, V_Vo VoiceStop(core,voice); thiscore.Regs.ENDX|=1<0) { - if(MsgAutoDMA) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); + if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); } #endif thiscore.InputDataLeft=0; @@ -705,7 +705,7 @@ void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR) #ifndef PUBLIC if(thiscore.InputDataLeft>0) { - if(MsgAutoDMA) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); + if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); } #endif thiscore.InputDataLeft=0; @@ -759,7 +759,7 @@ void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR) #ifndef PUBLIC if(thiscore.InputDataLeft>0) { - if(MsgAutoDMA) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); + if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); } #endif thiscore.InputDataLeft=0; @@ -1062,14 +1062,11 @@ static void __forceinline MixVoice( V_Core& thiscore, V_Voice& vc, s32& VValL, s static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR) { s32 RVL,RVR; - s32 TDL=0,TDR=0; s32 SDL=0,SDR=0; s32 SWL=0,SWR=0; V_Core& thiscore( Cores[core] ); - SDL=SDR=SWL=SWR=(s32)0; - for (voice=0;voice<24;voice++) { s32 VValL,VValR; @@ -1089,6 +1086,8 @@ static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR) spu2M_WriteFast( 0x1400 + (core<<12) + OutPos, (s16)(SWL>>16) ); spu2M_WriteFast( 0x1600 + (core<<12) + OutPos, (s16)(SWR>>16) ); + s32 TDL,TDR; + // Mix in the Input data TDL = OutL * thiscore.InpDryL; TDR = OutR * thiscore.InpDryR; @@ -1200,13 +1199,11 @@ void __fastcall Mix() Peak1 = max(Peak1,max(OutL,OutR)); #endif - // [Air] [TODO] : Replace this with MulShr32. - // I haven't done it yet because it would require making the - // VolumeDivisor a constant .. which it should be anyway. The presence - // of VolumeMultiplier more or less negates the need for a variable divisor. - - ExtL=MulDiv(OutL,VolumeMultiplier,VolumeDivisor<<6); - ExtR=MulDiv(OutR,VolumeMultiplier,VolumeDivisor<<6); + // [Air] : Removed MulDiv here in favor of a more direct approach + // within the SndOut driver (which ends up having to apply its own + // master volume divisors anyway). + //ExtL=MulDiv(OutL,VolumeMultiplier,1<<6); + //ExtR=MulDiv(OutR,VolumeMultiplier,1<<6); // Update spdif (called each sample) if(PlayMode&4) @@ -1215,17 +1212,17 @@ void __fastcall Mix() } // AddToBuffer - SndWrite(ExtL,ExtR); + SndWrite(OutL, OutR); //ExtL,ExtR); OutPos++; if (OutPos>=0x200) OutPos=0; #ifndef PUBLIC // [TODO]: Create an INI option to enable/disable this particular log. p_cachestat_counter++; - if(p_cachestat_counter > (48000*6) ) + if(p_cachestat_counter > (48000*10) ) { p_cachestat_counter = 0; - ConLog( " * SPU2 > CacheStatistics > Hits: %d Misses: %d Ignores: %d\n", + if( MsgCache() ) ConLog( " * SPU2 > CacheStats > Hits: %d Misses: %d Ignores: %d\n", g_counter_cache_hits, g_counter_cache_misses, g_counter_cache_ignores ); diff --git a/plugins/spu2ghz/resource.h b/plugins/spu2ghz/resource.h index 29caca77ea..a0e6ea8ef7 100644 --- a/plugins/spu2ghz/resource.h +++ b/plugins/spu2ghz/resource.h @@ -20,6 +20,7 @@ #define IDC_SRATE 1012 #define IDC_OUTPUT 1013 #define IDC_BUFFER 1014 +#define IDC_BUFFERS_SLIDER 1014 #define IDC_BSIZE 1016 #define IDC_BCOUNT 1018 #define IDC_TEXT 1019 @@ -37,16 +38,26 @@ #define IDC_SLIDER2 1034 #define IDC_SLIDER3 1035 #define IDC_EDIT1 1036 +#define IDC_BUTTON1 1037 +#define IDC_SHOW_DEBUG 1037 +#define IDC_DBG_OVERRUNS 1038 #define IDC_SLIDER4 1039 +#define IDC_DBG_CACHE 1039 #define IDC_SLIDER5 1040 +#define IDC_DEBUG_GROUP 1040 #define IDC_SLIDER6 1041 +#define IDC_LATENCY_SLIDER 1041 #define IDC_SLIDER7 1042 +#define IDC_LATENCY_LABEL 1042 #define IDC_EDIT2 1043 #define IDC_EDIT3 1044 +#define IDC_SPEEDLIMIT_RUNTIME_TOGGLE 1044 #define IDC_EDIT4 1045 #define IDC_EDIT5 1046 #define IDC_EDIT6 1047 +#define IDC_VOLBOOST 1047 #define IDC_EDIT7 1048 +#define IDC_LATENCY_LABEL2 1049 // Next default values for new objects // @@ -54,7 +65,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 110 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1037 +#define _APS_NEXT_CONTROL_VALUE 1048 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/plugins/spu2ghz/sndout.cpp b/plugins/spu2ghz/sndout.cpp index d981aaf5e0..5ec7db49f4 100644 --- a/plugins/spu2ghz/sndout.cpp +++ b/plugins/spu2ghz/sndout.cpp @@ -19,13 +19,30 @@ #include "SoundTouch/SoundTouch.h" #include "SoundTouch/WavFile.h" +static int ts_stats_stretchblocks = 0; +static int ts_stats_normalblocks = 0; +static int ts_stats_logcounter = 0; + class NullOutModule: public SndOutModule { +public: s32 Init(SndBuffer *) { return 0; } void Close() { } - s32 Test() { return 0; } + s32 Test() const { return 0; } void Configure(HWND parent) { } - bool Is51Out() { return false; } + bool Is51Out() const { return false; } + int GetEmptySampleCount() const { return 0; } + + const char* GetIdent() const + { + return "nullout"; + } + + const char* GetLongName() const + { + return "No Sound (Emulate SPU2 only)"; + } + } NullOut; SndOutModule* mods[]= @@ -36,9 +53,39 @@ SndOutModule* mods[]= DSound51Out, ASIOOut, XAudio2Out, + NULL // signals the end of our list }; -const u32 mods_count=sizeof(mods)/sizeof(SndOutModule*); +int FindOutputModuleById( const char* omodid ) +{ + int modcnt = 0; + while( mods[modcnt] != NULL ) + { + if( strcmp( mods[modcnt]->GetIdent(), omodid ) == 0 ) + break; + ++modcnt; + } + return modcnt; +} + + +// Overall master volume shift. +// Converts the mixer's 32 bit value into a 16 bit value. +int SndOutVolumeShift = SndOutVolumeShiftBase + 1; + +static __forceinline s16 SndScaleVol( s32 inval ) +{ + return inval >> SndOutVolumeShift; +} + + +// records last buffer status (fill %, range -100 to 100, with 0 being 50% full) +double lastPct; + +float cTempo=1; + +soundtouch::SoundTouch* pSoundTouch=NULL; + //usefull when timestretch isn't available //#define DYNAMIC_BUFFER_LIMITING @@ -52,45 +99,42 @@ private: s32 wpos; s32 data; -#ifdef DYNAMIC_BUFFER_LIMITING - s32 buffer_limit; -#endif + // data prediction amount, used to "commit" data that hasn't + // finished timestretch processing. + s32 predictData; - bool pr; bool pw; - int overflows; - int underflows; - int writewaits; - - - - bool isWaiting; + bool underrun_freeze; HANDLE hSyncEvent; CRITICAL_SECTION cs; - u32 datawritten; - u32 dataread; +protected: + int GetAlignedBufferSize( int comp ) + { + return (comp + SndOutPacketSize-1) & ~(SndOutPacketSize-1); + } public: - SndBufferImpl(s32 _size) + SndBufferImpl( double latencyMS ) { rpos=0; wpos=0; data=0; - size=(_size+1)&(~1); + size=GetAlignedBufferSize( (int)(latencyMS * SampleRate / 500.0 ) ); buffer = new s32[size]; - pr=false; pw=false; - isWaiting=false; + underrun_freeze = false; + predictData = 0; + + lastPct = 0.0; + #ifdef DYNAMIC_BUFFER_LIMITING overflows=0; underflows=0; writewaits=0; buffer_limit=size; #endif - datawritten=0; - dataread=0; InitializeCriticalSection(&cs); hSyncEvent = CreateEvent(NULL,FALSE,FALSE,NULL); } @@ -98,7 +142,7 @@ public: virtual ~SndBufferImpl() { pw=false; - if(isWaiting) PulseEvent(hSyncEvent); + PulseEvent(hSyncEvent); Sleep(10); EnterCriticalSection(&cs); LeaveCriticalSection(&cs); @@ -107,42 +151,24 @@ public: delete buffer; } - virtual void WriteSamples(s32 *bData, s32 nSamples) + virtual void WriteSamples(s32 *bData, int nSamples) { EnterCriticalSection(&cs); - datawritten+=nSamples; - -#ifdef DYNAMIC_BUFFER_LIMITING - int free = buffer_limit-data; -#else int free = size-data; -#endif + predictData = 0; - if(pw) + jASSUME( data <= size ); + + if( pw && ( free < nSamples ) ) { -#ifdef DYNAMIC_BUFFER_LIMITING - if(freenSamples - // Problem: // If the SPU2 gets out of sync with the SndOut device, the writepos of the // circular buffer will overtake the readpos, leading to a prolonged period @@ -154,64 +180,106 @@ public: // The older portion of the buffer is discarded rather than incoming data, // so that the overall audio synchronization is better. -#ifndef DYNAMIC_BUFFER_LIMITING - - if((data+nSamples > size) && !timeStretchEnabled) + if( free < nSamples ) { // Buffer overrun! // Dump samples from the read portion of the buffer instead of dropping // the newly written stuff. // Toss half the buffer plus whatever's being written anew: - s32 comp = (size / 2) + nSamples; - comp = (comp + 128) & ~127; // probably not important but it makes the log look nicer. :P - if( comp > size ) comp = size; + s32 comp = GetAlignedBufferSize( (size + nSamples ) / 2 ); + if( comp > (size-SndOutPacketSize) ) comp = size-SndOutPacketSize; + + if( timeStretchEnabled ) + { + // If we overran it means the timestretcher failed. We need to speed + // up audio playback. + + cTempo += cTempo * 1.5f; + if( cTempo > 5.0f ) cTempo = 5.0f; + pSoundTouch->setTempo( cTempo ); + } data-=comp; rpos=(rpos+comp)%size; - timeStretchEnabled = true; - ConLog(" * SPU2 > Overrun Compensation (%d samples tossed)\n", size ); - ConLog(" * SPU2 Timestretch: ENABLED\n"); + if( MsgOverruns() ) + ConLog(" * SPU2 > Overrun Compensation (%d packets tossed)\n", comp / SndOutPacketSize ); + lastPct = 0.0; // normalize the timestretcher } - while(data0) + // copy in two phases, since there's a chance the packet + // wraps around the buffer (it'd be nice to deal in packets only, but + // the timestretcher and DSP options require flexibility). + + const int endPos = wpos + nSamples; + const int secondCopyLen = endPos - size; + s32* wposbuffer = &buffer[wpos]; + + data += nSamples; + if( secondCopyLen > 0 ) { - buffer[wpos] = *(bData++); - wpos=(wpos+1)%size; - data++; - nSamples--; + nSamples -= secondCopyLen; + memcpy( buffer, &bData[nSamples], secondCopyLen * sizeof( *bData ) ); + wpos = secondCopyLen; } + else + wpos += nSamples; -#elif defined( DYNAMIC_BUFFER_LIMITING ) - - while(nSamples>0) - { - buffer[wpos] = *(bData++); - wpos=(wpos+1)%size; - data++; - nSamples--; - } - - if(data>size) - { - do { - data-=size; - } - while(data>size); - overflows++; - } -#endif - + memcpy( wposbuffer, bData, nSamples * sizeof( *bData ) ); LeaveCriticalSection(&cs); } - virtual void ReadSamples (s32 *bData, s32 nSamples) + protected: + // Returns TRUE if there is data to be output, or false if no data + // is available to be copied. + bool CheckUnderrunStatus( int& nSamples, int& quietSampleCount ) { - static bool underrun_freeze = false; + quietSampleCount = 0; + if( data < nSamples ) + { + nSamples = data; + quietSampleCount = SndOutPacketSize - data; + underrun_freeze = true; + + if( timeStretchEnabled ) + { + // timeStretcher failed it's job. We need to slow down the audio some. + + cTempo -= (cTempo * 0.25f); + if( cTempo < 0.2f ) cTempo = 0.2f; + pSoundTouch->setTempo( cTempo ); + } + + return nSamples != 0; + } + else if( underrun_freeze ) + { + int toFill = (int)(size * ( timeStretchEnabled ? 0.45 : 0.70 ) ); + toFill = GetAlignedBufferSize( toFill ); + + // toFill is now aligned to a SndOutPacket + + if( data < toFill ) + { + quietSampleCount = nSamples; + return false; + } + + underrun_freeze = false; + if( MsgOverruns() ) + ConLog(" * SPU2 > Underrun compensation (%d packets buffered)\n", toFill / SndOutPacketSize ); + lastPct = 0.0; // normalize timestretcher + } + return true; + } + + public: + void ReadSamples( s16* bData ) + { + int nSamples = SndOutPacketSize; EnterCriticalSection(&cs); - dataread+=nSamples; // Problem: // If the SPU2 gets even the least bit out of sync with the SndOut device, @@ -226,269 +294,219 @@ public: // This will cause one brief hiccup that can never exceed the user's // set buffer length in duration. -#ifndef DYNAMIC_BUFFER_LIMITING - if( underrun_freeze && !timeStretchEnabled) + int quietSamples; + if( CheckUnderrunStatus( nSamples, quietSamples ) ) { - // Let's fill up 80% of our buffer. - // (I just picked 80% arbitrarily.. there might be a better value) + jASSUME( nSamples <= SndOutPacketSize ); - int toFill = (int)(size * 0.80); - toFill = (toFill + 128) & ~127; // probably not important but it makes the log look nicer. :P + // [Air] [TODO]: This loop is probably a candidiate for SSE2 optimization. - if( data < toFill ) + const int endPos = rpos + nSamples; + const int secondCopyLen = endPos - size; + const s32* rposbuffer = &buffer[rpos]; + + data -= nSamples; + + if( secondCopyLen > 0 ) { - while( nSamples>0 ) - { - *(bData++) = 0; - nSamples--; - } - LeaveCriticalSection(&cs); - return; + nSamples -= secondCopyLen; + for( int i=0; i Underrun compensation (%d samples buffered)\n", toFill ); - ConLog(" * SPU2 Timestretch: ENABLED\n"); - } - else underrun_freeze = false; - - while(data>0 && nSamples>0) - { - *(bData++) = buffer[rpos]; - rpos=(rpos+1)%size; - data--; - nSamples--; + for( int i=0; i0 ) - { - // buffer underrun code: - // the contents of this loop only get run if data reached zero - // before nSamples. - // Let's just dull out some silence, because that's usually the least - // painful way of dealing with underruns. - - *(bData++) = 0; - nSamples--; - } - - if( data == 0 && !pw ) - { - underrun_freeze = true; - } - -#elif defined( DYNAMIC_BUFFER_LIMITING ) - - while(nSamples>0) - { - *(bData++) = buffer[rpos]; - rpos=(rpos+1)%size; - data--; - nSamples--; - } - - if(data<0) - { - do - { - data+=buffer_limit; - } - while(data<0); - underflows++; - } -#else - bool uflow = false; - while(data<0) - { - data+=size; - uflow = true; - } -#endif - - PulseEvent(hSyncEvent); - -#ifdef DYNAMIC_BUFFER_LIMITING - - // will never have BOTH overflows and write waits ;) - while((overflows>0)&&(underflows>0)) - { overflows--; underflows--; } - while((writewaits>0)&&(underflows>0)) - { writewaits--; underflows--; } - int t=buffer_limit; - if(underflows>0) - { - if(buffer_limit3) underflows=3; - } - if(writewaits>0) - { - if(buffer_limit>(3*CurBufferSize)) - { - buffer_limit=max(3*CurBufferSize,buffer_limit*3/4); - writewaits=0; - } - if(writewaits>10) writewaits=10; - } - if(overflows>0) - { - if(buffer_limit>(3*CurBufferSize)) - { - buffer_limit=max(3*CurBufferSize,buffer_limit*3/4); - overflows=0; - } - if(overflows>3) overflows=3; - } - - //printf(" ** SPU2 Dynamic limiter update: Buffer limit set to %d\n",buffer_limit); -#endif - + // If quietSamples != 0 it means we have an underrun... + // Let's just dull out some silence, because that's usually the least + // painful way of dealing with underruns: + memset( bData, 0, quietSamples * sizeof(*bData) ); + SetEvent( hSyncEvent ); LeaveCriticalSection(&cs); } + void ReadSamples( s32* bData ) + { + int nSamples = SndOutPacketSize; + + EnterCriticalSection(&cs); + + // Problem: + // If the SPU2 gets even the least bit out of sync with the SndOut device, + // the readpos of the circular buffer will overtake the writepos, + // leading to a prolonged period of hopscotching read/write accesses (ie, + // lots of staticy crap sound for several seconds). + // + // Fix: + // If the read position overtakes the write position, abort the + // transfer immediately and force the SndOut driver to wait until + // the read buffer has filled up again before proceeding. + // This will cause one brief hiccup that can never exceed the user's + // set buffer length in duration. + + int quietSamples; + if( CheckUnderrunStatus( nSamples, quietSamples ) ) + { + // nSamples is garaunteed non-zero if CheckUnderrunStatus + // returned true. + + const int endPos = rpos + nSamples; + const int secondCopyLen = endPos - size; + const int oldrpos = rpos; + + data -= nSamples; + + if( secondCopyLen > 0 ) + { + nSamples -= secondCopyLen; + memcpy( &bData[nSamples], buffer, secondCopyLen * sizeof( *bData ) ); + rpos = secondCopyLen; + } + else + rpos += nSamples; + + memcpy( bData, &buffer[oldrpos], nSamples * sizeof( *bData ) ); + } + + // If quietSamples != 0 it means we have an underrun... + // Let's just dull out some silence, because that's usually the least + // painful way of dealing with underruns: + memset( bData, 0, quietSamples * sizeof(*bData) ); + PulseEvent(hSyncEvent); + LeaveCriticalSection(&cs); + } + + void PredictDataWrite( int samples ) + { + predictData += samples; + } + virtual void PauseOnWrite(bool doPause) { pw = doPause; } - virtual s32 GetBufferUsage() - { - return data; - } - - virtual s32 GetBufferSize() - { - return size; - } - - bool GetStats(u32 &w, u32 &r, bool reset) + // Calculate the buffer status percentage. + // Returns range from -1.0 to 1.0 + // 1.0 = buffer overflow! + // 0.0 = buffer nominal (50% full) + // -1.0 = buffer underflow! + double GetStatusPct() { EnterCriticalSection(&cs); - w = datawritten; - r = dataread; - if(reset) { datawritten=dataread=0; } + + // Get the buffer status of the output driver too, so that we can + // obtain a more accurate overall buffer status. + + int drvempty = mods[OutputModule]->GetEmptySampleCount() / 2; + + double result = (data + predictData - drvempty) - (size/2); + result /= (size/2); LeaveCriticalSection(&cs); - return true; + return result; } -} *sndBuffer; + +}; + +SndBufferImpl *sndBuffer; + s32* sndTempBuffer; s32 sndTempProgress; -s32 sndTempSize; s16* sndTempBuffer16; -float* sndTempBufferFloat; - -s32 buffersize=0; - -soundtouch::SoundTouch* pSoundTouch=NULL; - -u32 inputSamples=0; - -u32 oldWritten=0; -u32 oldRead=0; -u32 oldInput=0; - -float valAccum1 = 1.0f; -float valAccum2 = 1.0f; -u32 numAccum = 1; - -const u32 numUpdates = 160; - -float lastTempo=1; -float cTempo=1; +//float* sndTempBufferFloat; void ResetTempoChange() { - u32 cWritten; - u32 cRead; - u32 cInput = inputSamples; - - sndBuffer->GetStats(cWritten,cRead,false); - - oldWritten=cWritten; - oldRead=cRead; - oldInput=cInput; - pSoundTouch->setTempo(1); } void UpdateTempoChange() { - u32 cWritten; - u32 cRead; - u32 cInput = inputSamples; - static short int runs =0; + double statusPct = sndBuffer->GetStatusPct(); + double pctChange = statusPct - lastPct; - s32 bufferUsage = sndBuffer->GetBufferUsage(); - s32 bufferSize = sndBuffer->GetBufferSize(); -//Emergency stretch to compensate for FPS fluctuations and keep the buffers happy - bool a=(bufferUsage < CurBufferSize * 4); - bool b=(bufferUsage >= (bufferSize - CurBufferSize * 4)); + double tempoChange; - if(a!=b) + // We have two factors. + // * Distance from nominal buffer status (50% full) + // * The change from previous update to this update. + + // The most important factor is the change from update to update. + // But the synchronization between emulator, mixer, and audio driver + // is rarely consistent so drifting away from nominal buffer status (50%) + // is inevitable. So we need to use the nominal buffer status to + // help temper things. + + double relation = statusPct / pctChange; + + if( relation < 0.0 ) { - if (bufferUsage < CurBufferSize * 2) { cTempo*=0.80f; } - else if(bufferUsage < CurBufferSize * 3) { cTempo*=0.90f; } - else if(bufferUsage < CurBufferSize * 4) { cTempo*=0.96f; } - - if (bufferUsage > (bufferSize - CurBufferSize * 2)) { cTempo*=1.20f; } - else if(bufferUsage > (bufferSize - CurBufferSize * 3)) { cTempo*=1.10f; } - else if(bufferUsage >= (bufferSize - CurBufferSize * 4)) { cTempo*=1.04f; } - - if (cTempo != lastTempo) { - pSoundTouch->setTempo(cTempo); - } + // The buffer is already shrinking toward + // nominal value, so let's not do "too much" + // We only want to adjust if the shrink rate seems too fast + // or slow compared to our distance from nominal (50%). + + tempoChange = ( pow( statusPct, 3.0 ) * 0.33 ) + pctChange * 0.23; } else { - cTempo = cTempo * 0.9f + lastTempo * 0.1f; + tempoChange = pctChange * 0.30; + + // Sudden spikes in framerate can cause the nominal buffer status + // to go critical, in which case we have to enact an emergency + // stretch. The following cubic formula does that. + + // Constants: + // Weight - weights the statusPct's "emergency" consideration. + // higher values here will make the buffer perform more drastic + // compensations. + + // Range - scales the adjustment to the given range (more or less). + // The actual range is dependent on the weight used, so if you increase + // Weight you'll usually want to decrease Range somewhat to compensate. + + const double weight = 1.55; + const double range = 0.12; + + double nominalAdjust = (statusPct * 0.10) + ( pow( statusPct*weight, 3.0 ) * range); + + tempoChange = tempoChange + nominalAdjust; } -////////////////////////////////////////////////////////////////////////////// - sndBuffer->GetStats(cWritten,cRead,false); - - valAccum1 += (cRead-oldRead); - valAccum2 += (cInput-oldInput); - numAccum++; - - oldRead = cRead; - oldInput = cInput; + // Threshold - Ignore small values between -.005 and +.005. + // We don't need to "pollute" our timestretcher with pointless + // tempo change overhead. + if( abs( tempoChange ) < 0.005 ) return; -//normal stretch, scales sound to game speed - if(numAccum >= numUpdates) + lastPct = statusPct; + + // Apply tempoChange as a scale of cTempo. That way the effect is proportional + // to the current tempo. (otherwise tempos would change too slowly/quickly at the extremes) + cTempo += (float)( tempoChange * cTempo ); + + if( statusPct < -0.20 || statusPct > 0.20 || cTempo < 0.980 || cTempo > 1.020 ) { - float valAccum = 1.0f; - - valAccum = valAccum2 / valAccum1; + if( cTempo < 0.20f ) cTempo = 0.20f; + else if( cTempo > 5.0f ) cTempo = 5.0f; + pSoundTouch->setTempo( cTempo ); + ts_stats_stretchblocks++; - if((valAccum < 1.04f) && (valAccum > 0.96f) /*&& (valAccum != 1)*/) - { - valAccum = 1.0f; - } - - if (valAccum != lastTempo) //only update soundtouch object when needed - pSoundTouch->setTempo(valAccum); - - lastTempo = valAccum; - cTempo = valAccum; - - if (lastTempo == 1) { - runs++; - if (runs == 5) { - timeStretchEnabled = false; - ConLog( " * SPU2 Timestretch: DISABLED > tempo = %f\n",lastTempo); - runs = 0; - } - } - else runs = 0; - - valAccum1 = 1.0f; - valAccum2 = 1.0f; - numAccum = 0; + ConLog(" %s * SPU2: TempoChange by %d%% (tempo: %d%%) (buffer: %d%%)\n", + (relation < 0.0) ? "Normalize" : "", + (int)(tempoChange * 100.0), (int)(cTempo * 100.0), + (int)(statusPct * 100.0) + ); + } + else + { + // Nominal operation -- turn off stretching. + pSoundTouch->setTempo( 1.0f ); + ts_stats_normalblocks++; } - } + void soundtouchInit() { pSoundTouch = new soundtouch::SoundTouch(); pSoundTouch->setSampleRate(SampleRate); @@ -500,18 +518,22 @@ void soundtouchInit() { s32 SndInit() { - if(OutputModule>=mods_count) - return -1; + if( mods[OutputModule] == NULL ) + { + // force us to the NullOut module if nothing assigned. + OutputModule = FindOutputModuleById( NullOut.GetIdent() ); + } // initialize sound buffer - sndBuffer = new SndBufferImpl(CurBufferSize * MaxBufferCount * 2); - sndTempSize = 512; + // Buffer actually attempts to run ~50%, so allocate near double what + // the requested latency is: + sndBuffer = new SndBufferImpl( SndOutLatencyMS * 1.75 ); sndTempProgress = 0; - sndTempBuffer = new s32[sndTempSize]; - sndTempBuffer16 = new s16[sndTempSize]; - sndTempBufferFloat = new float[sndTempSize]; - buffersize=sndBuffer->GetBufferSize(); + sndTempBuffer = new s32[SndOutPacketSize]; + sndTempBuffer16 = new s16[SndOutPacketSize]; + //sndTempBufferFloat = new float[sndTempSize]; + cTempo = 1.0; soundtouchInit(); ResetTempoChange(); @@ -530,15 +552,11 @@ s32 SndInit() void SndClose() { - if(OutputModule>=mods_count) - return; - mods[OutputModule]->Close(); delete sndBuffer; delete sndTempBuffer; delete sndTempBuffer16; - delete sndTempBufferFloat; delete pSoundTouch; } @@ -560,88 +578,108 @@ void SndUpdateLimitMode() } -bool SndGetStats(u32 *written, u32 *played) -{ - return sndBuffer->GetStats(*written,*played,false); -} s32 SndWrite(s32 ValL, s32 ValR) { - if(WaveLog && wavedump_ok) + #ifndef PUBLIC + if(WaveLog() && wavedump_ok) { - wavedump_write(ValL>>8,ValR>>8); + wavedump_write(SndScaleVol(ValL),SndScaleVol(ValR)); } - + #endif + if(recording!=0) - RecordWrite(ValL>>8,ValR>>8); - - if(OutputModule>=mods_count) - return -1; + RecordWrite(SndScaleVol(ValL),SndScaleVol(ValR)); if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p return 0; - inputSamples+=2; + //inputSamples+=2; sndTempBuffer[sndTempProgress++] = ValL; sndTempBuffer[sndTempProgress++] = ValR; - if(sndTempProgress>=sndTempSize) + // If we haven't accumulated a full packet yet, do nothing more: + if(sndTempProgress < SndOutPacketSize) return 1; + + if(dspPluginEnabled) { - if(dspPluginEnabled) + for(int i=0;i>1)<<1; + + for(int i=0;iPredictDataWrite( (int)( sndTempProgress / cTempo ) ); + for(int i=0;iputSamples((float*)sndTempBuffer, sndTempProgress>>1); + + while( ( sndTempProgress = pSoundTouch->receiveSamples((float*)sndTempBuffer, sndTempProgress>>1)<<1 ) != 0 ) { - for(int i=0;i>8; } - - // send to winamp DSP - sndTempProgress = DspProcess(sndTempBuffer16,sndTempProgress>>1)<<1; - - for(int i=0;iputSamples(sndTempBufferFloat, sndTempProgress>>1); - UpdateTempoChange(); - do + // The timestretcher returns packets in belated "clump" form. + // Meaning that most of the time we'll get nothing back, and then + // suddenly we'll get several chunks back at once. That's + // why we only update the tempo below after a set of blocks has been + // released (otherwise the tempo rates will be skewed by backlogged data) + + // [Air] [TODO] : Implement an SSE downsampler to int. + for(int i=0;ireceiveSamples(sndTempBufferFloat, sndTempSize>>1)<<1; - - if(sndTempProgress>0) - { - - for(int i=0;iWriteSamples(sndTempBuffer,sndTempProgress); - } - - } while (sndTempProgress != 0 ); + sndTempBuffer[i] = (s32)(((float*)sndTempBuffer)[i]*2147483648.0f); + } + sndBuffer->WriteSamples(sndTempBuffer, sndTempProgress); + progress = true; } - else + + if( progress ) { - sndBuffer->WriteSamples(sndTempBuffer,sndTempProgress); - sndTempProgress=0; + UpdateTempoChange(); + + if( MsgOverruns() ) + { + if( ++ts_stats_logcounter > 300 ) + { + ts_stats_logcounter = 0; + ConLog( " * SPU2 > Timestretch Stats > %d%% of packets stretched.\n", + ( ts_stats_stretchblocks * 100 ) / ( ts_stats_normalblocks + ts_stats_stretchblocks ) ); + ts_stats_normalblocks = 0; + ts_stats_stretchblocks = 0; + } + } } } - + else + { + sndBuffer->WriteSamples(sndTempBuffer, sndTempProgress); + sndTempProgress=0; + } + return 1; } s32 SndTest() { - if(OutputModule>=mods_count) + if( mods[OutputModule] == NULL ) return -1; return mods[OutputModule]->Test(); } -void SndConfigure(HWND parent) +void SndConfigure(HWND parent, u32 module ) { - if(OutputModule>=mods_count) + if( mods[module] == NULL ) return; - mods[OutputModule]->Configure(parent); + mods[module]->Configure(parent); } #if 0 diff --git a/plugins/spu2ghz/sndout.h b/plugins/spu2ghz/sndout.h index feca07bd1e..526f7bd402 100644 --- a/plugins/spu2ghz/sndout.h +++ b/plugins/spu2ghz/sndout.h @@ -18,12 +18,13 @@ #ifndef SNDOUT_H_INCLUDE #define SNDOUT_H_INCLUDE -#define OUTPUT_NULL 0 -#define OUTPUT_WAVEOUT 1 -#define OUTPUT_DSOUND 2 -#define OUTPUT_DSOUND51 3 -#define OUTPUT_ASIO 4 -#define OUTPUT_XAUDIO2 5 +// Number of stereo samples per SndOut block. +// All drivers must work in units of this size when communicating with +// SndOut. +static const int SndOutPacketSize = 1024; + +static const int SndOutVolumeShiftBase = 14; +extern int SndOutVolumeShift; #define pcmlog extern FILE *wavelog; @@ -32,32 +33,46 @@ s32 SndInit(); void SndClose(); s32 SndWrite(s32 ValL, s32 ValR); s32 SndTest(); -void SndConfigure(HWND parent); +void SndConfigure(HWND parent, u32 outmodidx ); bool SndGetStats(u32 *written, u32 *played); +int FindOutputModuleById( const char* omodid ); + class SndBuffer { public: virtual ~SndBuffer() {} - virtual void WriteSamples(s32 *buffer, s32 nSamples)=0; - virtual void ReadSamples (s32 *buffer, s32 nSamples)=0; - + virtual void WriteSamples(s32 *buffer, int nSamples)=0; virtual void PauseOnWrite(bool doPause)=0; - virtual s32 GetBufferUsage()=0; - virtual s32 GetBufferSize()=0; + virtual void ReadSamples( s16* bData )=0; + virtual void ReadSamples( s32* bData )=0; + + //virtual s32 GetBufferUsage()=0; + //virtual s32 GetBufferSize()=0; }; class SndOutModule { public: + // Returns a unique identification string for this driver. + // (usually just matches the driver's cpp filename) + virtual const char* GetIdent() const=0; + + // Returns the long name / description for this driver. + // (for use in configuration screen) + virtual const char* GetLongName() const=0; + virtual s32 Init(SndBuffer *buffer)=0; virtual void Close()=0; - virtual s32 Test()=0; + virtual s32 Test() const=0; virtual void Configure(HWND parent)=0; + virtual bool Is51Out() const=0; - virtual bool Is51Out()=0; + // Returns the number of empty samples in the output buffer. + // (which is effectively the amount of data played since the last update) + virtual int GetEmptySampleCount() const=0; }; //internal @@ -69,6 +84,5 @@ extern SndOutModule *XAudio2Out; extern SndOutModule *DSound51Out; extern SndOutModule* mods[]; -extern const u32 mods_count; #endif // SNDOUT_H_INCLUDE diff --git a/plugins/spu2ghz/spu2.cpp b/plugins/spu2ghz/spu2.cpp index 112f666de1..5373a4ddd5 100644 --- a/plugins/spu2ghz/spu2.cpp +++ b/plugins/spu2ghz/spu2.cpp @@ -42,6 +42,7 @@ static char *libraryName = "GiGaHeRz's SPU2 (" #endif ")"; + DWORD CALLBACK TimeThread(PVOID /* unused param */); @@ -171,11 +172,12 @@ void __inline __fastcall spu2M_Write( u32 addr, s16 value ) // Make sure the cache is invalidated: // (note to self : addr address WORDs, not bytes) + addr &= 0xfffff; const u32 nexta = addr >> 3; // 8 words per encoded block. const u32 flagbitmask = 1ul<<(nexta & 31); // 31 flags per array entry pcm_cache_flags[nexta>>5] &= ~flagbitmask; - *GetMemPtr( addr & 0xfffff ) = value; + *GetMemPtr( addr ) = value; } // writes an unsigned value to the SPU2 ram @@ -271,7 +273,7 @@ s32 CALLBACK SPU2init() acumCycles=0; #ifdef SPU2_LOG - if(AccessLog) + if(AccessLog()) { spu2Log = fopen(AccessLogFileName, "w"); setvbuf(spu2Log, NULL, _IONBF, 0); @@ -325,7 +327,7 @@ s32 CALLBACK SPU2init() DMALogOpen(); - if(WaveLog) + if(WaveLog()) { if(!wavedump_open()) { @@ -459,7 +461,7 @@ void CALLBACK SPU2shutdown() fclose(el0); fclose(el1); #endif - if(WaveLog && wavedump_ok) wavedump_close(); + if(WaveLog() && wavedump_ok) wavedump_close(); DMALogClose(); @@ -477,7 +479,7 @@ void CALLBACK SPU2shutdown() pcm_cache_data = NULL; #ifdef SPU2_LOG - if(!AccessLog) return; + if(!AccessLog()) return; FileLog("[%10d] SPU2shutdown\n",Cycles); if(spu2Log) fclose(spu2Log); #endif @@ -1895,7 +1897,7 @@ void VoiceStart(int core,int vc) DebugCores[core].Voices[vc].FirstBlock=1; if(core==1) { - if(MsgKeyOnOff) ConLog(" * SPU2: KeyOn: C%dV%02d: SSA: %8x; M: %s%s%s%s; H: %02x%02x; P: %04x V: %04x/%04x; ADSR: %04x%04x\n", + if(MsgKeyOnOff()) ConLog(" * SPU2: KeyOn: C%dV%02d: SSA: %8x; M: %s%s%s%s; H: %02x%02x; P: %04x V: %04x/%04x; ADSR: %04x%04x\n", core,vc,Cores[core].Voices[vc].StartA, (Cores[core].Voices[vc].DryL)?"+":"-",(Cores[core].Voices[vc].DryR)?"+":"-", (Cores[core].Voices[vc].WetL)?"+":"-",(Cores[core].Voices[vc].WetR)?"+":"-", @@ -1944,7 +1946,7 @@ void StopVoices(int core, u32 value) for (vc=0;vc<24;vc++) { if ((value>>vc) & 1) { Cores[core].Voices[vc].ADSR.Releasing=1; - //if(MsgKeyOnOff) ConLog(" * SPU2: KeyOff: Core %d; Voice %d.\n",core,vc); + //if(MsgKeyOnOff()) ConLog(" * SPU2: KeyOff: Core %d; Voice %d.\n",core,vc); } } } diff --git a/plugins/spu2ghz/waveout.cpp b/plugins/spu2ghz/waveout.cpp index ae5d9226ab..c3576a9a68 100644 --- a/plugins/spu2ghz/waveout.cpp +++ b/plugins/spu2ghz/waveout.cpp @@ -16,21 +16,23 @@ //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // #include "spu2.h" +#include "dialogs.h" +#include + class WaveOutModule: public SndOutModule { private: +# define MAX_BUFFER_COUNT 8 - #define MAX_BUFFER_COUNT 5 - - #define BufferSize (CurBufferSize<<1) - #define BufferSizeBytes (BufferSize<<1) + static const int PacketsPerBuffer = (1024 / SndOutPacketSize); + static const int BufferSize = SndOutPacketSize*PacketsPerBuffer; + static const int BufferSizeBytes = BufferSize << 1; HWAVEOUT hwodevice; WAVEFORMATEX wformat; WAVEHDR whbuffer[MAX_BUFFER_COUNT]; - s32* tbuffer; s16* qbuffer; #define QBUFFER(x) (qbuffer + BufferSize * (x)) @@ -63,14 +65,9 @@ private: buf->dwBytesRecorded = buf->dwBufferLength; - buff->ReadSamples(tbuffer,BufferSize); s16 *t = (s16*)buf->lpData; - s32 *s = (s32*)tbuffer; - - for(int bleh=0;bleh>8); - } + for(int p=0; pReadSamples( t ); whbuffer[i].dwFlags&=~WHDR_DONE; waveOutWrite(hwodevice,buf,sizeof(WAVEHDR)); @@ -94,8 +91,6 @@ public: if (Test()) return -1; - if(CurBufferSize<1024) CurBufferSize=1024; - wformat.wFormatTag=WAVE_FORMAT_PCM; wformat.nSamplesPerSec=SampleRate; wformat.wBitsPerSample=16; @@ -105,7 +100,6 @@ public: wformat.cbSize=0; qbuffer=new s16[BufferSize*MAX_BUFFER_COUNT]; - tbuffer=new s32[BufferSize]; woores = waveOutOpen(&hwodevice,WAVE_MAPPER,&wformat,0,0,0); if (woores != MMSYSERR_NOERROR) @@ -161,23 +155,121 @@ public: } waveOutClose(hwodevice); - delete tbuffer; delete qbuffer; } +private: - virtual void Configure(HWND parent) + static BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { + int wmId,wmEvent; + int tSel=0; + + switch(uMsg) + { + case WM_INITDIALOG: + + char temp[128]; + INIT_SLIDER( IDC_BUFFERS_SLIDER, 3, MAX_BUFFER_COUNT, 2, 1, 1 ); + SendMessage(GetDlgItem(hWnd,IDC_BUFFERS_SLIDER),TBM_SETPOS,TRUE,Config_WaveOut.NumBuffers); + sprintf_s(temp, 128, "%d (%d ms latency)",Config_WaveOut.NumBuffers, 1000 / (96000 / (Config_WaveOut.NumBuffers * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + + break; + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDOK: + { + Config_WaveOut.NumBuffers = (int)SendMessage( GetDlgItem( hWnd, IDC_BUFFERS_SLIDER ), TBM_GETPOS, 0, 0 ); + + if( Config_WaveOut.NumBuffers < 3 ) Config_WaveOut.NumBuffers = 3; + if( Config_WaveOut.NumBuffers > MAX_BUFFER_COUNT ) Config_WaveOut.NumBuffers = MAX_BUFFER_COUNT; + } + EndDialog(hWnd,0); + break; + case IDCANCEL: + EndDialog(hWnd,0); + break; + default: + return FALSE; + } + break; + + case WM_HSCROLL: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + switch(wmId) { + //case TB_ENDTRACK: + //case TB_THUMBPOSITION: + case TB_LINEUP: + case TB_LINEDOWN: + case TB_PAGEUP: + case TB_PAGEDOWN: + wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); + case TB_THUMBTRACK: + if( wmEvent < 3 ) wmEvent = 3; + if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT; + SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); + sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + break; + default: + return FALSE; + } + break; + + default: + return FALSE; + } + return TRUE; } - virtual bool Is51Out() { return false; } +public: + virtual void Configure(HWND parent) + { + INT_PTR ret; + ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_WAVEOUT),GetActiveWindow(),(DLGPROC)ConfigProc,1); + if(ret==-1) + { + MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0); + return; + } + } - s32 Test() { + virtual bool Is51Out() const { return false; } + + s32 Test() const + { if (waveOutGetNumDevs() == 0) { SysMessage("No waveOut Devices Present\n"); return -1; } return 0; } + + int GetEmptySampleCount() const + { + int result = 0; + for(int i=0;iReadSamples(tbuffer,BufferSize); + buff->ReadSamples(qb); buf.AudioBytes = BufferSizeBytes; - s16 *t = qb; - s32 *s = (s32*)tbuffer; - for(int i=0;i>8); - } - buf.pAudioData=(const BYTE*)qb; pSourceVoice->SubmitSourceBuffer( &buf ); @@ -161,7 +152,7 @@ public: wfx.nChannels=2; wfx.wBitsPerSample = 16; wfx.nBlockAlign = 2*2; - wfx.nAvgBytesPerSec = SampleRate * 2 * 2; + wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign; wfx.cbSize=0; // @@ -175,9 +166,9 @@ public: } pSourceVoice->Start( 0, 0 ); - tbuffer = new s32[BufferSize]; + //tbuffer = new s32[BufferSize]; qbuffer = new s16[BufferSize*MAX_BUFFER_COUNT]; - ZeroMemory(qbuffer,BufferSize*MAX_BUFFER_COUNT); + ZeroMemory(qbuffer,BufferSize*MAX_BUFFER_COUNT*2); // Start Thread xaudio2_running=true; @@ -218,20 +209,34 @@ public: SAFE_RELEASE( pXAudio2 ); CoUninitialize(); - - delete tbuffer; } virtual void Configure(HWND parent) { } - virtual bool Is51Out() { return false; } + virtual bool Is51Out() const { return false; } - s32 Test() + s32 Test() const { return 0; } + + int GetEmptySampleCount() const + { + return 0; + } + + const char* GetIdent() const + { + return "xaudio2"; + } + + const char* GetLongName() const + { + return "XAudio 2 (Experimental)"; + } + } XA2; SndOutModule *XAudio2Out=&XA2;