win32: add audio device selection (xaudio2 only for the moment)

This commit is contained in:
OV2 2018-12-15 14:19:16 +01:00
parent a8119d531a
commit 3832ec3607
10 changed files with 300 additions and 151 deletions

View File

@ -125,8 +125,13 @@ returns true if successful, false otherwise
bool CXAudio2::InitVoices(void)
{
HRESULT hr;
// subtract -1, we added "Default" as first index
int device_index = FindDeviceIndex(GUI.AudioDevice) - 1;
if (device_index < 0)
device_index = 0;
if ( FAILED(hr = pXAudio2->CreateMasteringVoice( &pMasterVoice, (Settings.Stereo?2:1),
Settings.SoundPlaybackRate, 0, 0 , NULL ) ) ) {
Settings.SoundPlaybackRate, 0, device_index, NULL ) ) ) {
DXTRACE_ERR_MSGBOX(TEXT("Unable to create mastering voice."),hr);
return false;
}
@ -308,3 +313,55 @@ void CXAudio2::ProcessSound()
availableSamples -= singleBufferSamples;
}
}
/* CXAudio2::GetDeviceList
get a list of the available output devices
-----
returns a vector of display names
*/
std::vector<std::wstring> CXAudio2::GetDeviceList()
{
std::vector<std::wstring> device_list;
if (pXAudio2)
{
UINT32 num_devices;
pXAudio2->GetDeviceCount(&num_devices);
device_list.push_back(_T("Default"));
for (unsigned int i = 0; i < num_devices; i++)
{
XAUDIO2_DEVICE_DETAILS device_details;
if (SUCCEEDED(pXAudio2->GetDeviceDetails(i, &device_details)))
{
device_list.push_back(device_details.DisplayName);
}
}
}
return device_list;
}
/* CXAudio2::FindDeviceIndex
find a device name in the list of possible output devices
-----
returns the index in the device list returned by GetDeviceList
*/
int CXAudio2::FindDeviceIndex(TCHAR *audio_device)
{
std::vector<std::wstring> device_list = GetDeviceList();
int index = 0;
for (int i = 0; i < device_list.size(); i++)
{
if (_tcsstr(device_list[i].c_str(), audio_device) != NULL)
{
index = i;
break;
}
}
return index;
}

View File

@ -41,6 +41,9 @@ private:
bool InitXAudio2(void);
void DeInitXAudio2(void);
std::vector<std::wstring> GetDeviceList();
int FindDeviceIndex(TCHAR *audio_device);
public:
CXAudio2(void);
~CXAudio2(void);

View File

