Audio: Ability to select ouput device (e.g speakers, headphones)

This commit is contained in:
Souryo 2016-01-17 22:16:20 -05:00
parent 8f3cd51743
commit e455dd3eb4
11 changed files with 143 additions and 25 deletions

View file

@ -11,6 +11,7 @@ namespace Mesen.GUI.Config
{
public class AudioInfo
{
public string AudioDevice = "";
public bool EnableAudio = true;
public UInt32 AudioLatency = 100;
public UInt32 MasterVolume = 100;
@ -37,6 +38,7 @@ namespace Mesen.GUI.Config
static public void ApplyConfig()
{
AudioInfo audioInfo = ConfigManager.Config.AudioInfo;
InteropEmu.SetAudioDevice(audioInfo.AudioDevice);
InteropEmu.SetAudioLatency(audioInfo.AudioLatency);
InteropEmu.SetMasterVolume(audioInfo.MasterVolume / 10d);
InteropEmu.SetChannelVolume(0, ConvertVolume(audioInfo.Square1Volume));

View file

@ -182,6 +182,11 @@ namespace Mesen.GUI.Forms
}
}
}
} else if(field.FieldType == typeof(string)) {
combo.SelectedItem = value;
if(combo.SelectedIndex < 0) {
combo.SelectedIndex = 0;
}
}
}
}
@ -225,6 +230,8 @@ namespace Mesen.GUI.Forms
if(UInt32.TryParse(item, out numericValue)) {
field.SetValue(Entity, numericValue);
}
} else if(field.FieldType == typeof(string)) {
field.SetValue(Entity, ((ComboBox)kvp.Value).SelectedItem);
}
}
} catch {

View file

@ -43,6 +43,8 @@
this.lblLatencyMs = new System.Windows.Forms.Label();
this.lblAudioLatency = new System.Windows.Forms.Label();
this.cboSampleRate = new System.Windows.Forms.ComboBox();
this.lblAudioDevice = new System.Windows.Forms.Label();
this.cboAudioDevice = new System.Windows.Forms.ComboBox();
this.btnReset = new System.Windows.Forms.Button();
this.baseConfigPanel.SuspendLayout();
this.grpVolume.SuspendLayout();
@ -55,7 +57,7 @@
// baseConfigPanel
//
this.baseConfigPanel.Controls.Add(this.btnReset);
this.baseConfigPanel.Location = new System.Drawing.Point(0, 267);
this.baseConfigPanel.Location = new System.Drawing.Point(0, 295);
this.baseConfigPanel.Size = new System.Drawing.Size(470, 29);
this.baseConfigPanel.Controls.SetChildIndex(this.btnReset, 0);
//
@ -63,7 +65,7 @@
//
this.tableLayoutPanel2.SetColumnSpan(this.grpVolume, 2);
this.grpVolume.Controls.Add(this.tableLayoutPanel1);
this.grpVolume.Location = new System.Drawing.Point(3, 80);
this.grpVolume.Location = new System.Drawing.Point(3, 107);
this.grpVolume.Name = "grpVolume";
this.grpVolume.Size = new System.Drawing.Size(462, 185);
this.grpVolume.TabIndex = 2;
@ -189,21 +191,23 @@
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.Controls.Add(this.chkEnableAudio, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.lblSampleRate, 0, 1);
this.tableLayoutPanel2.Controls.Add(this.flowLayoutPanel2, 1, 2);
this.tableLayoutPanel2.Controls.Add(this.lblAudioLatency, 0, 2);
this.tableLayoutPanel2.Controls.Add(this.cboSampleRate, 1, 1);
this.tableLayoutPanel2.Controls.Add(this.grpVolume, 0, 3);
this.tableLayoutPanel2.Controls.Add(this.lblSampleRate, 0, 2);
this.tableLayoutPanel2.Controls.Add(this.flowLayoutPanel2, 1, 3);
this.tableLayoutPanel2.Controls.Add(this.lblAudioLatency, 0, 3);
this.tableLayoutPanel2.Controls.Add(this.cboSampleRate, 1, 2);
this.tableLayoutPanel2.Controls.Add(this.grpVolume, 0, 4);
this.tableLayoutPanel2.Controls.Add(this.lblAudioDevice, 0, 1);
this.tableLayoutPanel2.Controls.Add(this.cboAudioDevice, 1, 1);
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
this.tableLayoutPanel2.RowCount = 4;
this.tableLayoutPanel2.RowCount = 5;
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel2.Size = new System.Drawing.Size(470, 296);
this.tableLayoutPanel2.Size = new System.Drawing.Size(470, 324);
this.tableLayoutPanel2.TabIndex = 3;
//
// chkEnableAudio
@ -223,7 +227,7 @@
//
this.lblSampleRate.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblSampleRate.AutoSize = true;
this.lblSampleRate.Location = new System.Drawing.Point(3, 33);
this.lblSampleRate.Location = new System.Drawing.Point(3, 60);
this.lblSampleRate.Name = "lblSampleRate";
this.lblSampleRate.Size = new System.Drawing.Size(71, 13);
this.lblSampleRate.TabIndex = 0;
@ -233,7 +237,7 @@
//
this.flowLayoutPanel2.Controls.Add(this.nudLatency);
this.flowLayoutPanel2.Controls.Add(this.lblLatencyMs);
this.flowLayoutPanel2.Location = new System.Drawing.Point(77, 53);
this.flowLayoutPanel2.Location = new System.Drawing.Point(77, 80);
this.flowLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel2.Name = "flowLayoutPanel2";
this.flowLayoutPanel2.Size = new System.Drawing.Size(78, 24);
@ -275,7 +279,7 @@
//
this.lblAudioLatency.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblAudioLatency.AutoSize = true;
this.lblAudioLatency.Location = new System.Drawing.Point(3, 58);
this.lblAudioLatency.Location = new System.Drawing.Point(3, 85);
this.lblAudioLatency.Name = "lblAudioLatency";
this.lblAudioLatency.Size = new System.Drawing.Size(48, 13);
this.lblAudioLatency.TabIndex = 0;
@ -290,11 +294,30 @@
"22,050 Hz",
"44,100 Hz",
"48,000 Hz"});
this.cboSampleRate.Location = new System.Drawing.Point(80, 29);
this.cboSampleRate.Location = new System.Drawing.Point(80, 56);
this.cboSampleRate.Name = "cboSampleRate";
this.cboSampleRate.Size = new System.Drawing.Size(75, 21);
this.cboSampleRate.TabIndex = 5;
//
// lblAudioDevice
//
this.lblAudioDevice.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblAudioDevice.AutoSize = true;
this.lblAudioDevice.Location = new System.Drawing.Point(3, 33);
this.lblAudioDevice.Name = "lblAudioDevice";
this.lblAudioDevice.Size = new System.Drawing.Size(44, 13);
this.lblAudioDevice.TabIndex = 6;
this.lblAudioDevice.Text = "Device:";
//
// cboAudioDevice
//
this.cboAudioDevice.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboAudioDevice.FormattingEnabled = true;
this.cboAudioDevice.Location = new System.Drawing.Point(80, 29);
this.cboAudioDevice.Name = "cboAudioDevice";
this.cboAudioDevice.Size = new System.Drawing.Size(209, 21);
this.cboAudioDevice.TabIndex = 7;
//
// btnReset
//
this.btnReset.AutoSize = true;
@ -310,7 +333,7 @@
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(470, 296);
this.ClientSize = new System.Drawing.Size(470, 324);
this.Controls.Add(this.tableLayoutPanel2);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
@ -352,6 +375,7 @@
private System.Windows.Forms.Label lblSampleRate;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2;
private System.Windows.Forms.ComboBox cboSampleRate;
private System.Windows.Forms.Label lblAudioDevice;
private System.Windows.Forms.ComboBox cboAudioDevice;
}
}

