SPU2-X: Added configuration dialog for the portaudio backend (windows only).

Added settings for customizing the suggested latency.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4852 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
gigaherz 2011-08-08 12:49:33 +00:00
parent 44f0cc140a
commit a5638b1466
4 changed files with 323 additions and 43 deletions

View File

@ -24,17 +24,17 @@
#include "wchar.h"
#include <vector>
#ifdef __WIN32__
#include "pa_win_wasapi.h"
#endif
#ifdef __LINUX__
int PaLinuxCallback( const void *inputBuffer, void *outputBuffer,
int PaCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData );
#endif
class Portaudio : public SndOutModule
{
@ -48,6 +48,9 @@ private:
bool m_UseHardware;
bool m_WasapiExclusiveMode;
bool m_SuggestedLatencyMinimal;
int m_SuggestedLatencyMS;
//////////////////////////////////////////////////////////////////////////////////////////
// Instance vars
@ -59,16 +62,7 @@ private:
bool started;
PaStream* stream;
#ifndef __LINUX__
static int PaCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
return PA.ActualPaCallback(inputBuffer,outputBuffer,framesPerBuffer,timeInfo,statusFlags,userData);
}
#endif
std::vector<const PaDeviceInfo*> devices;
public:
int ActualPaCallback( const void *inputBuffer, void *outputBuffer,
@ -92,6 +86,8 @@ public:
Portaudio()
{
m_ApiId=-1;
m_SuggestedLatencyMinimal = true;
m_SuggestedLatencyMS = 20;
}
s32 Init()
@ -177,7 +173,7 @@ public:
deviceIndex,
2,
paInt32,
SndOutPacketSize/(float)SampleRate, // 0.2f,
m_SuggestedLatencyMinimal?(SndOutPacketSize/(float)SampleRate):(m_SuggestedLatencyMS/1000.0f),
infoPtr
};
@ -185,11 +181,8 @@ public:
NULL, &outParams, SampleRate,
SndOutPacketSize,
paNoFlag,
#ifndef __LINUX__
PaCallback,
#else
PaLinuxCallback,
#endif
NULL);
}
else
@ -254,10 +247,226 @@ public:
}
}
virtual void Configure(uptr parent)
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
#ifdef WIN32
private:
bool _ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
int wmId,wmEvent;
int tSel = 0;
switch(uMsg)
{
case WM_INITDIALOG:
{
wchar_t temp[128];
for(int i=0;i<Pa_GetDeviceCount();i++)
{
const PaDeviceInfo * info = Pa_GetDeviceInfo(i);
devices.push_back(info);
}
SendMessage(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_RESETCONTENT,0,0);
SendMessageA(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_ADDSTRING,0,(LPARAM)"Default Device");
SendMessage(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_SETCURSEL,0,0);
SendMessage(GetDlgItem(hWnd,IDC_PA_HOSTAPI),CB_RESETCONTENT,0,0);
SendMessageA(GetDlgItem(hWnd,IDC_PA_HOSTAPI),CB_ADDSTRING,0,(LPARAM)"Unspecified");
int idx = 0;
for(int i=0;i<Pa_GetHostApiCount();i++)
{
const PaHostApiInfo * apiinfo = Pa_GetHostApiInfo(i);
if(apiinfo->deviceCount > 0)
{
SendMessageA(GetDlgItem(hWnd,IDC_PA_HOSTAPI),CB_ADDSTRING,0,(LPARAM)apiinfo->name);
SendMessageA(GetDlgItem(hWnd,IDC_PA_HOSTAPI),CB_SETITEMDATA,i+1,apiinfo->type);
}
if(apiinfo->type == m_ApiId)
{
idx = i+1;
}
}
SendMessage(GetDlgItem(hWnd,IDC_PA_HOSTAPI),CB_SETCURSEL,idx,0);
if(idx > 0)
{
int api_idx = idx-1;
SendMessage(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_RESETCONTENT,0,0);
SendMessageA(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_ADDSTRING,0,(LPARAM)"Default Device");
SendMessage(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_SETITEMDATA,0,-1);
int idx=0;
int i=1,j=0;
for(std::vector<const PaDeviceInfo*>::iterator it=devices.begin(); it != devices.end(); it++, j++)
{
const PaDeviceInfo* info = *it;
if(info->hostApi == api_idx && info->maxOutputChannels > 0)
{
SendMessageA(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_ADDSTRING,0,(LPARAM)info->name);
SendMessage(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_SETITEMDATA,i,j);
if(wxString::FromAscii(info->name) == m_Device)
{
idx = i;
}
i++;
}
}
SendMessage(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_SETCURSEL,idx,0);
}
INIT_SLIDER( IDC_LATENCY, 10, 200, 10, 1, 1 );
SendMessage(GetDlgItem(hWnd,IDC_LATENCY),TBM_SETPOS,TRUE,m_SuggestedLatencyMS);
swprintf_s(temp, L"%d ms",m_SuggestedLatencyMS);
SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp);
if(m_SuggestedLatencyMinimal)
SET_CHECK( IDC_MINIMIZE, true );
else
SET_CHECK( IDC_MANUAL, true );
SET_CHECK( IDC_EXCLUSIVE, m_WasapiExclusiveMode );
}
break;
case WM_COMMAND:
{
//wchar_t temp[128];
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDOK:
{
int idx = (int)SendMessage(GetDlgItem(hWnd,IDC_PA_HOSTAPI),CB_GETCURSEL,0,0);
m_ApiId = SendMessage(GetDlgItem(hWnd,IDC_PA_HOSTAPI),CB_GETITEMDATA,idx,0);
idx = (int)SendMessage(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_GETCURSEL,0,0);
idx = SendMessage(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_GETITEMDATA,idx,0);
if(idx >= 0)
m_Device = wxString::FromAscii( devices.at(idx)->name );
else
m_Device = L"default";
m_SuggestedLatencyMS = (int)SendMessage( GetDlgItem( hWnd, IDC_LATENCY ), TBM_GETPOS, 0, 0 );
if( m_SuggestedLatencyMS < 10 ) m_SuggestedLatencyMS = 10;
if( m_SuggestedLatencyMS > 200 ) m_SuggestedLatencyMS = 200;
m_SuggestedLatencyMinimal = SendMessage(GetDlgItem(hWnd,IDC_MINIMIZE),BM_GETCHECK,0,0)==BST_CHECKED;
m_WasapiExclusiveMode = SendMessage(GetDlgItem(hWnd,IDC_EXCLUSIVE),BM_GETCHECK,0,0)==BST_CHECKED;
EndDialog(hWnd,0);
}
break;
case IDCANCEL:
EndDialog(hWnd,0);
break;
case IDC_PA_HOSTAPI:
{
if(wmEvent == CBN_SELCHANGE)
{
int api_idx = (int)SendMessage(GetDlgItem(hWnd,IDC_PA_HOSTAPI),CB_GETCURSEL,0,0)-1;
int apiId = SendMessageA(GetDlgItem(hWnd,IDC_PA_HOSTAPI),CB_GETITEMDATA,api_idx,0);
SendMessage(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_RESETCONTENT,0,0);
SendMessageA(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_ADDSTRING,0,(LPARAM)"Default Device");
SendMessage(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_SETITEMDATA,0,-1);
int idx=0;
int i=1,j=0;
for(std::vector<const PaDeviceInfo*>::iterator it=devices.begin(); it != devices.end(); it++, j++)
{
const PaDeviceInfo* info = *it;
if(info->hostApi == api_idx && info->maxOutputChannels > 0)
{
SendMessageA(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_ADDSTRING,0,(LPARAM)info->name);
SendMessage(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_SETITEMDATA,i,j);
i++;
}
}
SendMessage(GetDlgItem(hWnd,IDC_PA_DEVICE),CB_SETCURSEL,idx,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:
{
wchar_t temp[128];
if( wmEvent < 10 ) wmEvent = 10;
if( wmEvent > 200 ) wmEvent = 200;
SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent);
swprintf_s(temp, L"%d ms",wmEvent);
SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp);
break;
}
default:
return FALSE;
}
}
break;
default:
return FALSE;
}
return TRUE;
}
static BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
static BOOL CALLBACK DSEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext );
public:
virtual void Configure(uptr parent)
{
PaError err = Pa_Initialize(); // Initialization can be done multiple times, PA keeps a counter
if( err != paNoError )
{
fprintf(stderr,"* SPU2-X: PortAudio error: %s\n", Pa_GetErrorText( err ) );
return;
}
// keep portaudio initialized until the dialog closes
INT_PTR ret;
ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_PORTAUDIO),(HWND)parent,(DLGPROC)ConfigProc,1);
if(ret==-1)
{
MessageBox((HWND)parent,L"Error Opening the config dialog.",L"OMG ERROR!",MB_OK | MB_SETFOREGROUND);
return;
}
Pa_Terminate();
}
#else
virtual void Configure(uptr parent)
{
}
#endif
virtual bool Is51Out() const { return false; }
s32 Test() const
@ -302,6 +511,11 @@ public:
SetApiSettings(api);
m_WasapiExclusiveMode = CfgReadBool( L"PORTAUDIO", L"Wasapi_Exclusive_Mode", false);
m_SuggestedLatencyMinimal = CfgReadBool( L"PORTAUDIO", L"Minimal_Suggested_Latency", true);
m_SuggestedLatencyMS = CfgReadInt( L"PORTAUDIO", L"Manual_Suggested_Latency_MS", 20);
if( m_SuggestedLatencyMS < 10 ) m_SuggestedLatencyMS = 10;
if( m_SuggestedLatencyMS > 200 ) m_SuggestedLatencyMS = 200;
}
void SetApiSettings(wxString api)
@ -349,19 +563,24 @@ public:
CfgWriteStr( L"PORTAUDIO", L"Device", m_Device);
CfgWriteBool( L"PORTAUDIO", L"Wasapi_Exclusive_Mode", m_WasapiExclusiveMode);
CfgWriteBool( L"PORTAUDIO", L"Minimal_Suggested_Latency", m_SuggestedLatencyMinimal);
CfgWriteInt( L"PORTAUDIO", L"Manual_Suggested_Latency_MS", m_SuggestedLatencyMS);
}
} static PA;
#ifdef __LINUX__
int PaLinuxCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
return PA.ActualPaCallback(inputBuffer,outputBuffer,framesPerBuffer,timeInfo,statusFlags,userData);
}
#endif
int PaCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
return PA.ActualPaCallback(inputBuffer,outputBuffer,framesPerBuffer,timeInfo,statusFlags,userData);
}
BOOL CALLBACK Portaudio::ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
return PA._ConfigProc( hWnd, uMsg, wParam, lParam );
}
SndOutModule *PortaudioOut = &PA;

