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:
parent
566107e12e
commit
e3e5ae4934
|
@ -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;
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue