Configurable DirectSound buffer size.

A bunch of changes in Sound / SoundOutputProvider to support this and behave nicely.
This commit is contained in:
jdpurcell 2015-01-25 03:33:45 +00:00
parent a04982bc84
commit 69c66d12b1
6 changed files with 174 additions and 121 deletions

View File

@ -228,6 +228,7 @@ namespace BizHawk.Client.Common
public int SoundVolume = 100; // Range 0-100 public int SoundVolume = 100; // Range 0-100
public bool SoundThrottle = false; public bool SoundThrottle = false;
public string SoundDevice = ""; public string SoundDevice = "";
public int SoundBufferSizeMs = 100;
public bool UseNewOutputBuffer = false; public bool UseNewOutputBuffer = false;
// Log Window // Log Window

View File

@ -2093,6 +2093,13 @@ namespace BizHawk.Client.EmuHawk
Global.Config.DisplayInput ^= true; Global.Config.DisplayInput ^= true;
} }
public static void ToggleSound()
{
Global.Config.SoundEnabled ^= true;
GlobalWin.Sound.StopSound();
GlobalWin.Sound.StartSound();
}
private static void VolumeUp() private static void VolumeUp()
{ {
Global.Config.SoundVolume += 10; Global.Config.SoundVolume += 10;
@ -2101,17 +2108,10 @@ namespace BizHawk.Client.EmuHawk
Global.Config.SoundVolume = 100; Global.Config.SoundVolume = 100;
} }
GlobalWin.Sound.ChangeVolume(Global.Config.SoundVolume); GlobalWin.Sound.ApplyVolumeSettings();
GlobalWin.OSD.AddMessage("Volume " + Global.Config.SoundVolume); GlobalWin.OSD.AddMessage("Volume " + Global.Config.SoundVolume);
} }
public static void ToggleSound()
{
Global.Config.SoundEnabled ^= true;
GlobalWin.Sound.UpdateSoundSettings();
GlobalWin.Sound.StartSound();
}
private static void VolumeDown() private static void VolumeDown()
{ {
Global.Config.SoundVolume -= 10; Global.Config.SoundVolume -= 10;
@ -2120,7 +2120,7 @@ namespace BizHawk.Client.EmuHawk
Global.Config.SoundVolume = 0; Global.Config.SoundVolume = 0;
} }
GlobalWin.Sound.ChangeVolume(Global.Config.SoundVolume); GlobalWin.Sound.ApplyVolumeSettings();
GlobalWin.OSD.AddMessage("Volume " + Global.Config.SoundVolume); GlobalWin.OSD.AddMessage("Volume " + Global.Config.SoundVolume);
} }

View File

