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:
parent
706d7c43e6
commit
9a60f84ff6
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
{
|
||||
public enum ESoundOutputMethod
|
||||
{
|
||||
DirectSound, XAudio2, OpenAL, Dummy
|
||||
LegacyDirectSound, // kept here to handle old configs
|
||||
XAudio2,
|
||||
OpenAL,
|
||||
Dummy
|
||||
}
|
||||
|
||||
public enum EDispManagerAR
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -110,7 +110,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
RefreshAspectRatioOptions();
|
||||
|
||||
if (!HostCapabilityDetector.HasDirectX)
|
||||
if (!HostCapabilityDetector.HasD3D9)
|
||||
{
|
||||
rbD3D9.Enabled = false;
|
||||
rbD3D9.AutoCheck = false;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue