Remove DirectSound support

This has been the source of various reported odd issues/crashes due to buggy DirectSound drivers. DirectSound is just deprecated anyways, and the code handling it is very fragile and filled with hacks. XAudio2 would be preferred in practically any case (not to mention XAudio2 is built-in for modern Windows versions, with some redist version available for older Windows versions). OpenAL works fine as a substitute in case XAudio2 isn't available.
This commit is contained in:
CasualPokePlayer 2024-05-05 17:52:44 -07:00
parent 706d7c43e6
commit 9a60f84ff6
12 changed files with 59 additions and 461 deletions

View File

@ -14,7 +14,6 @@
<PackageReference Include="Silk.NET.OpenAL.Extensions.EXT" />
<PackageReference Include="Vortice.MediaFoundation" />
<PackageReference Include="Vortice.XAudio2" />
<PackageReference Include="SharpDX.DirectSound" />
<PackageReference Include="ppy.SDL2-CS" ExcludeAssets="native;contentFiles" />
<ProjectReference Include="$(ProjectDir)../BizHawk.Client.Common/BizHawk.Client.Common.csproj" />
</ItemGroup>

View File

@ -1,380 +0,0 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using BizHawk.Client.Common;
using BizHawk.Common;
using SharpDX;
using SharpDX.DirectSound;
using SharpDX.Multimedia;
namespace BizHawk.Bizware.Audio
{
public sealed class DirectSoundSoundOutput : ISoundOutput
{
private readonly IHostAudioManager _sound;
private readonly IntPtr _mainWindowHandle;
private bool _disposed;
private DirectSound _device;
private SecondarySoundBuffer _deviceBuffer, _wavDeviceBuffer;
private int _actualWriteOffsetBytes = -1;
private int _filledBufferSizeBytes;
private long _lastWriteTime;
private int _lastWriteCursor;
private int _retryCounter;
public DirectSoundSoundOutput(IHostAudioManager sound, IntPtr mainWindowHandle, string soundDevice)
{
_sound = sound;
_mainWindowHandle = mainWindowHandle; // needed for resetting _device on device invalidation
_retryCounter = 5;
var deviceInfo = DirectSound.GetDevices().Find(d => d.Description == soundDevice);
_device = deviceInfo != null ? new(deviceInfo.DriverGuid) : new();
_device.SetCooperativeLevel(mainWindowHandle, CooperativeLevel.Priority);
}
public void Dispose()
{
if (_disposed) return;
StopWav(throwOnInvalidDevice: false);
_device.Dispose();
_device = null;
_disposed = true;
}
public static IEnumerable<string> GetDeviceNames()
{
return DirectSound.GetDevices().Select(d => d.Description);
}
private int BufferSizeSamples { get; set; }
private int BufferSizeBytes => BufferSizeSamples * _sound.BlockAlign;
public int MaxSamplesDeficit { get; private set; }
private void ResetToDefaultDevice()
{
// can't use StopSound, as that checks IsPlaying, which will end up calling this function again!
_deviceBuffer.Dispose();
_deviceBuffer = null;
StopWav(throwOnInvalidDevice: false);
_device.Dispose();
_device = new();
_device.SetCooperativeLevel(_mainWindowHandle, CooperativeLevel.Priority);
StartPlaying();
}
private bool IsPlaying
{
get
{
if (_deviceBuffer == null)
{
return false;
}
try
{
var status = (BufferStatus)_deviceBuffer.Status;
return (status & (BufferStatus.BufferLost | BufferStatus.Playing)) is BufferStatus.Playing;
}
catch (SharpDXException)
{
// this only seems to ever occur if the device is disconnected...
ResetToDefaultDevice();
return false;
}
}
}
private void StartPlaying()
{
_actualWriteOffsetBytes = -1;
_filledBufferSizeBytes = 0;
_lastWriteTime = 0;
_lastWriteCursor = 0;
var attempts = _retryCounter;
while (!IsPlaying && attempts > 0)
{
attempts--;
try
{
if (_deviceBuffer == null)
{
var format = WaveFormat.CreateCustomFormat(
tag: WaveFormatEncoding.Pcm,
sampleRate: _sound.SampleRate,
channels: _sound.ChannelCount,
averageBytesPerSecond: _sound.SampleRate * _sound.BlockAlign,
blockAlign: _sound.BlockAlign,
bitsPerSample: _sound.BytesPerSample * 8);
var desc = new SoundBufferDescription
{
Format = format,
Flags =
BufferFlags.GlobalFocus |
BufferFlags.Software |
BufferFlags.GetCurrentPosition2 |
BufferFlags.ControlVolume,
BufferBytes = BufferSizeBytes
};
_deviceBuffer = new(_device, desc);
}
_deviceBuffer.Play(0, PlayFlags.Looping);
}
catch (SharpDXException)
{
_deviceBuffer?.Restore();
if (attempts > 0)
{
Thread.Sleep(10);
}
}
}
if (IsPlaying)
{
_retryCounter = 5;
}
else if (_retryCounter > 1)
{
_retryCounter--;
}
}
public void ApplyVolumeSettings(double volume)
{
if (IsPlaying)
{
try
{
// I'm not sure if this is "technically" correct but it works okay
const int range = Volume.Maximum - Volume.Minimum;
_deviceBuffer.Volume = (int)(Math.Pow(volume, 0.1) * range) + Volume.Minimum;
}
catch (SharpDXException)
{
}
}
}
public void StartSound()
{
BufferSizeSamples = _sound.MillisecondsToSamples(_sound.ConfigBufferSizeMs);
// 35 to 65 milliseconds depending on how big the buffer is. This is a trade-off
// between more frequent but less severe glitches (i.e. catching underruns before
// they happen and filling the buffer with silence) or less frequent but more
// severe glitches. At least on my Windows 8 machines, the distance between the
// play and write cursors can be up to 30 milliseconds, so that would be the
// absolute minimum we could use here.
var minBufferFullnessMs = Math.Min(35 + (_sound.ConfigBufferSizeMs - 60) / 2, 65);
MaxSamplesDeficit = BufferSizeSamples - _sound.MillisecondsToSamples(minBufferFullnessMs);
StartPlaying();
}
public void StopSound()
{
if (IsPlaying)
{
try
{
_deviceBuffer.Stop();
}
catch (SharpDXException)
{
}
}
_deviceBuffer.Dispose();
_deviceBuffer = null;
BufferSizeSamples = 0;
}
public int CalculateSamplesNeeded()
{
var samplesNeeded = 0;
if (IsPlaying)
{
try
{
var currentWriteTime = Stopwatch.GetTimestamp();
_deviceBuffer.GetCurrentPosition(out var playCursor, out var writeCursor);
var isInitializing = _actualWriteOffsetBytes == -1;
var detectedUnderrun = false;
if (!isInitializing)
{
var elapsedSeconds = (currentWriteTime - _lastWriteTime) / (double)Stopwatch.Frequency;
var bufferSizeSeconds = (double) BufferSizeSamples / _sound.SampleRate;
var cursorDelta = CircularDistance(_lastWriteCursor, writeCursor, BufferSizeBytes);
cursorDelta += BufferSizeBytes * (int) Math.Round((elapsedSeconds - (cursorDelta / (double) (_sound.SampleRate * _sound.BlockAlign))) / bufferSizeSeconds);
_filledBufferSizeBytes -= cursorDelta;
detectedUnderrun = _filledBufferSizeBytes < 0;
}
if (isInitializing || detectedUnderrun)
{
_actualWriteOffsetBytes = writeCursor;
_filledBufferSizeBytes = 0;
}
samplesNeeded = CircularDistance(_actualWriteOffsetBytes, playCursor, BufferSizeBytes) / _sound.BlockAlign;
if (isInitializing || detectedUnderrun)
{
_sound.HandleInitializationOrUnderrun(detectedUnderrun, ref samplesNeeded);
}
_lastWriteTime = currentWriteTime;
_lastWriteCursor = writeCursor;
}
catch (SharpDXException)
{
samplesNeeded = 0;
}
}
return samplesNeeded;
}
private static int CircularDistance(int start, int end, int size)
{
return (end - start + size) % size;
}
public void WriteSamples(short[] samples, int sampleOffset, int sampleCount)
{
// For lack of a better place, this function will be the one that attempts to restart playing
// after a sound buffer is lost.
if (IsPlaying)
{
if (sampleCount == 0) return;
try
{
_deviceBuffer.Write(samples, sampleOffset * _sound.ChannelCount, sampleCount * _sound.ChannelCount, _actualWriteOffsetBytes, LockFlags.None);
_actualWriteOffsetBytes = (_actualWriteOffsetBytes + (sampleCount * _sound.BlockAlign)) % BufferSizeBytes;
_filledBufferSizeBytes += sampleCount * _sound.BlockAlign;
}
catch (SharpDXException)
{
_deviceBuffer.Restore();
StartPlaying();
}
}
else
{
_deviceBuffer?.Restore();
StartPlaying();
}
}
private bool IsWavPlaying
{
get
{
if (_wavDeviceBuffer == null)
{
return false;
}
var status = (BufferStatus)_wavDeviceBuffer.Status;
return (status & (BufferStatus.BufferLost | BufferStatus.Playing)) is BufferStatus.Playing;
}
}
private void StopWav(bool throwOnInvalidDevice = true)
{
bool isPlaying;
try
{
isPlaying = IsWavPlaying;
}
catch (SharpDXException)
{
if (throwOnInvalidDevice)
{
throw;
}
isPlaying = false;
}
if (isPlaying)
{
try
{
_wavDeviceBuffer.Stop();
}
catch (SharpDXException)
{
}
}
_wavDeviceBuffer?.Dispose();
_wavDeviceBuffer = null;
}
public void PlayWavFile(Stream wavFile, double volume)
{
using var wavStream = new SDL2WavStream(wavFile);
var format = wavStream.Format == SDL2WavStream.AudioFormat.F32LSB
? WaveFormat.CreateIeeeFloatWaveFormat(wavStream.Frequency, wavStream.Channels)
: new(wavStream.Frequency, wavStream.BitsPerSample, wavStream.Channels);
var desc = new SoundBufferDescription
{
Format = format,
Flags =
BufferFlags.GlobalFocus |
BufferFlags.Software |
BufferFlags.GetCurrentPosition2 |
BufferFlags.ControlVolume,
BufferBytes = unchecked((int)wavStream.Length)
};
StopWav();
_wavDeviceBuffer = new(_device, desc);
const int TEMP_BUFFER_LENGTH = 65536;
var tempBuffer = ArrayPool<byte>.Shared.Rent(TEMP_BUFFER_LENGTH);
try
{
var bufferOffset = 0;
while (true)
{
var numRead = wavStream.Read(tempBuffer, 0, TEMP_BUFFER_LENGTH);
if (numRead == 0)
{
break;
}
if (wavStream.Format == SDL2WavStream.AudioFormat.S16MSB)
{
EndiannessUtils.MutatingByteSwap16(tempBuffer.AsSpan()[..numRead]);
}
_wavDeviceBuffer.Write(tempBuffer, 0, numRead, bufferOffset, LockFlags.None);
bufferOffset += numRead;
}
}
finally
{
ArrayPool<byte>.Shared.Return(tempBuffer);
}
const int range = Volume.Maximum - Volume.Minimum;
_wavDeviceBuffer.Volume = (int)(Math.Pow(volume, 0.1) * range) + Volume.Minimum;
_wavDeviceBuffer.Play(0, PlayFlags.None);
}
}
}