@ -7,6 +7,8 @@
#ifndef IS9XSOUNDOUTPUT_H
#define IS9XSOUNDOUTPUT_H
#include "../port.h"
#include <vector>
#include <string>
/* IS9xSoundOutput
Interface for the sound output.
@ -31,6 +33,19 @@ public:
// Host sound system. If the sound system is callback based, ProcessSound should do a syncronized
// S9xFinalizeSamples and return.
virtual void ProcessSound()=0;
// GetDeviceList should return a list of device strings that can be displayed in a dropdown
virtual std::vector<std::wstring> GetDeviceList()
{
return std::vector<std::wstring>();
}
// FindDeviceIndex should try to find a matching index in the device list for a particular device string
virtual int FindDeviceIndex(TCHAR *audio_device)
{
return 0;
}
};
#endif

View File

@ -33,7 +33,6 @@
#define IDD_CREATEMOVIE 135
#define IDD_KEYCUSTOM 136
#define IDI_ICON1 144
#define IDI_ICON2 160
#define IDB_REMOVABLE 145
#define IDB_RAMDISK 146
#define IDB_UNKNOWN 147
@ -42,10 +41,12 @@
#define IDD_MULTICART 150
#define IDD_DIALOG_SHADER_PARAMS 155
#define IDD_DIALOG_XAUDIO2_INIT_ERROR 159
#define IDI_ICON2 160
#define IDC_DRIVER 1001
#define IDC_BUFLEN 1002
#define IDC_RATE 1003
#define IDC_MIX 1004
#define IDC_OUTPUT_DEVICE 1004
#define IDC_DYNRATECONTROL 1005
#define IDC_STEREO 1006
#define IDC_REV_STEREO 1007

View File

@ -26,40 +26,42 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// Dialog
//
IDD_SOUND_OPTS DIALOGEX 0, 0, 413, 144
STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
IDD_SOUND_OPTS DIALOGEX 0, 0, 413, 157
STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
CAPTION "Sound Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Sound Quality",IDC_STATIC,119,7,286,112,0,WS_EX_TRANSPARENT
DEFPUSHBUTTON "&OK",IDOK,288,122,56,16
COMBOBOX IDC_DRIVER,177,24,106,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Sound Driver:",IDC_STATIC,125,25,49,11
COMBOBOX IDC_BUFLEN,177,56,106,101,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Buffer Length:",IDC_STATIC,125,58,49,11
COMBOBOX IDC_RATE,177,40,106,171,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Playback Rate:",IDC_STATIC,125,41,49,11
CONTROL "&Dynamic Rate Control",IDC_DYNRATECONTROL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,295,90,96,10
CONTROL "&Automatic Input Rate",IDC_AUTOMATICINPUTRATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,295,105,96,10
CONTROL "&Stereo",IDC_STEREO,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,295,15,93,10
CONTROL "&Reverse Stereo",IDC_REV_STEREO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,295,30,94,10
GROUPBOX "Sound Quality",IDC_STATIC,119,7,286,124,0,WS_EX_TRANSPARENT
DEFPUSHBUTTON "&OK",IDOK,288,134,56,16
COMBOBOX IDC_DRIVER,177,34,106,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Sound Driver:",IDC_STATIC,125,36,49,11
COMBOBOX IDC_BUFLEN,177,68,106,101,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Buffer Length:",IDC_STATIC,125,70,49,11
COMBOBOX IDC_RATE,177,51,106,171,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Playback Rate:",IDC_STATIC,125,53,49,11
CONTROL "&Dynamic Rate Control",IDC_DYNRATECONTROL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,295,97,102,10
CONTROL "&Automatic Input Rate",IDC_AUTOMATICINPUTRATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,295,109,102,10
CONTROL "&Stereo",IDC_STEREO,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,295,37,102,10
CONTROL "&Reverse Stereo",IDC_REV_STEREO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,295,49,102,10
CONTROL "&Synchronize with sound core",IDC_SYNC_TO_SOUND_CPU,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,295,75,102,10
PUSHBUTTON "&Cancel",IDCANCEL,350,122,56,16
CONTROL "&Mute sound",IDC_MUTE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,295,45,93,12
CONTROL "Frame Advance mu&te",IDC_FAMT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,295,60,90,12
CONTROL "",IDC_INRATE,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | WS_TABSTOP,124,88,157,26
EDITTEXT IDC_INRATEEDIT,177,74,105,12,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "Input Rate:",IDC_INRATETEXT,126,74,46,11
CONTROL "",IDC_SLIDER_VOLUME_REGULAR,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | WS_TABSTOP | 0x400,22,25,23,73
EDITTEXT IDC_EDIT_VOLUME_REGULAR,22,102,22,13,ES_AUTOHSCROLL
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,295,85,102,10
PUSHBUTTON "&Cancel",IDCANCEL,350,134,56,16
CONTROL "&Mute sound",IDC_MUTE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,295,61,102,10
CONTROL "Frame Advance mu&te",IDC_FAMT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,295,73,102,10
CONTROL "",IDC_INRATE,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | WS_TABSTOP,124,100,157,26
EDITTEXT IDC_INRATEEDIT,177,86,105,12,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "Input Rate:",IDC_INRATETEXT,126,86,46,11
CONTROL "",IDC_SLIDER_VOLUME_REGULAR,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | WS_TABSTOP | 0x400,22,25,23,80
EDITTEXT IDC_EDIT_VOLUME_REGULAR,22,111,22,13,ES_AUTOHSCROLL
LTEXT "Regular",IDC_STATIC,22,17,49,10
GROUPBOX "Volume",IDC_STATIC,7,7,105,112,0,WS_EX_TRANSPARENT
CONTROL "",IDC_SLIDER_VOLUME_TURBO,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | WS_TABSTOP | 0x400,70,25,23,73
EDITTEXT IDC_EDIT_VOLUME_TURBO,70,102,22,13,ES_AUTOHSCROLL
GROUPBOX "Volume",IDC_STATIC,7,7,105,124,0,WS_EX_TRANSPARENT
CONTROL "",IDC_SLIDER_VOLUME_TURBO,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | WS_TABSTOP | 0x400,70,25,23,80
EDITTEXT IDC_EDIT_VOLUME_TURBO,70,111,22,13,ES_AUTOHSCROLL
LTEXT "Fast-Forward",IDC_STATIC,62,17,49,10
LTEXT "%",IDC_STATIC,47,104,8,8
LTEXT "%",IDC_STATIC,95,104,8,8
LTEXT "%",IDC_STATIC,47,113,8,8
LTEXT "%",IDC_STATIC,95,113,8,8
COMBOBOX IDC_OUTPUT_DEVICE,177,17,220,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Output Device:",IDC_STATIC,125,19,49,11
END
IDD_ROM_INFO DIALOGEX 0, 0, 233, 185
@ -575,7 +577,7 @@ BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 406
TOPMARGIN, 7
BOTTOMMARGIN, 138
BOTTOMMARGIN, 150
END
IDD_ROM_INFO, DIALOG
@ -823,6 +825,7 @@ IDB_HIDDENFOLDER BITMAP "hiddir.bmp"
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "icon1.ico"
IDI_ICON2 ICON "icon2.ico"

View File

@ -828,6 +828,7 @@ void WinRegisterConfigItems()
AddBoolC("MuteFrameAdvance", GUI.FAMute, false, "true to prevent Snes9x from outputting sound when the Frame Advance command is in use");
AddUIntC("VolumeRegular", GUI.VolumeRegular, 100, "volume during regular play (percentage between 0 and 100)");
AddUIntC("VolumeTurbo", GUI.VolumeTurbo, 100, "volume during turbo mode (percentage between 0 and 100)");
AddStringC("OutputDevice", GUI.AudioDevice, MAX_AUDIO_NAME_LENGTH, "Default", "Name of the output audio device (substring matching, XAudio2 only atm), set to 'Default' for default audio device");
#undef CATEGORY
#define CATEGORY "Controls"
AddBoolC("AllowLeftRight", Settings.UpAndDown, false, "true to allow left+right and up+down");

View File

@ -107,3 +107,19 @@ void S9xSoundCallback(void *data)
S9xSoundOutput->ProcessSound();
}
/* GetAvailableSoundDevices
returns a list of output devices available for the current output driver
*/
std::vector<std::wstring> GetAvailableSoundDevices()
{
return S9xSoundOutput->GetDeviceList();
}
/* FindAudioDeviceIndex
find an audio device that matches the currently configured audio device string
*/
int FindAudioDeviceIndex(TCHAR *audio_device)
{
return S9xSoundOutput->FindDeviceIndex(audio_device);
}