View file

@ -19,6 +19,8 @@ namespace Mesen.GUI.Forms.Config
Entity = ConfigManager.Config.AudioInfo;
cboAudioDevice.Items.AddRange(InteropEmu.GetAudioDevices().ToArray());
AddBinding("EnableAudio", chkEnableAudio);
AddBinding("MasterVolume", trkMaster);
AddBinding("Square1Volume", trkSquare1Vol);
@ -28,6 +30,7 @@ namespace Mesen.GUI.Forms.Config
AddBinding("DmcVolume", trkDmcVol);
AddBinding("AudioLatency", nudLatency);
AddBinding("SampleRate", cboSampleRate);
AddBinding("AudioDevice", cboAudioDevice);
}
protected override void OnFormClosed(FormClosedEventArgs e)

View file

@ -117,4 +117,7 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View file

@ -87,6 +87,9 @@ namespace Mesen.GUI
[DllImport(DLLPath, EntryPoint="GetScreenSize")] private static extern void GetScreenSizeWrapper(out ScreenSize size);
[DllImport(DLLPath, EntryPoint= "GetAudioDevices")] private static extern IntPtr GetAudioDevicesWrapper();
[DllImport(DLLPath)] public static extern void SetAudioDevice(string audioDevice);
[DllImport(DLLPath)] public static extern void DebugInitialize();
[DllImport(DLLPath)] public static extern void DebugRelease();
[DllImport(DLLPath)] public static extern void DebugGetState(ref DebugState state);
@ -237,6 +240,10 @@ namespace Mesen.GUI
public static string GetROMPath() { return PtrToStringUtf8(InteropEmu.GetROMPathWrapper()); }
public static string GetKeyName(UInt32 key) { return PtrToStringUtf8(InteropEmu.GetKeyNameWrapper(key)); }
public static List<string> GetAudioDevices()
{
return new List<string>(PtrToStringUtf8(InteropEmu.GetAudioDevicesWrapper()).Split(new string[1] { "||" }, StringSplitOptions.RemoveEmptyEntries ));
}
private static string PtrToStringUtf8(IntPtr ptr)
{

View file

@ -220,6 +220,14 @@ namespace InteropEmu {
DllExport void __stdcall GetRgbPalette(uint32_t *paletteBuffer) { EmulationSettings::GetRgbPalette(paletteBuffer); }
DllExport void __stdcall SetRgbPalette(uint32_t *paletteBuffer) { EmulationSettings::SetRgbPalette(paletteBuffer); }
DllExport const char* __stdcall GetAudioDevices()
{
_returnString = _soundManager->GetAvailableDevices();
return _returnString.c_str();
}
DllExport void __stdcall SetAudioDevice(char* audioDevice) { _soundManager->SetAudioDevice(audioDevice); }
DllExport void __stdcall GetScreenSize(ScreenSize &size) { VideoDecoder::GetInstance()->GetScreenSize(size); }
}
}