View File

@ -114,13 +114,12 @@ namespace BizHawk.Bizware.Audio
{
if (_deviceResetRequired)
{
_deviceResetRequired = false;
StopSound();
StopWav();
_masteringVoice.Dispose();
_device.Dispose();
_deviceResetRequired = false;
_device = XAudio2.XAudio2Create();
_device.CriticalError += (_, _) => _deviceResetRequired = true;
_masteringVoice = _device.CreateMasteringVoice(

View File

@ -6,17 +6,38 @@ namespace BizHawk.Client.Common
{
public static class HostCapabilityDetector
{
private static bool? _hasDirectX = null;
public static bool HasDirectX => _hasDirectX ??= DetectDirectX();
private static bool DetectDirectX()
private static readonly Lazy<bool> _hasD3D9 = new(() =>
{
if (OSTailoredCode.IsUnixHost) return false;
var p = OSTailoredCode.LinkedLibManager.LoadOrZero("d3dx9_43.dll");
if (p == IntPtr.Zero) return false;
OSTailoredCode.LinkedLibManager.FreeByPtr(p);
return true;
}
});
private static readonly Lazy<bool> _hasXAudio2 = new(() =>
{
if (OSTailoredCode.IsUnixHost)
{
return false;
}
// This should always work for anything Windows 8+ (where XAudio 2.8/2.9 is built-in)
var libNames = new[] { "xaudio2_9.dll", "xaudio2_8.dll", "xaudio2_9redist.dll" };
foreach (var libName in libNames)
{
var p = OSTailoredCode.LinkedLibManager.LoadOrZero(libName);
if (p != IntPtr.Zero)
{
OSTailoredCode.LinkedLibManager.FreeByPtr(p);
return true;
}
}
return false;
});
public static bool HasD3D9 => _hasD3D9.Value;
public static bool HasXAudio2 => _hasXAudio2.Value;
}
}

View File

@ -220,7 +220,7 @@ namespace BizHawk.Client.Common
public int DispPrescale { get; set; } = 1;
public EDispMethod DispMethod { get; set; } = HostCapabilityDetector.HasDirectX && !OSTailoredCode.IsWine ? EDispMethod.D3D9 : EDispMethod.OpenGL;
public EDispMethod DispMethod { get; set; } = HostCapabilityDetector.HasD3D9 && !OSTailoredCode.IsWine ? EDispMethod.D3D9 : EDispMethod.OpenGL;
public int DispChromeFrameWindowed { get; set; } = 2;
public bool DispChromeStatusBarWindowed { get; set; } = true;
@ -248,7 +248,7 @@ namespace BizHawk.Client.Common
public int DispCropBottom { get; set; } = 0;
// Sound options
public ESoundOutputMethod SoundOutputMethod { get; set; } = HostCapabilityDetector.HasDirectX ? ESoundOutputMethod.DirectSound : ESoundOutputMethod.OpenAL;
public ESoundOutputMethod SoundOutputMethod { get; set; } = HostCapabilityDetector.HasXAudio2 ? ESoundOutputMethod.XAudio2 : ESoundOutputMethod.OpenAL;
/// <value>iff <see langword="false"/>, cores may skip processing audio</value>
/// <seealso cref="SoundEnabledNormal"/>

View File

@ -2,7 +2,10 @@
{
public enum ESoundOutputMethod
{
DirectSound, XAudio2, OpenAL, Dummy
LegacyDirectSound, // kept here to handle old configs
XAudio2,
OpenAL,
Dummy
}
public enum EDispManagerAR

View File

@ -885,7 +885,6 @@ namespace BizHawk.Client.EmuHawk
{
static IEnumerable<string> GetDeviceNamesCallback(ESoundOutputMethod outputMethod) => outputMethod switch
{
ESoundOutputMethod.DirectSound => DirectSoundSoundOutput.GetDeviceNames(),
ESoundOutputMethod.XAudio2 => XAudio2SoundOutput.GetDeviceNames(),
ESoundOutputMethod.OpenAL => OpenALSoundOutput.GetDeviceNames(),
_ => Enumerable.Empty<string>()
@ -903,7 +902,7 @@ namespace BizHawk.Client.EmuHawk
else
{
Sound.Dispose();
Sound = new Sound(Handle, Config, () => Emulator.VsyncRate());
Sound = new Sound(Config, () => Emulator.VsyncRate());
}
Sound.StartSound();
RewireSound();

View File

@ -595,10 +595,10 @@ namespace BizHawk.Client.EmuHawk
InputManager.ResetMainControllers(_autofireNullControls);
InputManager.AutofireStickyXorAdapter.SetOnOffPatternFromConfig(Config.AutofireOn, Config.AutofireOff);
var savedOutputMethod = Config.SoundOutputMethod;
if (savedOutputMethod is ESoundOutputMethod.Dummy) Config.SoundOutputMethod = HostCapabilityDetector.HasDirectX ? ESoundOutputMethod.DirectSound : ESoundOutputMethod.OpenAL;
if (savedOutputMethod is ESoundOutputMethod.Dummy) Config.SoundOutputMethod = HostCapabilityDetector.HasXAudio2 ? ESoundOutputMethod.XAudio2 : ESoundOutputMethod.OpenAL;
try
{
Sound = new Sound(Handle, Config, () => Emulator.VsyncRate());
Sound = new Sound(Config, () => Emulator.VsyncRate());
}
catch
{
@ -606,14 +606,12 @@ namespace BizHawk.Client.EmuHawk
{
ShowMessageBox(
owner: null,
text: savedOutputMethod is ESoundOutputMethod.DirectSound
? "Couldn't initialize DirectSound! Things may go poorly for you. Try changing your sound driver to 44.1khz instead of 48khz in mmsys.cpl."
: "Couldn't initialize sound device! Try changing the output method in Sound config.",
text: "Couldn't initialize sound device! Try changing the output method in Sound config.",
caption: "Initialization Error",
EMsgBoxIcon.Error);
}
Config.SoundOutputMethod = ESoundOutputMethod.Dummy;
Sound = new Sound(Handle, Config, () => Emulator.VsyncRate());
Sound = new Sound(Config, () => Emulator.VsyncRate());
}
Sound.StartSound();

View File

@ -32,7 +32,7 @@ namespace BizHawk.Client.EmuHawk
public int ConfigBufferSizeMs => Config.SoundBufferSizeMs;
public Sound(IntPtr mainWindowHandle, Config config, Func<double> getCoreVsyncRateCallback)
public Sound(Config config, Func<double> getCoreVsyncRateCallback)
{
BlockAlign = BytesPerSample * ChannelCount;
@ -40,9 +40,14 @@ namespace BizHawk.Client.EmuHawk
_outputProvider = new SoundOutputProvider(_getCoreVsyncRateCallback);
Config = config;
if (config.SoundOutputMethod == ESoundOutputMethod.LegacyDirectSound)
{
config.SoundOutputMethod = HostCapabilityDetector.HasXAudio2 ? ESoundOutputMethod.XAudio2 : ESoundOutputMethod.OpenAL;
}
if (OSTailoredCode.IsUnixHost)
{
// if DirectSound or XAudio is chosen, use OpenAL, otherwise comply with the user's choice
// if XAudio is chosen, use OpenAL, otherwise comply with the user's choice
_outputDevice = config.SoundOutputMethod == ESoundOutputMethod.Dummy
? new DummySoundOutput(this)
: new OpenALSoundOutput(this, config.SoundDevice);
@ -51,7 +56,6 @@ namespace BizHawk.Client.EmuHawk
{
_outputDevice = config.SoundOutputMethod switch
{
ESoundOutputMethod.DirectSound => new DirectSoundSoundOutput(this, mainWindowHandle, config.SoundDevice),
ESoundOutputMethod.XAudio2 => new XAudio2SoundOutput(this, config.SoundDevice),
ESoundOutputMethod.OpenAL => new OpenALSoundOutput(this, config.SoundDevice),
_ => new DummySoundOutput(this)

View File

@ -110,7 +110,7 @@ namespace BizHawk.Client.EmuHawk
RefreshAspectRatioOptions();
if (!HostCapabilityDetector.HasDirectX)
if (!HostCapabilityDetector.HasD3D9)
{
rbD3D9.Enabled = false;
rbD3D9.AutoCheck = false;

View File

@ -47,7 +47,6 @@
this.grpOutputMethod = new System.Windows.Forms.GroupBox();
this.rbOutputMethodOpenAL = new System.Windows.Forms.RadioButton();
this.rbOutputMethodXAudio2 = new System.Windows.Forms.RadioButton();
this.rbOutputMethodDirectSound = new System.Windows.Forms.RadioButton();
this.cbMuteFrameAdvance = new System.Windows.Forms.CheckBox();
this.cbEnableMaster = new System.Windows.Forms.CheckBox();
this.label3 = new BizHawk.WinForms.Controls.LocLabelEx();
@ -117,11 +116,7 @@
this.nudRWFF.Name = "nudRWFF";
this.nudRWFF.Size = new System.Drawing.Size(45, 20);
this.nudRWFF.TabIndex = 7;
this.nudRWFF.Value = new decimal(new int[] {
100,
0,
0,
0});
this.nudRWFF.Value = new decimal(new int[] { 100, 0, 0, 0 });
this.nudRWFF.ValueChanged += new System.EventHandler(this.nudRWFF_ValueChanged);
//
// cbEnableRWFF
@ -141,7 +136,7 @@
this.tbRWFF.Maximum = 100;
this.tbRWFF.Name = "tbRWFF";
this.tbRWFF.Orientation = System.Windows.Forms.Orientation.Vertical;
this.tbRWFF.Size = new System.Drawing.Size(42, 164);
this.tbRWFF.Size = new System.Drawing.Size(45, 164);
this.tbRWFF.TabIndex = 6;
this.tbRWFF.TickFrequency = 10;
this.tbRWFF.Scroll += new System.EventHandler(this.TbRwff_Scroll);
@ -167,7 +162,7 @@
this.tbNormal.Maximum = 100;
this.tbNormal.Name = "tbNormal";
this.tbNormal.Orientation = System.Windows.Forms.Orientation.Vertical;
this.tbNormal.Size = new System.Drawing.Size(42, 164);
this.tbNormal.Size = new System.Drawing.Size(45, 164);
this.tbNormal.TabIndex = 2;
this.tbNormal.TickFrequency = 10;
this.tbNormal.Scroll += new System.EventHandler(this.TrackBar1_Scroll);
@ -178,18 +173,12 @@
this.nudNormal.Name = "nudNormal";
this.nudNormal.Size = new System.Drawing.Size(45, 20);
this.nudNormal.TabIndex = 3;
this.nudNormal.Value = new decimal(new int[] {
100,
0,
0,
0});
this.nudNormal.Value = new decimal(new int[] { 100, 0, 0, 0 });
this.nudNormal.ValueChanged += new System.EventHandler(this.SoundVolNumeric_ValueChanged);
//
// listBoxSoundDevices
//
this.listBoxSoundDevices.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listBoxSoundDevices.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right)));
this.listBoxSoundDevices.FormattingEnabled = true;
this.listBoxSoundDevices.Location = new System.Drawing.Point(138, 110);
this.listBoxSoundDevices.Name = "listBoxSoundDevices";
@ -213,24 +202,12 @@
//
this.BufferSizeNumeric.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.BufferSizeNumeric.Location = new System.Drawing.Point(202, 208);
this.BufferSizeNumeric.Maximum = new decimal(new int[] {
250,
0,
0,
0});
this.BufferSizeNumeric.Minimum = new decimal(new int[] {
30,
0,
0,
0});
this.BufferSizeNumeric.Maximum = new decimal(new int[] { 250, 0, 0, 0 });
this.BufferSizeNumeric.Minimum = new decimal(new int[] { 30, 0, 0, 0 });
this.BufferSizeNumeric.Name = "BufferSizeNumeric";
this.BufferSizeNumeric.Size = new System.Drawing.Size(59, 20);
this.BufferSizeNumeric.TabIndex = 10;
this.BufferSizeNumeric.Value = new decimal(new int[] {
100,
0,
0,
0});
this.BufferSizeNumeric.Value = new decimal(new int[] { 100, 0, 0, 0 });
//
// BufferSizeUnitsLabel
//
@ -243,10 +220,9 @@
//
this.grpOutputMethod.Controls.Add(this.rbOutputMethodOpenAL);
this.grpOutputMethod.Controls.Add(this.rbOutputMethodXAudio2);
this.grpOutputMethod.Controls.Add(this.rbOutputMethodDirectSound);
this.grpOutputMethod.Location = new System.Drawing.Point(292, 12);
this.grpOutputMethod.Name = "grpOutputMethod";
this.grpOutputMethod.Size = new System.Drawing.Size(100, 90);
this.grpOutputMethod.Size = new System.Drawing.Size(100, 73);
this.grpOutputMethod.TabIndex = 12;
this.grpOutputMethod.TabStop = false;
this.grpOutputMethod.Text = "Output Method";
@ -254,7 +230,7 @@
// rbOutputMethodOpenAL
//
this.rbOutputMethodOpenAL.AutoSize = true;
this.rbOutputMethodOpenAL.Location = new System.Drawing.Point(6, 65);
this.rbOutputMethodOpenAL.Location = new System.Drawing.Point(6, 43);
this.rbOutputMethodOpenAL.Name = "rbOutputMethodOpenAL";
this.rbOutputMethodOpenAL.Size = new System.Drawing.Size(64, 17);
this.rbOutputMethodOpenAL.TabIndex = 2;
@ -266,7 +242,7 @@
// rbOutputMethodXAudio2
//
this.rbOutputMethodXAudio2.AutoSize = true;
this.rbOutputMethodXAudio2.Location = new System.Drawing.Point(6, 42);
this.rbOutputMethodXAudio2.Location = new System.Drawing.Point(6, 20);
this.rbOutputMethodXAudio2.Name = "rbOutputMethodXAudio2";
this.rbOutputMethodXAudio2.Size = new System.Drawing.Size(65, 17);
this.rbOutputMethodXAudio2.TabIndex = 1;
@ -275,18 +251,6 @@
this.rbOutputMethodXAudio2.UseVisualStyleBackColor = true;
this.rbOutputMethodXAudio2.CheckedChanged += new System.EventHandler(this.OutputMethodRadioButtons_CheckedChanged);
//
// rbOutputMethodDirectSound
//
this.rbOutputMethodDirectSound.AutoSize = true;
this.rbOutputMethodDirectSound.Location = new System.Drawing.Point(6, 19);
this.rbOutputMethodDirectSound.Name = "rbOutputMethodDirectSound";
this.rbOutputMethodDirectSound.Size = new System.Drawing.Size(84, 17);
this.rbOutputMethodDirectSound.TabIndex = 0;
this.rbOutputMethodDirectSound.TabStop = true;
this.rbOutputMethodDirectSound.Text = "DirectSound";
this.rbOutputMethodDirectSound.UseVisualStyleBackColor = true;
this.rbOutputMethodDirectSound.CheckedChanged += new System.EventHandler(this.OutputMethodRadioButtons_CheckedChanged);
//
// cbMuteFrameAdvance
//
this.cbMuteFrameAdvance.AutoSize = true;
@ -352,7 +316,6 @@
this.grpOutputMethod.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
@ -370,7 +333,6 @@
private BizHawk.WinForms.Controls.LocLabelEx BufferSizeUnitsLabel;
private System.Windows.Forms.GroupBox grpOutputMethod;
private System.Windows.Forms.RadioButton rbOutputMethodXAudio2;
private System.Windows.Forms.RadioButton rbOutputMethodDirectSound;
private System.Windows.Forms.RadioButton rbOutputMethodOpenAL;
private System.Windows.Forms.NumericUpDown nudRWFF;
private System.Windows.Forms.CheckBox cbEnableRWFF;

View File

@ -34,9 +34,8 @@ namespace BizHawk.Client.EmuHawk
cbEnableRWFF.Checked = _config.SoundEnabledRWFF;
cbMuteFrameAdvance.Checked = _config.MuteFrameAdvance;
rbOutputMethodDirectSound.Enabled = rbOutputMethodXAudio2.Enabled = HostCapabilityDetector.HasDirectX;
rbOutputMethodXAudio2.Enabled = HostCapabilityDetector.HasXAudio2;
rbOutputMethodDirectSound.Checked = _config.SoundOutputMethod == ESoundOutputMethod.DirectSound;
rbOutputMethodXAudio2.Checked = _config.SoundOutputMethod == ESoundOutputMethod.XAudio2;
rbOutputMethodOpenAL.Checked = _config.SoundOutputMethod == ESoundOutputMethod.OpenAL;
BufferSizeNumeric.Value = _config.SoundBufferSizeMs;
@ -53,7 +52,6 @@ namespace BizHawk.Client.EmuHawk
{
if (!OSTailoredCode.IsUnixHost)
{
if (rbOutputMethodDirectSound.Checked) return ESoundOutputMethod.DirectSound;
if (rbOutputMethodXAudio2.Checked) return ESoundOutputMethod.XAudio2;
}
if (rbOutputMethodOpenAL.Checked) return ESoundOutputMethod.OpenAL;
@ -62,11 +60,6 @@ namespace BizHawk.Client.EmuHawk
private void Ok_Click(object sender, EventArgs e)
{
if (rbOutputMethodDirectSound.Checked && (int)BufferSizeNumeric.Value < 60)
{
DialogController.ShowMessageBox("Buffer size must be at least 60 milliseconds for DirectSound.", "Error", EMsgBoxIcon.Error);
return;
}
_config.SoundEnabled = cbEnableMaster.Checked;
_config.SoundEnabledNormal = cbEnableNormal.Checked;
_config.SoundEnabledRWFF = cbEnableRWFF.Checked;