View File

@ -86,6 +86,7 @@ void ReadSettings()
Config_WaveOut.NumBuffers = CfgReadInt( L"WAVEOUT", L"Buffer_Count", 4 );
DSoundOut->ReadSettings();
PortaudioOut->ReadSettings();
SoundtouchCfg::ReadSettings();
DebugConfig::ReadSettings();
@ -126,7 +127,8 @@ void WriteSettings()
CfgWriteStr(L"DSP PLUGIN",L"Filename",dspPlugin);
CfgWriteInt(L"DSP PLUGIN",L"ModuleNum",dspPluginModule);
CfgWriteBool(L"DSP PLUGIN",L"Enabled",dspPluginEnabled);
PortaudioOut->WriteSettings();
DSoundOut->WriteSettings();
SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings();

View File

@ -13,13 +13,11 @@
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
@ -195,7 +193,7 @@ END
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
GUIDELINES DESIGNINFO
BEGIN
IDD_ABOUT, DIALOG
BEGIN
@ -280,8 +278,8 @@ IDB_SPU2X_SMALL BITMAP "..\\..\\spu2-x-sm.bmp"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,0,0,SVN_REV
PRODUCTVERSION 2,0,0,SVN_REV
FILEVERSION 2,0,0,4851
PRODUCTVERSION 2,0,0,4851
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -313,18 +311,72 @@ BEGIN
END
END
#endif // English (U.S.) resources
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Spanish resources
// English (United Kingdom) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_PORTAUDIO DIALOGEX 0, 0, 316, 166
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Portaudio Output Module Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,205,145,50,14
PUSHBUTTON "Cancel",IDCANCEL,259,145,50,14
COMBOBOX IDC_PA_HOSTAPI,7,18,95,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Host Api",IDC_STATIC,7,7,28,8
COMBOBOX IDC_PA_DEVICE,108,18,201,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Device Name",IDC_STATIC,107,7,42,8
CONTROL "",IDC_LATENCY,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,96,93,155,10
LTEXT "NOTE: Depending on the hardware and drivers, the suggested manual latency might not be used, and portaudio will choose the closest possible value.",IDC_STATIC,12,111,286,19
CTEXT "20ms",IDC_LATENCY_LABEL,264,93,35,11
GROUPBOX "Output Latency",IDC_STATIC,7,57,302,82
CONTROL "Use smallest possible (may cause issues if the actual value is too small)",IDC_MINIMIZE,
"Button",BS_AUTORADIOBUTTON | WS_GROUP,12,75,258,10
CONTROL "Use this latency:",IDC_MANUAL,"Button",BS_AUTORADIOBUTTON,12,93,69,10
CONTROL "WASAPI Exclusive Mode",IDC_EXCLUSIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,39,93,10
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_PORTAUDIO, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 309
TOPMARGIN, 7
BOTTOMMARGIN, 159
END
END
#endif // APSTUDIO_INVOKED
#endif // English (United Kingdom) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Spanish (Spain, International Sort) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESN)
#ifdef _WIN32
LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_MODERN
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
@ -350,7 +402,7 @@ END
#endif // APSTUDIO_INVOKED
#endif // Spanish resources
#endif // Spanish (Spain, International Sort) resources
/////////////////////////////////////////////////////////////////////////////

