New SoundOutputProvider class which takes the place of BufferedAsync. This should be far less prone to audible glitches and reduces latency.

This commit is contained in:
jdpurcell 2015-01-23 04:16:25 +00:00
parent 566107e12e
commit e3e5ae4934
7 changed files with 439 additions and 168 deletions

View File

@ -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;

View File

@ -616,6 +616,7 @@
<Compile Include="RomStatusPicker.Designer.cs">
<DependentUpon>RomStatusPicker.cs</DependentUpon>
</Compile>
<Compile Include="SoundOutputProvider.cs" />
<Compile Include="Throttle.cs" />
<Compile Include="ToolAttributes.cs" />
<Compile Include="tools\BatchRun.cs">

View File

@ -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)

View File

@ -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)

View File

@ -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<short> _buffer = new Queue<short>(MaxExtraSamples * ChannelCount);
private Queue<int> _extraCountHistory = new Queue<int>();
private Queue<int> _outputCountHistory = new Queue<int>();
private Queue<bool> _hardCorrectionHistory = new Queue<bool>();
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<T>(Queue<T> 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;
}
}
}

View File

@ -28,154 +28,154 @@
/// </summary>
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;
}

View File

@ -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("<default>");
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 ?? "<default>";
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;
}
}
}