View File

@ -7,8 +7,13 @@
#ifndef WIN32_SOUND_H
#define WIN32_SOUND_H
#include <vector>
#include <string>
bool ReInitSound();
void S9xSoundCallback(void *data);
void CloseSoundDevice();
std::vector<std::wstring> GetAvailableSoundDevices();
int FindAudioDeviceIndex(TCHAR *audio_device);
#endif

View File

@ -4317,21 +4317,53 @@ BOOL CreateToolTip(int toolID, HWND hDlg, TCHAR* pText)
return TRUE;
}
void UpdateAudioDeviceDropdown(HWND hCtl)
{
std::vector<std::wstring> device_list = GetAvailableSoundDevices();
ComboBox_ResetContent(hCtl);
int num_devices = device_list.size();
if (!num_devices)
{
ComboBox_AddString(hCtl, _T("Default"));
}
else
{
for (int i = 0; i < num_devices; i++)
{
ComboBox_AddString(hCtl, device_list[i].c_str());
}
}
}
INT_PTR CALLBACK DlgSoundConf(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
HWND hTrackbar;
TCHAR valTxt[10];
// temporary GUI state for restoring after switching devices (need to actually switch devices to get output devices)
static int prevDriver;
switch(msg)
{
case WM_INITDIALOG:
{
WinRefreshDisplay();
prevDriver = GUI.SoundDriver;
// FIXME: these strings should come from wlanguage.h
CreateToolTip(IDC_INRATEEDIT, hDlg, TEXT("For each 'Input rate' samples generated by the SNES, 'Playback rate' samples will produced. If you experience crackling you can try to lower this setting."));
CreateToolTip(IDC_INRATE, hDlg, TEXT("For each 'Input rate' samples generated by the SNES, 'Playback rate' samples will produced. If you experience crackling you can try to lower this setting."));
CreateToolTip(IDC_DYNRATECONTROL, hDlg, TEXT("Try to dynamically adjust the input rate to never overflow or underflow the sound buffer. Only works with XAudio2."));
HWND output_dropdown = GetDlgItem(hDlg, IDC_OUTPUT_DEVICE);
UpdateAudioDeviceDropdown(output_dropdown);
ComboBox_SetCurSel(output_dropdown, FindAudioDeviceIndex(GUI.AudioDevice));
int pos;
pos = SendDlgItemMessage(hDlg, IDC_DRIVER, CB_INSERTSTRING, -1, (LPARAM)TEXT("Snes9x DirectSound"));
SendDlgItemMessage(hDlg, IDC_DRIVER, CB_SETITEMDATA, pos, WIN_SNES9X_DIRECT_SOUND_DRIVER);
@ -4455,6 +4487,7 @@ INT_PTR CALLBACK DlgSoundConf(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
SendDlgItemMessage(hDlg, IDC_AUTOMATICINPUTRATE, BM_SETCHECK, BST_CHECKED, 0);
return true;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
@ -4537,14 +4570,20 @@ INT_PTR CALLBACK DlgSoundConf(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
sliderVal = _tstoi(valTxt);
GUI.VolumeTurbo = (sliderVal >= 0 && sliderVal <= 100) ? sliderVal : 100;
// output device
Edit_GetText(GetDlgItem(hDlg, IDC_OUTPUT_DEVICE), GUI.AudioDevice, MAX_AUDIO_NAME_LENGTH);
WinSaveConfigFile();
// already done in WinProc on return
// ReInitSound();
} /* FALL THROUGH */
EndDialog(hDlg, 1);
}
case IDCANCEL:
GUI.SoundDriver = prevDriver;
EndDialog(hDlg, 1);
return true;
@ -4590,6 +4629,15 @@ INT_PTR CALLBACK DlgSoundConf(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
SendDlgItemMessage(hDlg,IDC_BUFLEN,CB_SETCURSEL,7,0);
break;
}
// get current selected device name, switch driver, try to select the same
HWND output_dropdown = GetDlgItem(hDlg, IDC_OUTPUT_DEVICE);
TCHAR selected_device[MAX_AUDIO_NAME_LENGTH];
Edit_GetText(output_dropdown, selected_device, MAX_AUDIO_NAME_LENGTH);
GUI.SoundDriver = driver;
ReInitSound();
UpdateAudioDeviceDropdown(output_dropdown);
ComboBox_SetCurSel(output_dropdown, FindAudioDeviceIndex(selected_device));
return true;
}
else return false;
@ -7349,7 +7397,6 @@ INT_PTR CALLBACK DlgFunky(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
lstrcpy(prevD3DShaderFile, GUI.D3DshaderFileName);
lstrcpy(prevOGLShaderFile, GUI.OGLshaderFileName);
_stprintf(s, TEXT("Current: %dx%d %dbit %dHz"), GUI.FullscreenMode.width, GUI.FullscreenMode.height, GUI.FullscreenMode.depth, GUI.FullscreenMode.rate);
SendDlgItemMessage(hDlg, IDC_CURRMODE, WM_SETTEXT, 0, (LPARAM)s);

View File

@ -28,7 +28,7 @@
#include "rsrc/resource.h"
#define COUNT(a) (sizeof (a) / sizeof (a[0]))
#define GUI_VERSION 1008
#define MAX_AUDIO_NAME_LENGTH 1024
#define MAX_RECENT_GAMES_LIST_SIZE 32
#define MAX_RECENT_HOSTS_LIST_SIZE 16
@ -216,6 +216,7 @@ struct sGUI {
// used for sync sound synchronization
CRITICAL_SECTION SoundCritSect;
HANDLE SoundSyncEvent;
TCHAR AudioDevice[MAX_AUDIO_NAME_LENGTH];
TCHAR RomDir [_MAX_PATH];
TCHAR ScreensDir [_MAX_PATH];