@ -43,18 +43,14 @@ namespace BizHawk.Client.EmuHawk
private const int BytesPerSample = 2; private const int BytesPerSample = 2;
private const int ChannelCount = 2; private const int ChannelCount = 2;
private const int BlockAlign = BytesPerSample * ChannelCount; private const int BlockAlign = BytesPerSample * ChannelCount;
private const int BufferSizeMilliseconds = 100; private const int MinBufferFullnessSamples = 55 * SampleRate / 1000;
private const int BufferSizeSamples = SampleRate * BufferSizeMilliseconds / 1000;
private const int BufferSizeBytes = BufferSizeSamples * BlockAlign;
private const double BufferSizeSeconds = (double)(BufferSizeBytes / BlockAlign) / SampleRate;
private const int MinBufferFullnessMilliseconds = 55;
private const int MinBufferFullnessSamples = SampleRate * MinBufferFullnessMilliseconds / 1000;
private bool _muted; private bool _muted;
private bool _disposed; private bool _disposed;
private DirectSound _device;
private SecondarySoundBuffer _deviceBuffer; private SecondarySoundBuffer _deviceBuffer;
private readonly BufferedAsync _semiSync = new BufferedAsync(); private readonly BufferedAsync _semiSync = new BufferedAsync();
private readonly SoundOutputProvider _outputProvider = new SoundOutputProvider(); private SoundOutputProvider _outputProvider;
private ISoundProvider _asyncSoundProvider; private ISoundProvider _asyncSoundProvider;
private ISyncSoundProvider _syncSoundProvider; private ISyncSoundProvider _syncSoundProvider;
private int _actualWriteOffsetBytes = -1; private int _actualWriteOffsetBytes = -1;
@ -67,6 +63,24 @@ namespace BizHawk.Client.EmuHawk
if (device == null) return; if (device == null) return;
device.SetCooperativeLevel(handle, CooperativeLevel.Priority); device.SetCooperativeLevel(handle, CooperativeLevel.Priority);
_device = device;
}
private int BufferSizeMilliseconds { get; set; }
private int BufferSizeSamples
{
get { return SampleRate * BufferSizeMilliseconds / 1000; }
}
private int BufferSizeBytes
{
get { return BufferSizeSamples * BlockAlign; }
}
private void CreateDeviceBuffer()
{
BufferSizeMilliseconds = Global.Config.SoundBufferSizeMs;
var format = new WaveFormat var format = new WaveFormat
{ {
@ -81,25 +95,31 @@ namespace BizHawk.Client.EmuHawk
var desc = new SoundBufferDescription var desc = new SoundBufferDescription
{ {
Format = format, Format = format,
Flags = Flags = BufferFlags.GlobalFocus | BufferFlags.Software | BufferFlags.GetCurrentPosition2 | BufferFlags.ControlVolume,
BufferFlags.GlobalFocus | BufferFlags.Software | BufferFlags.GetCurrentPosition2 | BufferFlags.ControlVolume,
SizeInBytes = BufferSizeBytes SizeInBytes = BufferSizeBytes
}; };
_deviceBuffer = new SecondarySoundBuffer(device, desc); _deviceBuffer = new SecondarySoundBuffer(_device, desc);
}
ChangeVolume(Global.Config.SoundVolume); public void ApplyVolumeSettings()
{
if (_deviceBuffer == null) return;
//LogUnderruns = true; if (Global.Config.SoundVolume == 0)
//_outputProvider.LogDebug = true; _deviceBuffer.Volume = -5000;
else
_deviceBuffer.Volume = 0 - ((100 - Global.Config.SoundVolume) * 45);
} }
public void StartSound() public void StartSound()
{ {
if (_disposed) throw new ObjectDisposedException("Sound"); if (_disposed) throw new ObjectDisposedException("Sound");
if (Global.Config.SoundEnabled == false) return; if (!Global.Config.SoundEnabled) return;
if (_deviceBuffer == null) return; if (_deviceBuffer != null) return;
if (IsPlaying) return;
CreateDeviceBuffer();
ApplyVolumeSettings();
_deviceBuffer.Write(new byte[BufferSizeBytes], 0, LockFlags.EntireBuffer); _deviceBuffer.Write(new byte[BufferSizeBytes], 0, LockFlags.EntireBuffer);
_deviceBuffer.CurrentPlayPosition = 0; _deviceBuffer.CurrentPlayPosition = 0;
@ -109,34 +129,33 @@ namespace BizHawk.Client.EmuHawk
_filledBufferSizeBytes = 0; _filledBufferSizeBytes = 0;
_lastWriteTime = 0; _lastWriteTime = 0;
_lastWriteCursor = 0; _lastWriteCursor = 0;
}
bool IsPlaying _outputProvider = new SoundOutputProvider();
{ _outputProvider.HardCorrectionThresholdSamples = BufferSizeSamples - MinBufferFullnessSamples;
get _outputProvider.BaseSoundProvider = _syncSoundProvider;
{
if (_deviceBuffer == null) return false; //LogUnderruns = true;
if ((_deviceBuffer.Status & BufferStatus.Playing) != 0) return true; //_outputProvider.LogDebug = true;
return false;
}
} }
public void StopSound() public void StopSound()
{ {
if (!IsPlaying) return; if (_deviceBuffer == null) return;
_deviceBuffer.Write(new byte[BufferSizeBytes], 0, LockFlags.EntireBuffer); _deviceBuffer.Write(new byte[BufferSizeBytes], 0, LockFlags.EntireBuffer);
_deviceBuffer.Stop(); _deviceBuffer.Stop();
_deviceBuffer.Dispose();
_deviceBuffer = null;
_outputProvider = null;
BufferSizeMilliseconds = 0;
} }
public void Dispose() public void Dispose()
{ {
if (_disposed) return; if (_disposed) return;
if (_deviceBuffer != null && _deviceBuffer.Disposed == false) StopSound();
{
_deviceBuffer.Dispose();
_deviceBuffer = null;
}
_disposed = true; _disposed = true;
} }
@ -150,7 +169,10 @@ namespace BizHawk.Client.EmuHawk
_semiSync.DiscardSamples(); _semiSync.DiscardSamples();
_semiSync.BaseSoundProvider = null; _semiSync.BaseSoundProvider = null;
_syncSoundProvider = source; _syncSoundProvider = source;
_outputProvider.BaseSoundProvider = source; if (_outputProvider != null)
{
_outputProvider.BaseSoundProvider = source;
}
} }
public void SetAsyncInputPin(ISoundProvider source) public void SetAsyncInputPin(ISoundProvider source)
@ -160,21 +182,29 @@ namespace BizHawk.Client.EmuHawk
_syncSoundProvider.DiscardSamples(); _syncSoundProvider.DiscardSamples();
_syncSoundProvider = null; _syncSoundProvider = null;
} }
_outputProvider.DiscardSamples(); if (_outputProvider != null)
_outputProvider.BaseSoundProvider = null; {
_outputProvider.DiscardSamples();
_outputProvider.BaseSoundProvider = null;
}
_asyncSoundProvider = source; _asyncSoundProvider = source;
_semiSync.BaseSoundProvider = source; _semiSync.BaseSoundProvider = source;
_semiSync.RecalculateMagic(Global.CoreComm.VsyncRate); _semiSync.RecalculateMagic(Global.CoreComm.VsyncRate);
} }
public bool InitializeBufferWithSilence private bool InitializeBufferWithSilence
{ {
get { return Global.Config.SoundThrottle; } get { return true; }
} }
public bool RecoverFromUnderrunsWithSilence private bool RecoverFromUnderrunsWithSilence
{ {
get { return Global.Config.SoundThrottle; } get { return true; }
}
private int SilenceLeaveRoomForFrameCount
{
get { return Global.Config.SoundThrottle ? 1 : 2; } // Why 2? I don't know, but it seems to work well with the clock throttle's behavior.
} }
public bool LogUnderruns { get; set; } public bool LogUnderruns { get; set; }
@ -188,8 +218,9 @@ namespace BizHawk.Client.EmuHawk
if (_actualWriteOffsetBytes != -1) if (_actualWriteOffsetBytes != -1)
{ {
double elapsedSeconds = (currentWriteTime - _lastWriteTime) / (double)Stopwatch.Frequency; double elapsedSeconds = (currentWriteTime - _lastWriteTime) / (double)Stopwatch.Frequency;
double bufferSizeSeconds = (double)BufferSizeSamples / SampleRate;
int cursorDelta = CircularDistance(_lastWriteCursor, writeCursor, BufferSizeBytes); int cursorDelta = CircularDistance(_lastWriteCursor, writeCursor, BufferSizeBytes);
cursorDelta += BufferSizeBytes * (int)Math.Round((elapsedSeconds - (cursorDelta / (double)(SampleRate * BlockAlign))) / BufferSizeSeconds); cursorDelta += BufferSizeBytes * (int)Math.Round((elapsedSeconds - (cursorDelta / (double)(SampleRate * BlockAlign))) / bufferSizeSeconds);
_filledBufferSizeBytes -= cursorDelta; _filledBufferSizeBytes -= cursorDelta;
if (_filledBufferSizeBytes < 0) if (_filledBufferSizeBytes < 0)
{ {
@ -206,9 +237,8 @@ namespace BizHawk.Client.EmuHawk
int samplesNeeded = CircularDistance(_actualWriteOffsetBytes, playCursor, BufferSizeBytes) / BlockAlign; int samplesNeeded = CircularDistance(_actualWriteOffsetBytes, playCursor, BufferSizeBytes) / BlockAlign;
if ((isInitializing && InitializeBufferWithSilence) || (detectedUnderrun && RecoverFromUnderrunsWithSilence)) if ((isInitializing && InitializeBufferWithSilence) || (detectedUnderrun && RecoverFromUnderrunsWithSilence))
{ {
// Fill the buffer with silence but leave enough empty for one frame's audio
int samplesPerFrame = (int)Math.Round(SampleRate / Global.Emulator.CoreComm.VsyncRate); int samplesPerFrame = (int)Math.Round(SampleRate / Global.Emulator.CoreComm.VsyncRate);
int silenceSamples = Math.Max(samplesNeeded - samplesPerFrame, 0); int silenceSamples = Math.Max(samplesNeeded - (SilenceLeaveRoomForFrameCount * samplesPerFrame), 0);
WriteSamples(new short[silenceSamples * 2], silenceSamples); WriteSamples(new short[silenceSamples * 2], silenceSamples);
samplesNeeded -= silenceSamples; samplesNeeded -= silenceSamples;
} }
@ -244,7 +274,7 @@ namespace BizHawk.Client.EmuHawk
public void UpdateSound() public void UpdateSound()
{ {
if (Global.Config.SoundEnabled == false || _disposed) if (!Global.Config.SoundEnabled || _deviceBuffer == null || _disposed)
{ {
if (_asyncSoundProvider != null) _asyncSoundProvider.DiscardSamples(); if (_asyncSoundProvider != null) _asyncSoundProvider.DiscardSamples();
if (_syncSoundProvider != null) _syncSoundProvider.DiscardSamples(); if (_syncSoundProvider != null) _syncSoundProvider.DiscardSamples();
@ -281,7 +311,7 @@ namespace BizHawk.Client.EmuHawk
{ {
samples = new short[samplesNeeded * ChannelCount]; samples = new short[samplesNeeded * ChannelCount];
samplesProvided = _outputProvider.GetSamples(samples, samplesNeeded, samplesNeeded - (BufferSizeSamples - MinBufferFullnessSamples)); samplesProvided = _outputProvider.GetSamples(samples, samplesNeeded);
} }
} }
else if (_asyncSoundProvider != null) else if (_asyncSoundProvider != null)
@ -297,31 +327,6 @@ namespace BizHawk.Client.EmuHawk
WriteSamples(samples, samplesProvided); WriteSamples(samples, samplesProvided);
} }
/// <summary>
/// Range: 0-100
/// </summary>
/// <param name="vol"></param>
public void ChangeVolume(int vol)
{
if (vol > 100)
vol = 100;
if (vol < 0)
vol = 0;
Global.Config.SoundVolume = vol;
UpdateSoundSettings();
}
/// <summary>
/// Uses Global.Config.SoundEnabled, this just notifies the object to read it
/// </summary>
public void UpdateSoundSettings()
{
if (!Global.Config.SoundEnabled || Global.Config.SoundVolume == 0)
_deviceBuffer.Volume = -5000;
else
_deviceBuffer.Volume = 0 - ((100 - Global.Config.SoundVolume) * 45);
}
} }
#else #else
// Dummy implementation for non-Windows platforms for now. // Dummy implementation for non-Windows platforms for now.

View File

@ -14,19 +14,14 @@ namespace BizHawk.Client.EmuHawk
// samples here on average. As long as we're within +/-5 milliseconds we don't need // samples here on average. As long as we're within +/-5 milliseconds we don't need
// to touch the source audio. Once it goes outside of that window, we'll start to // to touch the source audio. Once it goes outside of that window, we'll start to
// perform a "soft" correction by resampling it to hopefully get back inside our // perform a "soft" correction by resampling it to hopefully get back inside our
// window shortly. If it ends up going too low (-45 ms) and depleting the output // window shortly. If it ends up going too low or too high, we will perform a
// device's buffer, or too high (+45 ms), we will perform a "hard" correction by // "hard" correction by generating silence or discarding samples.
// generating silence or discarding samples.
public class SoundOutputProvider public class SoundOutputProvider
{ {
private const int SampleRate = 44100; private const int SampleRate = 44100;
private const int ChannelCount = 2; private const int ChannelCount = 2;
private const int MaxExtraMilliseconds = 45; private const int SoftCorrectionThresholdSamples = 5 * SampleRate / 1000;
private const int MaxExtraSamples = SampleRate * MaxExtraMilliseconds / 1000; private const int StartupHardCorrectionThresholdSamples = 10 * SampleRate / 1000;
private const int MaxTargetOffsetMilliseconds = 5;
private const int MaxTargetOffsetSamples = SampleRate * MaxTargetOffsetMilliseconds / 1000;
private const int HardCorrectionMilliseconds = 20;
private const int HardCorrectionSamples = SampleRate * HardCorrectionMilliseconds / 1000;
private const int UsableHistoryLength = 20; private const int UsableHistoryLength = 20;
private const int MaxHistoryLength = 60; private const int MaxHistoryLength = 60;
private const int SoftCorrectionLength = 240; private const int SoftCorrectionLength = 240;
@ -34,7 +29,7 @@ namespace BizHawk.Client.EmuHawk
private const int BaseSampleRateMaxHistoryLength = 300; private const int BaseSampleRateMaxHistoryLength = 300;
private const int MinResamplingDistanceSamples = 3; private const int MinResamplingDistanceSamples = 3;
private Queue<short> _buffer = new Queue<short>(MaxExtraSamples * ChannelCount); private Queue<short> _buffer = new Queue<short>();
private Queue<int> _extraCountHistory = new Queue<int>(); private Queue<int> _extraCountHistory = new Queue<int>();
private Queue<int> _outputCountHistory = new Queue<int>(); private Queue<int> _outputCountHistory = new Queue<int>();
@ -46,12 +41,14 @@ namespace BizHawk.Client.EmuHawk
private short[] _resampleBuffer = new short[0]; private short[] _resampleBuffer = new short[0];
private double _resampleLengthRoundingError; private double _resampleLengthRoundingError;
public ISyncSoundProvider BaseSoundProvider { get; set; }
public SoundOutputProvider() public SoundOutputProvider()
{ {
} }
public int HardCorrectionThresholdSamples { get; set; }
public ISyncSoundProvider BaseSoundProvider { get; set; }
public void DiscardSamples() public void DiscardSamples()
{ {
_buffer.Clear(); _buffer.Clear();
@ -76,14 +73,14 @@ namespace BizHawk.Client.EmuHawk
get { return SampleRate / Global.Emulator.CoreComm.VsyncRate; } get { return SampleRate / Global.Emulator.CoreComm.VsyncRate; }
} }
public int GetSamples(short[] samples, int idealSampleCount, int minSampleCount) public int GetSamples(short[] samples, int idealSampleCount)
{ {
double scaleFactor = 1.0; double scaleFactor = 1.0;
if (_extraCountHistory.Count >= UsableHistoryLength && !_hardCorrectionHistory.Any(c => c)) if (_extraCountHistory.Count >= UsableHistoryLength && !_hardCorrectionHistory.Any(c => c))
{ {
double offsetFromTarget = _extraCountHistory.Average(); double offsetFromTarget = _extraCountHistory.Average();
if (Math.Abs(offsetFromTarget) > MaxTargetOffsetSamples) if (Math.Abs(offsetFromTarget) > SoftCorrectionThresholdSamples)
{ {
double correctionSpan = _outputCountHistory.Average() * SoftCorrectionLength; double correctionSpan = _outputCountHistory.Average() * SoftCorrectionLength;
scaleFactor *= correctionSpan / (correctionSpan + offsetFromTarget); scaleFactor *= correctionSpan / (correctionSpan + offsetFromTarget);
@ -94,11 +91,13 @@ namespace BizHawk.Client.EmuHawk
int bufferSampleCount = _buffer.Count / ChannelCount; int bufferSampleCount = _buffer.Count / ChannelCount;
int extraSampleCount = bufferSampleCount - idealSampleCount; int extraSampleCount = bufferSampleCount - idealSampleCount;
int hardCorrectionThresholdSamples = _extraCountHistory.Count >= UsableHistoryLength ? HardCorrectionThresholdSamples :
Math.Min(StartupHardCorrectionThresholdSamples, HardCorrectionThresholdSamples);
bool hardCorrected = false; bool hardCorrected = false;
if (bufferSampleCount < minSampleCount) if (extraSampleCount < -hardCorrectionThresholdSamples)
{ {
int generateSampleCount = (minSampleCount - bufferSampleCount) + HardCorrectionSamples; int generateSampleCount = -extraSampleCount;
if (LogDebug) Console.WriteLine("Generating " + generateSampleCount + " samples"); if (LogDebug) Console.WriteLine("Generating " + generateSampleCount + " samples");
for (int i = 0; i < generateSampleCount * ChannelCount; i++) for (int i = 0; i < generateSampleCount * ChannelCount; i++)
{ {
@ -106,9 +105,9 @@ namespace BizHawk.Client.EmuHawk
} }
hardCorrected = true; hardCorrected = true;
} }
else if (extraSampleCount > MaxExtraSamples) else if (extraSampleCount > hardCorrectionThresholdSamples)
{ {
int discardSampleCount = (extraSampleCount - MaxExtraSamples) + HardCorrectionSamples; int discardSampleCount = extraSampleCount;
if (LogDebug) Console.WriteLine("Discarding " + discardSampleCount + " samples"); if (LogDebug) Console.WriteLine("Discarding " + discardSampleCount + " samples");
for (int i = 0; i < discardSampleCount * ChannelCount; i++) for (int i = 0; i < discardSampleCount * ChannelCount; i++)
{ {
@ -236,7 +235,6 @@ namespace BizHawk.Client.EmuHawk
return output; return output;
} }
double roundingError = 0.0;
for (int iOutput = 0; iOutput < outputCount; iOutput++) for (int iOutput = 0; iOutput < outputCount; iOutput++)
{ {
double iInput = ((double)iOutput / (outputCount - 1)) * (inputCount - 1); double iInput = ((double)iOutput / (outputCount - 1)) * (inputCount - 1);
@ -250,17 +248,11 @@ namespace BizHawk.Client.EmuHawk
for (int iChannel = 0; iChannel < ChannelCount; iChannel++) for (int iChannel = 0; iChannel < ChannelCount; iChannel++)
{ {
double valueExact = double value =
input[iInput0 * ChannelCount + iChannel] * input0Weight + input[iInput0 * ChannelCount + iChannel] * input0Weight +
input[iInput1 * ChannelCount + iChannel] * input1Weight + input[iInput1 * ChannelCount + iChannel] * input1Weight;
roundingError;
if (valueExact < -32768.0) valueExact = -32768.0; output[iOutput * ChannelCount + iChannel] = (short)((int)(value + 32768.5) - 32768);
if (valueExact > 32767.0) valueExact = 32767.0;
short value = (short)((int)(valueExact + 32768.5) - 32768);
output[iOutput * ChannelCount + iChannel] = value;
roundingError = valueExact - value;
} }
} }

View File

@ -37,17 +37,21 @@
this.SoundVolNumeric = new System.Windows.Forms.NumericUpDown(); this.SoundVolNumeric = new System.Windows.Forms.NumericUpDown();
this.UseNewOutputBuffer = new System.Windows.Forms.CheckBox(); this.UseNewOutputBuffer = new System.Windows.Forms.CheckBox();
this.listBoxSoundDevices = new System.Windows.Forms.ListBox(); this.listBoxSoundDevices = new System.Windows.Forms.ListBox();
this.label1 = new System.Windows.Forms.Label(); this.SoundDeviceLabel = new System.Windows.Forms.Label();
this.BufferSizeLabel = new System.Windows.Forms.Label();
this.BufferSizeNumeric = new System.Windows.Forms.NumericUpDown();
this.BufferSizeUnitsLabel = new System.Windows.Forms.Label();
this.SoundVolGroup.SuspendLayout(); this.SoundVolGroup.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.SoundVolBar)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.SoundVolBar)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.SoundVolNumeric)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.SoundVolNumeric)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.BufferSizeNumeric)).BeginInit();
this.SuspendLayout(); this.SuspendLayout();
// //
// Cancel // Cancel
// //
this.Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.Cancel.Location = new System.Drawing.Point(317, 209); this.Cancel.Location = new System.Drawing.Point(317, 244);
this.Cancel.Name = "Cancel"; this.Cancel.Name = "Cancel";
this.Cancel.Size = new System.Drawing.Size(75, 23); this.Cancel.Size = new System.Drawing.Size(75, 23);
this.Cancel.TabIndex = 0; this.Cancel.TabIndex = 0;
@ -59,7 +63,7 @@
// //
this.OK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.OK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.OK.DialogResult = System.Windows.Forms.DialogResult.OK; this.OK.DialogResult = System.Windows.Forms.DialogResult.OK;
this.OK.Location = new System.Drawing.Point(236, 209); this.OK.Location = new System.Drawing.Point(236, 244);
this.OK.Name = "OK"; this.OK.Name = "OK";
this.OK.Size = new System.Drawing.Size(75, 23); this.OK.Size = new System.Drawing.Size(75, 23);
this.OK.TabIndex = 1; this.OK.TabIndex = 1;
@ -135,19 +139,62 @@
| System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.listBoxSoundDevices.FormattingEnabled = true; this.listBoxSoundDevices.FormattingEnabled = true;
this.listBoxSoundDevices.Location = new System.Drawing.Point(108, 108); this.listBoxSoundDevices.Location = new System.Drawing.Point(108, 102);
this.listBoxSoundDevices.Name = "listBoxSoundDevices"; this.listBoxSoundDevices.Name = "listBoxSoundDevices";
this.listBoxSoundDevices.Size = new System.Drawing.Size(284, 95); this.listBoxSoundDevices.Size = new System.Drawing.Size(284, 95);
this.listBoxSoundDevices.TabIndex = 6; this.listBoxSoundDevices.TabIndex = 6;
// //
// label1 // SoundDeviceLabel
// //
this.label1.AutoSize = true; this.SoundDeviceLabel.AutoSize = true;
this.label1.Location = new System.Drawing.Point(108, 92); this.SoundDeviceLabel.Location = new System.Drawing.Point(108, 86);
this.label1.Name = "label1"; this.SoundDeviceLabel.Name = "SoundDeviceLabel";
this.label1.Size = new System.Drawing.Size(78, 13); this.SoundDeviceLabel.Size = new System.Drawing.Size(78, 13);
this.label1.TabIndex = 7; this.SoundDeviceLabel.TabIndex = 7;
this.label1.Text = "Sound Device:"; this.SoundDeviceLabel.Text = "Sound Device:";
//
// BufferSizeLabel
//
this.BufferSizeLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.BufferSizeLabel.AutoSize = true;
this.BufferSizeLabel.Location = new System.Drawing.Point(105, 213);
this.BufferSizeLabel.Name = "BufferSizeLabel";
this.BufferSizeLabel.Size = new System.Drawing.Size(61, 13);
this.BufferSizeLabel.TabIndex = 8;
this.BufferSizeLabel.Text = "Buffer Size:";
//
// BufferSizeNumeric
//
this.BufferSizeNumeric.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.BufferSizeNumeric.Location = new System.Drawing.Point(172, 211);
this.BufferSizeNumeric.Maximum = new decimal(new int[] {
250,
0,
0,
0});
this.BufferSizeNumeric.Minimum = new decimal(new int[] {
80,
0,
0,
0});
this.BufferSizeNumeric.Name = "BufferSizeNumeric";
this.BufferSizeNumeric.Size = new System.Drawing.Size(59, 20);
this.BufferSizeNumeric.TabIndex = 9;
this.BufferSizeNumeric.Value = new decimal(new int[] {
100,
0,
0,
0});
//
// BufferSizeUnitsLabel
//
this.BufferSizeUnitsLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.BufferSizeUnitsLabel.AutoSize = true;
this.BufferSizeUnitsLabel.Location = new System.Drawing.Point(237, 213);
this.BufferSizeUnitsLabel.Name = "BufferSizeUnitsLabel";
this.BufferSizeUnitsLabel.Size = new System.Drawing.Size(63, 13);
this.BufferSizeUnitsLabel.TabIndex = 10;
this.BufferSizeUnitsLabel.Text = "milliseconds";
// //
// SoundConfig // SoundConfig
// //
@ -155,8 +202,11 @@
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.Cancel; this.CancelButton = this.Cancel;
this.ClientSize = new System.Drawing.Size(404, 244); this.ClientSize = new System.Drawing.Size(404, 279);
this.Controls.Add(this.label1); this.Controls.Add(this.BufferSizeUnitsLabel);
this.Controls.Add(this.BufferSizeNumeric);
this.Controls.Add(this.BufferSizeLabel);
this.Controls.Add(this.SoundDeviceLabel);
this.Controls.Add(this.listBoxSoundDevices); this.Controls.Add(this.listBoxSoundDevices);
this.Controls.Add(this.UseNewOutputBuffer); this.Controls.Add(this.UseNewOutputBuffer);
this.Controls.Add(this.SoundVolGroup); this.Controls.Add(this.SoundVolGroup);
@ -174,6 +224,7 @@
this.SoundVolGroup.PerformLayout(); this.SoundVolGroup.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.SoundVolBar)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.SoundVolBar)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.SoundVolNumeric)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.SoundVolNumeric)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.BufferSizeNumeric)).EndInit();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();
@ -190,6 +241,9 @@
private System.Windows.Forms.TrackBar SoundVolBar; private System.Windows.Forms.TrackBar SoundVolBar;
private System.Windows.Forms.CheckBox UseNewOutputBuffer; private System.Windows.Forms.CheckBox UseNewOutputBuffer;
private System.Windows.Forms.ListBox listBoxSoundDevices; private System.Windows.Forms.ListBox listBoxSoundDevices;
private System.Windows.Forms.Label label1; private System.Windows.Forms.Label SoundDeviceLabel;
private System.Windows.Forms.Label BufferSizeLabel;
private System.Windows.Forms.NumericUpDown BufferSizeNumeric;
private System.Windows.Forms.Label BufferSizeUnitsLabel;
} }
} }

