From e3e5ae493472b7f06be1d3b9f79247f0c97dda1f Mon Sep 17 00:00:00 2001 From: jdpurcell Date: Fri, 23 Jan 2015 04:16:25 +0000 Subject: [PATCH] New SoundOutputProvider class which takes the place of BufferedAsync. This should be far less prone to audible glitches and reduces latency. --- BizHawk.Client.Common/config/Config.cs | 1 + .../BizHawk.Client.EmuHawk.csproj | 1 + BizHawk.Client.EmuHawk/MainForm.cs | 6 +- BizHawk.Client.EmuHawk/Sound.cs | 50 ++- BizHawk.Client.EmuHawk/SoundOutputProvider.cs | 241 ++++++++++++++ .../config/SoundConfig.Designer.cs | 294 +++++++++--------- BizHawk.Client.EmuHawk/config/SoundConfig.cs | 14 +- 7 files changed, 439 insertions(+), 168 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/SoundOutputProvider.cs diff --git a/BizHawk.Client.Common/config/Config.cs b/BizHawk.Client.Common/config/Config.cs index ad39a8341b..f41976c0ef 100644 --- a/BizHawk.Client.Common/config/Config.cs +++ b/BizHawk.Client.Common/config/Config.cs @@ -228,6 +228,7 @@ namespace BizHawk.Client.Common public int SoundVolume = 100; // Range 0-100 public bool SoundThrottle = false; public string SoundDevice = ""; + public bool UseNewOutputBuffer = false; // Log Window public bool LogWindowSaveWindowPosition = true; diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 492232d499..e6509610fd 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -616,6 +616,7 @@ RomStatusPicker.cs + diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 074b90b001..da7aed472f 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -1458,15 +1458,15 @@ namespace BizHawk.Client.EmuHawk // note that the avi dumper has already rewired the emulator itself in this case. GlobalWin.Sound.SetAsyncInputPin(_dumpProxy); } - else if (Global.Config.SoundThrottle) + else if (Global.Config.SoundThrottle || Global.Config.UseNewOutputBuffer) { - // for sound throttle, use sync mode + // for sound throttle and new output buffer, use sync mode Global.Emulator.EndAsyncSound(); GlobalWin.Sound.SetSyncInputPin(Global.Emulator.SyncSoundProvider); } else { - // for vsync\clock throttle modes, use async + // for vsync\clock throttle modes through old output buffer, use async GlobalWin.Sound.SetAsyncInputPin( !Global.Emulator.StartAsyncSound() ? new MetaspuAsync(Global.Emulator.SyncSoundProvider, ESynchMethod.ESynchMethod_V) diff --git a/BizHawk.Client.EmuHawk/Sound.cs b/BizHawk.Client.EmuHawk/Sound.cs index c4865a1c09..3a991ae58a 100644 --- a/BizHawk.Client.EmuHawk/Sound.cs +++ b/BizHawk.Client.EmuHawk/Sound.cs @@ -47,11 +47,14 @@ namespace BizHawk.Client.EmuHawk 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 = 60; + private const int MinBufferFullnessSamples = SampleRate * MinBufferFullnessMilliseconds / 1000; private bool _muted; private bool _disposed; private SecondarySoundBuffer _deviceBuffer; private readonly BufferedAsync _semiSync = new BufferedAsync(); + private readonly SoundOutputProvider _outputProvider = new SoundOutputProvider(); private ISoundProvider _asyncSoundProvider; private ISyncSoundProvider _syncSoundProvider; private int _actualWriteOffsetBytes = -1; @@ -86,6 +89,9 @@ namespace BizHawk.Client.EmuHawk _deviceBuffer = new SecondarySoundBuffer(device, desc); ChangeVolume(Global.Config.SoundVolume); + + //LogUnderruns = true; + //_outputProvider.LogDebug = true; } public void StartSound() @@ -98,6 +104,11 @@ namespace BizHawk.Client.EmuHawk _deviceBuffer.Write(new byte[BufferSizeBytes], 0, LockFlags.EntireBuffer); _deviceBuffer.CurrentPlayPosition = 0; _deviceBuffer.Play(0, PlayFlags.Looping); + + _actualWriteOffsetBytes = -1; + _filledBufferSizeBytes = 0; + _lastWriteTime = 0; + _lastWriteCursor = 0; } bool IsPlaying @@ -131,14 +142,26 @@ namespace BizHawk.Client.EmuHawk public void SetSyncInputPin(ISyncSoundProvider source) { - _syncSoundProvider = source; - _asyncSoundProvider = null; + if (_asyncSoundProvider != null) + { + _asyncSoundProvider.DiscardSamples(); + _asyncSoundProvider = null; + } _semiSync.DiscardSamples(); + _semiSync.BaseSoundProvider = null; + _syncSoundProvider = source; + _outputProvider.BaseSoundProvider = source; } public void SetAsyncInputPin(ISoundProvider source) { - _syncSoundProvider = null; + if (_syncSoundProvider != null) + { + _syncSoundProvider.DiscardSamples(); + _syncSoundProvider = null; + } + _outputProvider.DiscardSamples(); + _outputProvider.BaseSoundProvider = null; _asyncSoundProvider = source; _semiSync.BaseSoundProvider = source; _semiSync.RecalculateMagic(Global.CoreComm.VsyncRate); @@ -225,6 +248,7 @@ namespace BizHawk.Client.EmuHawk { if (_asyncSoundProvider != null) _asyncSoundProvider.DiscardSamples(); if (_syncSoundProvider != null) _syncSoundProvider.DiscardSamples(); + if (_outputProvider != null) _outputProvider.DiscardSamples(); return; } @@ -239,15 +263,25 @@ namespace BizHawk.Client.EmuHawk if (_asyncSoundProvider != null) _asyncSoundProvider.DiscardSamples(); if (_syncSoundProvider != null) _syncSoundProvider.DiscardSamples(); + if (_outputProvider != null) _outputProvider.DiscardSamples(); } else if (_syncSoundProvider != null) { - _syncSoundProvider.GetSamples(out samples, out samplesProvided); - - while (samplesNeeded < samplesProvided && !Global.DisableSecondaryThrottling) + if (Global.Config.SoundThrottle) { - Thread.Sleep((samplesProvided - samplesNeeded) / (SampleRate / 1000)); // let audio clock control sleep time - samplesNeeded = CalculateSamplesNeeded(); + _syncSoundProvider.GetSamples(out samples, out samplesProvided); + + while (samplesNeeded < samplesProvided && !Global.DisableSecondaryThrottling) + { + Thread.Sleep((samplesProvided - samplesNeeded) / (SampleRate / 1000)); // let audio clock control sleep time + samplesNeeded = CalculateSamplesNeeded(); + } + } + else + { + samples = new short[samplesNeeded * ChannelCount]; + + samplesProvided = _outputProvider.GetSamples(samples, samplesNeeded, samplesNeeded - (BufferSizeSamples - MinBufferFullnessSamples)); } } else if (_asyncSoundProvider != null) diff --git a/BizHawk.Client.EmuHawk/SoundOutputProvider.cs b/BizHawk.Client.EmuHawk/SoundOutputProvider.cs new file mode 100644 index 0000000000..13602a2922 --- /dev/null +++ b/BizHawk.Client.EmuHawk/SoundOutputProvider.cs @@ -0,0 +1,241 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Emulation.Common; +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + // This is intended to be a buffer between a synchronous sound provider and the + // output device (e.g. DirectSound). The idea is to take advantage of the samples + // buffered up in the output device so that we don't need to keep a bunch buffered + // up here. This will keep the latency at a minimum. The goal is to keep zero extra + // 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 + // perform a "soft" correction by resampling it to hopefully get back inside our + // window shortly. If it ends up going too low (-40 ms) and depleting the output + // device's buffer, or too high (+40 ms), we will perform a "hard" correction by + // generating silence or discarding samples. + public class SoundOutputProvider + { + private const int SampleRate = 44100; + private const int ChannelCount = 2; + private const int MaxExtraMilliseconds = 40; + private const int MaxExtraSamples = SampleRate * MaxExtraMilliseconds / 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 MaxHistoryLength = 60; + private const int SoftCorrectionLength = 240; + + private Queue _buffer = new Queue(MaxExtraSamples * ChannelCount); + + private Queue _extraCountHistory = new Queue(); + private Queue _outputCountHistory = new Queue(); + private Queue _hardCorrectionHistory = new Queue(); + + private short[] _resampleBuffer = new short[0]; + private double _resampleLengthRoundingError; + + public ISyncSoundProvider BaseSoundProvider { get; set; } + + public SoundOutputProvider() + { + } + + public void DiscardSamples() + { + _buffer.Clear(); + _extraCountHistory.Clear(); + _outputCountHistory.Clear(); + _hardCorrectionHistory.Clear(); + _resampleBuffer = new short[0]; + _resampleLengthRoundingError = 0.0; + + if (BaseSoundProvider != null) + { + BaseSoundProvider.DiscardSamples(); + } + } + + public bool LogDebug { get; set; } + + private double SamplesPerFrame + { + get { return SampleRate / Global.Emulator.CoreComm.VsyncRate; } + } + + public int GetSamples(short[] samples, int idealSampleCount, int minSampleCount) + { + double scaleFactor = 1.0; + + if (_extraCountHistory.Count >= UsableHistoryLength && !_hardCorrectionHistory.Any(c => c)) + { + double offsetFromTarget = _extraCountHistory.Average(); + if (Math.Abs(offsetFromTarget) > MaxTargetOffsetSamples) + { + double correctionSpan = _outputCountHistory.Average() * SoftCorrectionLength; + scaleFactor *= correctionSpan / (correctionSpan + offsetFromTarget); + } + } + + GetSamplesFromBase(scaleFactor); + + int bufferSampleCount = _buffer.Count / ChannelCount; + int extraSampleCount = bufferSampleCount - idealSampleCount; + bool hardCorrected = false; + + if (bufferSampleCount < minSampleCount) + { + int generateSampleCount = (minSampleCount - bufferSampleCount) + HardCorrectionSamples; + if (LogDebug) Console.WriteLine("Generating " + generateSampleCount + " samples"); + for (int i = 0; i < generateSampleCount * ChannelCount; i++) + { + _buffer.Enqueue(0); + } + hardCorrected = true; + } + else if (extraSampleCount > MaxExtraSamples) + { + int discardSampleCount = (extraSampleCount - MaxExtraSamples) + HardCorrectionSamples; + if (LogDebug) Console.WriteLine("Discarding " + discardSampleCount + " samples"); + for (int i = 0; i < discardSampleCount * ChannelCount; i++) + { + _buffer.Dequeue(); + } + hardCorrected = true; + } + + bufferSampleCount = _buffer.Count / ChannelCount; + extraSampleCount = bufferSampleCount - idealSampleCount; + + int outputSampleCount = Math.Min(idealSampleCount, bufferSampleCount); + + UpdateHistory(_extraCountHistory, extraSampleCount); + UpdateHistory(_outputCountHistory, outputSampleCount); + UpdateHistory(_hardCorrectionHistory, hardCorrected); + + GetSamplesFromBuffer(samples, outputSampleCount); + + if (LogDebug) + { + Console.WriteLine("Avg: {0:0.0} ms, Min: {1:0.0} ms, Max: {2:0.0} ms, Scale: {3:0.0000}", + _extraCountHistory.Average() * 1000.0 / SampleRate, + _extraCountHistory.Min() * 1000.0 / SampleRate, + _extraCountHistory.Max() * 1000.0 / SampleRate, + scaleFactor); + } + + return outputSampleCount; + } + + private void GetSamplesFromBase(double scaleFactor) + { + short[] samples; + int count; + + BaseSoundProvider.GetSamples(out samples, out count); + + scaleFactor *= SamplesPerFrame / count; + + double newCountTarget = count * scaleFactor; + int newCount = (int)Math.Round(newCountTarget + _resampleLengthRoundingError); + // Do not resample for one-sample differences. With NTSC @ 59.94 FPS, for example, + // there are ~735.7 samples per frame so the source will oscillate between 735 and + // 736 samples. Our calculated number of samples will also oscillate between 735 + // and 736, but likely out of phase. There's no point resampling to make up for + // something that will average out over time, so don't resample for these + // differences. We will, however, keep track of them as part of the rounding error + // in case they end up not averaging out as expected. + if (Math.Abs(newCount - count) > 1) + { + samples = Resample(samples, count, newCount); + count = newCount; + } + // Although the rounding error may seem insignificant, it definitely matters over + // time so we need to keep track of it. With NTSC @ 59.94 FPS, for example, if we + // were to always round to 736 samples per frame ignoring the rounding error, we + // would drift by ~22 milliseconds per minute. + _resampleLengthRoundingError += newCountTarget - count; + + AddSamplesToBuffer(samples, count); + } + + private void UpdateHistory(Queue queue, T value) + { + queue.Enqueue(value); + while (queue.Count > MaxHistoryLength) + { + queue.Dequeue(); + } + } + + private void GetSamplesFromBuffer(short[] samples, int count) + { + for (int i = 0; i < count * ChannelCount; i++) + { + samples[i] = _buffer.Dequeue(); + } + } + + private void AddSamplesToBuffer(short[] samples, int count) + { + for (int i = 0; i < count * ChannelCount; i++) + { + _buffer.Enqueue(samples[i]); + } + } + + private short[] GetResampleBuffer(int count) + { + if (_resampleBuffer.Length < count * ChannelCount) + { + _resampleBuffer = new short[count * ChannelCount]; + } + return _resampleBuffer; + } + + // This uses simple linear interpolation which is supposedly not a great idea for + // resampling audio, but it sounds surprisingly good to me. Maybe it works well + // because we are typically stretching by very small amounts. + private short[] Resample(short[] input, int inputCount, int outputCount) + { + if (inputCount == outputCount) + { + return input; + } + + short[] output = GetResampleBuffer(outputCount); + + if (inputCount == 0 || outputCount == 0) + { + Array.Clear(output, 0, outputCount * ChannelCount); + return output; + } + + for (int iOutput = 0; iOutput < outputCount; iOutput++) + { + double iInput = ((double)iOutput / (outputCount - 1)) * (inputCount - 1); + int iInput0 = (int)iInput; + int iInput1 = iInput0 + 1; + double input0Weight = iInput1 - iInput; + double input1Weight = iInput - iInput0; + + if (iInput1 == inputCount) + iInput1 = inputCount - 1; + + for (int iChannel = 0; iChannel < ChannelCount; iChannel++) + { + output[iOutput * ChannelCount + iChannel] = (short) + (input[iInput0 * ChannelCount + iChannel] * input0Weight + + input[iInput1 * ChannelCount + iChannel] * input1Weight); + } + } + + return output; + } + } +} diff --git a/BizHawk.Client.EmuHawk/config/SoundConfig.Designer.cs b/BizHawk.Client.EmuHawk/config/SoundConfig.Designer.cs index 9de445ed40..5c21b91162 100644 --- a/BizHawk.Client.EmuHawk/config/SoundConfig.Designer.cs +++ b/BizHawk.Client.EmuHawk/config/SoundConfig.Designer.cs @@ -28,154 +28,154 @@ /// private void InitializeComponent() { - this.Cancel = new System.Windows.Forms.Button(); - this.OK = new System.Windows.Forms.Button(); - this.SoundOnCheckBox = new System.Windows.Forms.CheckBox(); - this.MuteFrameAdvance = new System.Windows.Forms.CheckBox(); - this.SoundVolGroup = new System.Windows.Forms.GroupBox(); - this.SoundVolBar = new System.Windows.Forms.TrackBar(); - this.SoundVolNumeric = new System.Windows.Forms.NumericUpDown(); - this.ThrottlecheckBox = new System.Windows.Forms.CheckBox(); - this.listBoxSoundDevices = new System.Windows.Forms.ListBox(); - this.label1 = new System.Windows.Forms.Label(); - this.SoundVolGroup.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.SoundVolBar)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.SoundVolNumeric)).BeginInit(); - this.SuspendLayout(); - // - // Cancel - // - 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.Location = new System.Drawing.Point(317, 209); - this.Cancel.Name = "Cancel"; - this.Cancel.Size = new System.Drawing.Size(75, 23); - this.Cancel.TabIndex = 0; - this.Cancel.Text = "&Cancel"; - this.Cancel.UseVisualStyleBackColor = true; - this.Cancel.Click += new System.EventHandler(this.Cancel_Click); - // - // OK - // - 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.Location = new System.Drawing.Point(236, 209); - this.OK.Name = "OK"; - this.OK.Size = new System.Drawing.Size(75, 23); - this.OK.TabIndex = 1; - this.OK.Text = "&Ok"; - this.OK.UseVisualStyleBackColor = true; - this.OK.Click += new System.EventHandler(this.OK_Click); - // - // SoundOnCheckBox - // - this.SoundOnCheckBox.AutoSize = true; - this.SoundOnCheckBox.Location = new System.Drawing.Point(147, 12); - this.SoundOnCheckBox.Name = "SoundOnCheckBox"; - this.SoundOnCheckBox.Size = new System.Drawing.Size(74, 17); - this.SoundOnCheckBox.TabIndex = 2; - this.SoundOnCheckBox.Text = "Sound On"; - this.SoundOnCheckBox.UseVisualStyleBackColor = true; - this.SoundOnCheckBox.CheckedChanged += new System.EventHandler(this.SoundOnCheckBox_CheckedChanged); - // - // MuteFrameAdvance - // - this.MuteFrameAdvance.AutoSize = true; - this.MuteFrameAdvance.Location = new System.Drawing.Point(147, 35); - this.MuteFrameAdvance.Name = "MuteFrameAdvance"; - this.MuteFrameAdvance.Size = new System.Drawing.Size(128, 17); - this.MuteFrameAdvance.TabIndex = 3; - this.MuteFrameAdvance.Text = "Mute Frame Advance"; - this.MuteFrameAdvance.UseVisualStyleBackColor = true; - // - // SoundVolGroup - // - this.SoundVolGroup.Controls.Add(this.SoundVolBar); - this.SoundVolGroup.Controls.Add(this.SoundVolNumeric); - this.SoundVolGroup.Location = new System.Drawing.Point(12, 12); - this.SoundVolGroup.Name = "SoundVolGroup"; - this.SoundVolGroup.Size = new System.Drawing.Size(90, 219); - this.SoundVolGroup.TabIndex = 4; - this.SoundVolGroup.TabStop = false; - this.SoundVolGroup.Text = "Volume"; - // - // SoundVolBar - // - this.SoundVolBar.LargeChange = 10; - this.SoundVolBar.Location = new System.Drawing.Point(23, 23); - this.SoundVolBar.Maximum = 100; - this.SoundVolBar.Name = "SoundVolBar"; - this.SoundVolBar.Orientation = System.Windows.Forms.Orientation.Vertical; - this.SoundVolBar.Size = new System.Drawing.Size(45, 164); - this.SoundVolBar.TabIndex = 1; - this.SoundVolBar.TickFrequency = 10; - this.SoundVolBar.Scroll += new System.EventHandler(this.trackBar1_Scroll); - // - // SoundVolNumeric - // - this.SoundVolNumeric.Location = new System.Drawing.Point(16, 190); - this.SoundVolNumeric.Name = "SoundVolNumeric"; - this.SoundVolNumeric.Size = new System.Drawing.Size(59, 20); - this.SoundVolNumeric.TabIndex = 0; - this.SoundVolNumeric.ValueChanged += new System.EventHandler(this.SoundVolNumeric_ValueChanged); - // - // ThrottlecheckBox - // - this.ThrottlecheckBox.AutoSize = true; - this.ThrottlecheckBox.Location = new System.Drawing.Point(147, 58); - this.ThrottlecheckBox.Name = "ThrottlecheckBox"; - this.ThrottlecheckBox.Size = new System.Drawing.Size(96, 17); - this.ThrottlecheckBox.TabIndex = 5; - this.ThrottlecheckBox.Text = "Sound Throttle"; - this.ThrottlecheckBox.UseVisualStyleBackColor = true; - // - // listBoxSoundDevices - // - this.listBoxSoundDevices.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.Cancel = new System.Windows.Forms.Button(); + this.OK = new System.Windows.Forms.Button(); + this.SoundOnCheckBox = new System.Windows.Forms.CheckBox(); + this.MuteFrameAdvance = new System.Windows.Forms.CheckBox(); + this.SoundVolGroup = new System.Windows.Forms.GroupBox(); + this.SoundVolBar = new System.Windows.Forms.TrackBar(); + this.SoundVolNumeric = new System.Windows.Forms.NumericUpDown(); + this.UseNewOutputBuffer = new System.Windows.Forms.CheckBox(); + this.listBoxSoundDevices = new System.Windows.Forms.ListBox(); + this.label1 = new System.Windows.Forms.Label(); + this.SoundVolGroup.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.SoundVolBar)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.SoundVolNumeric)).BeginInit(); + this.SuspendLayout(); + // + // Cancel + // + 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.Location = new System.Drawing.Point(317, 209); + this.Cancel.Name = "Cancel"; + this.Cancel.Size = new System.Drawing.Size(75, 23); + this.Cancel.TabIndex = 0; + this.Cancel.Text = "&Cancel"; + this.Cancel.UseVisualStyleBackColor = true; + this.Cancel.Click += new System.EventHandler(this.Cancel_Click); + // + // OK + // + 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.Location = new System.Drawing.Point(236, 209); + this.OK.Name = "OK"; + this.OK.Size = new System.Drawing.Size(75, 23); + this.OK.TabIndex = 1; + this.OK.Text = "&Ok"; + this.OK.UseVisualStyleBackColor = true; + this.OK.Click += new System.EventHandler(this.OK_Click); + // + // SoundOnCheckBox + // + this.SoundOnCheckBox.AutoSize = true; + this.SoundOnCheckBox.Location = new System.Drawing.Point(147, 12); + this.SoundOnCheckBox.Name = "SoundOnCheckBox"; + this.SoundOnCheckBox.Size = new System.Drawing.Size(74, 17); + this.SoundOnCheckBox.TabIndex = 2; + this.SoundOnCheckBox.Text = "Sound On"; + this.SoundOnCheckBox.UseVisualStyleBackColor = true; + this.SoundOnCheckBox.CheckedChanged += new System.EventHandler(this.SoundOnCheckBox_CheckedChanged); + // + // MuteFrameAdvance + // + this.MuteFrameAdvance.AutoSize = true; + this.MuteFrameAdvance.Location = new System.Drawing.Point(147, 35); + this.MuteFrameAdvance.Name = "MuteFrameAdvance"; + this.MuteFrameAdvance.Size = new System.Drawing.Size(128, 17); + this.MuteFrameAdvance.TabIndex = 3; + this.MuteFrameAdvance.Text = "Mute Frame Advance"; + this.MuteFrameAdvance.UseVisualStyleBackColor = true; + // + // SoundVolGroup + // + this.SoundVolGroup.Controls.Add(this.SoundVolBar); + this.SoundVolGroup.Controls.Add(this.SoundVolNumeric); + this.SoundVolGroup.Location = new System.Drawing.Point(12, 12); + this.SoundVolGroup.Name = "SoundVolGroup"; + this.SoundVolGroup.Size = new System.Drawing.Size(90, 219); + this.SoundVolGroup.TabIndex = 4; + this.SoundVolGroup.TabStop = false; + this.SoundVolGroup.Text = "Volume"; + // + // SoundVolBar + // + this.SoundVolBar.LargeChange = 10; + this.SoundVolBar.Location = new System.Drawing.Point(23, 23); + this.SoundVolBar.Maximum = 100; + this.SoundVolBar.Name = "SoundVolBar"; + this.SoundVolBar.Orientation = System.Windows.Forms.Orientation.Vertical; + this.SoundVolBar.Size = new System.Drawing.Size(45, 164); + this.SoundVolBar.TabIndex = 1; + this.SoundVolBar.TickFrequency = 10; + this.SoundVolBar.Scroll += new System.EventHandler(this.trackBar1_Scroll); + // + // SoundVolNumeric + // + this.SoundVolNumeric.Location = new System.Drawing.Point(16, 190); + this.SoundVolNumeric.Name = "SoundVolNumeric"; + this.SoundVolNumeric.Size = new System.Drawing.Size(59, 20); + this.SoundVolNumeric.TabIndex = 0; + this.SoundVolNumeric.ValueChanged += new System.EventHandler(this.SoundVolNumeric_ValueChanged); + // + // UseNewOutputBuffer + // + this.UseNewOutputBuffer.AutoSize = true; + this.UseNewOutputBuffer.Location = new System.Drawing.Point(147, 58); + this.UseNewOutputBuffer.Name = "UseNewOutputBuffer"; + this.UseNewOutputBuffer.Size = new System.Drawing.Size(205, 17); + this.UseNewOutputBuffer.TabIndex = 5; + this.UseNewOutputBuffer.Text = "Use New Output Buffer (Experimental)"; + this.UseNewOutputBuffer.UseVisualStyleBackColor = true; + // + // 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.FormattingEnabled = true; - this.listBoxSoundDevices.Location = new System.Drawing.Point(108, 108); - this.listBoxSoundDevices.Name = "listBoxSoundDevices"; - this.listBoxSoundDevices.Size = new System.Drawing.Size(284, 95); - this.listBoxSoundDevices.TabIndex = 6; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(108, 92); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(78, 13); - this.label1.TabIndex = 7; - this.label1.Text = "Sound Device:"; - // - // SoundConfig - // - this.AcceptButton = this.OK; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.CancelButton = this.Cancel; - this.ClientSize = new System.Drawing.Size(404, 244); - this.Controls.Add(this.label1); - this.Controls.Add(this.listBoxSoundDevices); - this.Controls.Add(this.ThrottlecheckBox); - this.Controls.Add(this.SoundVolGroup); - this.Controls.Add(this.MuteFrameAdvance); - this.Controls.Add(this.SoundOnCheckBox); - this.Controls.Add(this.OK); - this.Controls.Add(this.Cancel); - this.MinimumSize = new System.Drawing.Size(279, 259); - this.Name = "SoundConfig"; - this.ShowIcon = false; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Sound Configuration"; - this.Load += new System.EventHandler(this.SoundConfig_Load); - this.SoundVolGroup.ResumeLayout(false); - this.SoundVolGroup.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.SoundVolBar)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.SoundVolNumeric)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); + this.listBoxSoundDevices.FormattingEnabled = true; + this.listBoxSoundDevices.Location = new System.Drawing.Point(108, 108); + this.listBoxSoundDevices.Name = "listBoxSoundDevices"; + this.listBoxSoundDevices.Size = new System.Drawing.Size(284, 95); + this.listBoxSoundDevices.TabIndex = 6; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(108, 92); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(78, 13); + this.label1.TabIndex = 7; + this.label1.Text = "Sound Device:"; + // + // SoundConfig + // + this.AcceptButton = this.OK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.Cancel; + this.ClientSize = new System.Drawing.Size(404, 244); + this.Controls.Add(this.label1); + this.Controls.Add(this.listBoxSoundDevices); + this.Controls.Add(this.UseNewOutputBuffer); + this.Controls.Add(this.SoundVolGroup); + this.Controls.Add(this.MuteFrameAdvance); + this.Controls.Add(this.SoundOnCheckBox); + this.Controls.Add(this.OK); + this.Controls.Add(this.Cancel); + this.MinimumSize = new System.Drawing.Size(279, 259); + this.Name = "SoundConfig"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Sound Configuration"; + this.Load += new System.EventHandler(this.SoundConfig_Load); + this.SoundVolGroup.ResumeLayout(false); + this.SoundVolGroup.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.SoundVolBar)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.SoundVolNumeric)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); } @@ -188,7 +188,7 @@ private System.Windows.Forms.GroupBox SoundVolGroup; private System.Windows.Forms.NumericUpDown SoundVolNumeric; private System.Windows.Forms.TrackBar SoundVolBar; - private System.Windows.Forms.CheckBox ThrottlecheckBox; + private System.Windows.Forms.CheckBox UseNewOutputBuffer; private System.Windows.Forms.ListBox listBoxSoundDevices; private System.Windows.Forms.Label label1; } diff --git a/BizHawk.Client.EmuHawk/config/SoundConfig.cs b/BizHawk.Client.EmuHawk/config/SoundConfig.cs index 6eeede2202..c2280e6476 100644 --- a/BizHawk.Client.EmuHawk/config/SoundConfig.cs +++ b/BizHawk.Client.EmuHawk/config/SoundConfig.cs @@ -20,14 +20,11 @@ namespace BizHawk.Client.EmuHawk SoundOnCheckBox.Checked = Global.Config.SoundEnabled; MuteFrameAdvance.Checked = Global.Config.MuteFrameAdvance; - ThrottlecheckBox.Checked = Global.Config.SoundThrottle; + UseNewOutputBuffer.Checked = Global.Config.UseNewOutputBuffer; SoundVolBar.Value = Global.Config.SoundVolume; SoundVolNumeric.Value = Global.Config.SoundVolume; UpdateSoundDialog(); - // vestigal - ThrottlecheckBox.Visible = false; - var dd = SoundEnumeration.DeviceNames(); listBoxSoundDevices.Items.Add(""); listBoxSoundDevices.SelectedIndex = 0; @@ -47,8 +44,8 @@ namespace BizHawk.Client.EmuHawk { Global.Config.SoundEnabled = SoundOnCheckBox.Checked; Global.Config.MuteFrameAdvance = MuteFrameAdvance.Checked; + Global.Config.UseNewOutputBuffer = UseNewOutputBuffer.Checked; Global.Config.SoundVolume = SoundVolBar.Value; - Global.Config.SoundThrottle = ThrottlecheckBox.Checked; Global.Config.SoundDevice = (string)listBoxSoundDevices.SelectedItem ?? ""; GlobalWin.Sound.ChangeVolume(Global.Config.SoundVolume); GlobalWin.Sound.UpdateSoundSettings(); @@ -81,13 +78,10 @@ namespace BizHawk.Client.EmuHawk { UpdateSoundDialog(); } + private void UpdateSoundDialog() { - //Ocean Prince commented this out - //SoundVolGroup.Enabled = - MuteFrameAdvance.Enabled = - ThrottlecheckBox.Enabled = - SoundOnCheckBox.Checked; + MuteFrameAdvance.Enabled = SoundOnCheckBox.Checked; } } }