View file

@ -10,6 +10,8 @@ SoundManager::SoundManager(HWND hwnd)
_primaryBuffer = 0;
_secondaryBuffer = 0;
memset(&_audioDeviceID, 0, sizeof(_audioDeviceID));
if(InitializeDirectSound(44100)) {
SoundMixer::RegisterAudioDevice(this);
} else {
@ -22,6 +24,52 @@ SoundManager::~SoundManager()
Release();
}
bool CALLBACK SoundManager::DirectSoundEnumProc(LPGUID lpGUID, LPCSTR lpszDesc, LPCSTR lpszDrvName, LPVOID lpContext)
{
vector<SoundDeviceInfo> *devices = (vector<SoundDeviceInfo>*)lpContext;
SoundDeviceInfo deviceInfo;
deviceInfo.description = lpszDesc;
if(lpGUID != nullptr) {
memcpy((void*)&deviceInfo.guid, lpGUID, 16);
} else {
memset((void*)&deviceInfo.guid, 0, 16);
}
devices->push_back(deviceInfo);
return true;
}
vector<SoundDeviceInfo> SoundManager::GetAvailableDeviceInfo()
{
vector<SoundDeviceInfo> devices;
DirectSoundEnumerate((LPDSENUMCALLBACKA)SoundManager::DirectSoundEnumProc, &devices);
return devices;
}
string SoundManager::GetAvailableDevices()
{
string deviceString;
for(SoundDeviceInfo device : GetAvailableDeviceInfo()) {
deviceString += device.description + "||"s;
}
return deviceString;
}
void SoundManager::SetAudioDevice(string deviceName)
{
memset(&_audioDeviceID, 0, sizeof(_audioDeviceID));
for(SoundDeviceInfo device : GetAvailableDeviceInfo()) {
if(device.description.compare(deviceName) == 0) {
memcpy((void*)&_audioDeviceID, (void*)&device.guid, 16);
break;
}
}
_needReset = true;
}
bool SoundManager::InitializeDirectSound(uint32_t sampleRate)
{
HRESULT result;
@ -29,7 +77,7 @@ bool SoundManager::InitializeDirectSound(uint32_t sampleRate)
WAVEFORMATEX waveFormat;
// Initialize the direct sound interface pointer for the default sound device.
result = DirectSoundCreate8(NULL, &_directSound, NULL);
result = DirectSoundCreate8(&_audioDeviceID, &_directSound, NULL);
if(FAILED(result)) {
return false;
}
@ -107,6 +155,7 @@ bool SoundManager::InitializeDirectSound(uint32_t sampleRate)
void SoundManager::Release()
{
_needReset = false;
_lastWriteOffset = 0;
if(_secondaryBuffer) {
@ -179,7 +228,7 @@ void SoundManager::Play()
void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t soundBufferSize, uint32_t sampleRate)
{
if(_sampleRate != sampleRate) {
if(_sampleRate != sampleRate || _needReset) {
Release();
InitializeDirectSound(sampleRate);
}

View file

@ -3,6 +3,12 @@
#include "stdafx.h"
#include "../Core/IAudioDevice.h"
struct SoundDeviceInfo
{
string description;
GUID guid;
};
class SoundManager : public IAudioDevice
{
public:
@ -15,7 +21,12 @@ public:
void Pause();
void Stop();
string GetAvailableDevices();
void SetAudioDevice(string deviceName);
private:
vector<SoundDeviceInfo> GetAvailableDeviceInfo();
static bool CALLBACK DirectSoundEnumProc(LPGUID lpGUID, LPCSTR lpszDesc, LPCSTR lpszDrvName, LPVOID lpContext);
bool InitializeDirectSound(uint32_t sampleRate);
void ShutdownDirectSound();
void ClearSecondaryBuffer();
@ -23,6 +34,8 @@ private:
private:
HWND _hWnd;
GUID _audioDeviceID;
bool _needReset = false;
uint16_t _lastWriteOffset = 0;
uint16_t _previousLatency = 0;

View file

@ -30,47 +30,48 @@
<ProjectGuid>{7761E790-B42C-4179-8550-8365FF9EB23E}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>Windows</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release x64|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release x64|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">

View file

@ -43,4 +43,5 @@
using std::list;
using std::vector;
using std::shared_ptr;
using std::string;
using std::string;
using namespace std::literals::string_literals;