View File

@ -21,6 +21,7 @@ namespace BizHawk.Client.EmuHawk
SoundOnCheckBox.Checked = Global.Config.SoundEnabled; SoundOnCheckBox.Checked = Global.Config.SoundEnabled;
MuteFrameAdvance.Checked = Global.Config.MuteFrameAdvance; MuteFrameAdvance.Checked = Global.Config.MuteFrameAdvance;
UseNewOutputBuffer.Checked = Global.Config.UseNewOutputBuffer; UseNewOutputBuffer.Checked = Global.Config.UseNewOutputBuffer;
BufferSizeNumeric.Value = Global.Config.SoundBufferSizeMs;
SoundVolBar.Value = Global.Config.SoundVolume; SoundVolBar.Value = Global.Config.SoundVolume;
SoundVolNumeric.Value = Global.Config.SoundVolume; SoundVolNumeric.Value = Global.Config.SoundVolume;
UpdateSoundDialog(); UpdateSoundDialog();
@ -45,10 +46,10 @@ namespace BizHawk.Client.EmuHawk
Global.Config.SoundEnabled = SoundOnCheckBox.Checked; Global.Config.SoundEnabled = SoundOnCheckBox.Checked;
Global.Config.MuteFrameAdvance = MuteFrameAdvance.Checked; Global.Config.MuteFrameAdvance = MuteFrameAdvance.Checked;
Global.Config.UseNewOutputBuffer = UseNewOutputBuffer.Checked; Global.Config.UseNewOutputBuffer = UseNewOutputBuffer.Checked;
Global.Config.SoundBufferSizeMs = (int)BufferSizeNumeric.Value;
Global.Config.SoundVolume = SoundVolBar.Value; Global.Config.SoundVolume = SoundVolBar.Value;
Global.Config.SoundDevice = (string)listBoxSoundDevices.SelectedItem ?? "<default>"; Global.Config.SoundDevice = (string)listBoxSoundDevices.SelectedItem ?? "<default>";
GlobalWin.Sound.ChangeVolume(Global.Config.SoundVolume); GlobalWin.Sound.StopSound();
GlobalWin.Sound.UpdateSoundSettings();
GlobalWin.Sound.StartSound(); GlobalWin.Sound.StartSound();
GlobalWin.OSD.AddMessage("Sound settings saved"); GlobalWin.OSD.AddMessage("Sound settings saved");
Close(); Close();