View File

@ -12,6 +12,7 @@
#define IDB_SPU2X_SMALL 116
#define IDD_CONFIG_SOUNDTOUCH 117
#define IDD_CONFIG_DEBUG 118
#define IDD_PORTAUDIO 119
#define IDC_EFFECTS_DISABLE 1001
#define IDC_DUMPREGS 1003
#define IDC_DUMPMEM 1004
@ -34,6 +35,7 @@
#define IDC_OUTCONF 1028
#define IDC_DSP_ENABLE 1029
#define IDC_DS_DEVICE 1032
#define IDC_PA_DEVICE 1033
#define IDC_DBG_OVERRUNS 1038
#define IDC_DBG_CACHE 1039
#define IDC_LATENCY_SLIDER 1040
@ -59,14 +61,19 @@
#define IDC_DEBUG_VISUAL 1066
#define IDC_VOLUME_LABEL 1067
#define IDC_VOLUME_SLIDER 1068
#define IDC_MINIMIZE 1069
#define IDC_MANUAL 1070
#define IDC_PA_HOSTAPI 1071
#define IDC_LATENCY 1072
#define IDC_EXCLUSIVE 1073
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 119
#define _APS_NEXT_RESOURCE_VALUE 120
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1069
#define _APS_NEXT_CONTROL_VALUE 1074
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif