diff --git a/GUI.NET/Config/AudioInfo.cs b/GUI.NET/Config/AudioInfo.cs index 8ed3b7f2..32aa7d9b 100644 --- a/GUI.NET/Config/AudioInfo.cs +++ b/GUI.NET/Config/AudioInfo.cs @@ -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)); diff --git a/GUI.NET/Forms/BaseConfigForm.cs b/GUI.NET/Forms/BaseConfigForm.cs index d8934941..0be0eb25 100644 --- a/GUI.NET/Forms/BaseConfigForm.cs +++ b/GUI.NET/Forms/BaseConfigForm.cs @@ -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 { diff --git a/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs b/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs index 64e99670..1aff7779 100644 --- a/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs +++ b/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs @@ -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; } } \ No newline at end of file diff --git a/GUI.NET/Forms/Config/frmAudioConfig.cs b/GUI.NET/Forms/Config/frmAudioConfig.cs index 08c22202..2577122c 100644 --- a/GUI.NET/Forms/Config/frmAudioConfig.cs +++ b/GUI.NET/Forms/Config/frmAudioConfig.cs @@ -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) diff --git a/GUI.NET/Forms/Config/frmAudioConfig.resx b/GUI.NET/Forms/Config/frmAudioConfig.resx index 1af7de15..8766f298 100644 --- a/GUI.NET/Forms/Config/frmAudioConfig.resx +++ b/GUI.NET/Forms/Config/frmAudioConfig.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + \ No newline at end of file diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index 7d039d86..a9a4c0f0 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -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 GetAudioDevices() + { + return new List(PtrToStringUtf8(InteropEmu.GetAudioDevicesWrapper()).Split(new string[1] { "||" }, StringSplitOptions.RemoveEmptyEntries )); + } private static string PtrToStringUtf8(IntPtr ptr) { diff --git a/InteropDLL/ConsoleWrapper.cpp b/InteropDLL/ConsoleWrapper.cpp index 1fd4332f..5c2716a9 100644 --- a/InteropDLL/ConsoleWrapper.cpp +++ b/InteropDLL/ConsoleWrapper.cpp @@ -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); } } } \ No newline at end of file diff --git a/Windows/SoundManager.cpp b/Windows/SoundManager.cpp index f4aa09b3..47ea62fb 100644 --- a/Windows/SoundManager.cpp +++ b/Windows/SoundManager.cpp @@ -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 *devices = (vector*)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 SoundManager::GetAvailableDeviceInfo() +{ + vector 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); } diff --git a/Windows/SoundManager.h b/Windows/SoundManager.h index 52b5f12c..fdcd42e7 100644 --- a/Windows/SoundManager.h +++ b/Windows/SoundManager.h @@ -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 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; diff --git a/Windows/Windows.vcxproj b/Windows/Windows.vcxproj index e50e7a4a..d830abda 100644 --- a/Windows/Windows.vcxproj +++ b/Windows/Windows.vcxproj @@ -30,47 +30,48 @@ {7761E790-B42C-4179-8550-8365FF9EB23E} Win32Proj Windows + 8.1 StaticLibrary true v140 - Unicode + MultiByte StaticLibrary true v140 - Unicode + MultiByte StaticLibrary false v140 true - Unicode + MultiByte StaticLibrary false v140 true - Unicode + MultiByte StaticLibrary false v140 true - Unicode + MultiByte StaticLibrary false v140 true - Unicode + MultiByte diff --git a/Windows/stdafx.h b/Windows/stdafx.h index 92f5cad0..4db3bd9d 100644 --- a/Windows/stdafx.h +++ b/Windows/stdafx.h @@ -43,4 +43,5 @@ using std::list; using std::vector; using std::shared_ptr; -using std::string; \ No newline at end of file +using std::string; +using namespace std::literals::string_literals; \ No newline at end of file