diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 13fe805389..e5cc678bb9 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -3142,7 +3142,7 @@ namespace BizHawk.Client.EmuHawk else { _currentSoundProvider.SetSyncMode(SyncSoundMode.Sync); - _aviSoundInputAsync = new SyncToAsyncProvider(_currentSoundProvider, 10.0); + _aviSoundInputAsync = new SyncToAsyncProvider(_currentSoundProvider); } } _dumpProxy = new SimpleSyncSoundProvider(); diff --git a/BizHawk.Client.EmuHawk/Sound/Utilities/SoundOutputProvider.cs b/BizHawk.Client.EmuHawk/Sound/Utilities/SoundOutputProvider.cs index 33ef5471a7..76995020e0 100644 --- a/BizHawk.Client.EmuHawk/Sound/Utilities/SoundOutputProvider.cs +++ b/BizHawk.Client.EmuHawk/Sound/Utilities/SoundOutputProvider.cs @@ -32,6 +32,9 @@ namespace BizHawk.Client.EmuHawk private const int MinResamplingDistanceSamples = 3; private Queue _buffer = new Queue(); + private bool _standaloneMode; + private int _targetExtraSamples; + private int _maxSamplesDeficit; private Queue _extraCountHistory = new Queue(); private Queue _outputCountHistory = new Queue(); @@ -48,17 +51,37 @@ namespace BizHawk.Client.EmuHawk private short[] _resampleBuffer = new short[0]; private double _resampleLengthRoundingError; - public SoundOutputProvider() + public SoundOutputProvider(bool standaloneMode = false) { + _standaloneMode = standaloneMode; + if (_standaloneMode) + { + const double targetExtraMs = 10.0; + _targetExtraSamples = (int)Math.Ceiling(targetExtraMs * SampleRate / 1000.0); + } + ResetBuffer(); } - public int MaxSamplesDeficit { get; set; } + public int MaxSamplesDeficit + { + get { return _maxSamplesDeficit; } + set + { + if (_standaloneMode) throw new InvalidOperationException(); + _maxSamplesDeficit = value; + } + } + + private int EffectiveMaxSamplesDeficit + { + get { return _maxSamplesDeficit + _targetExtraSamples; } + } public ISoundProvider BaseSoundProvider { get; set; } public void DiscardSamples() { - _buffer.Clear(); + ResetBuffer(); _extraCountHistory.Clear(); _outputCountHistory.Clear(); _hardCorrectionHistory.Clear(); @@ -76,6 +99,15 @@ namespace BizHawk.Client.EmuHawk } } + private void ResetBuffer() + { + _buffer.Clear(); + for (int i = 0; i < _targetExtraSamples * ChannelCount; i++) + { + _buffer.Enqueue(0); + } + } + // To let us know about buffer underruns, rewinding, fast-forwarding, etc. public void OnVolatility() { @@ -91,7 +123,23 @@ namespace BizHawk.Client.EmuHawk get { return SampleRate / Global.Emulator.CoreComm.VsyncRate; } } + public void GetSamples(short[] samples) + { + if (!_standaloneMode) throw new InvalidOperationException(); + int returnSampleCount = samples.Length / ChannelCount; + GetSamples(returnSampleCount); + GetSamplesFromBuffer(samples, returnSampleCount); + } + public void GetSamples(int idealSampleCount, out short[] samples, out int sampleCount) + { + if (_standaloneMode) throw new InvalidOperationException(); + sampleCount = GetSamples(idealSampleCount); + samples = GetOutputBuffer(sampleCount); + GetSamplesFromBuffer(samples, sampleCount); + } + + private int GetSamples(int idealSampleCount) { double scaleFactor = 1.0; @@ -108,9 +156,9 @@ namespace BizHawk.Client.EmuHawk GetSamplesFromBase(ref scaleFactor); int bufferSampleCount = _buffer.Count / ChannelCount; - int extraSampleCount = bufferSampleCount - idealSampleCount; + int extraSampleCount = bufferSampleCount - _targetExtraSamples - idealSampleCount; int maxSamplesDeficit = _extraCountHistory.Count >= UsableHistoryLength ? - MaxSamplesDeficit : Math.Min(StartupMaxSamplesSurplusDeficit, MaxSamplesDeficit); + EffectiveMaxSamplesDeficit : Math.Min(StartupMaxSamplesSurplusDeficit, EffectiveMaxSamplesDeficit); int maxSamplesSurplus = _extraCountHistory.Count >= UsableHistoryLength ? MaxSamplesSurplus : Math.Min(StartupMaxSamplesSurplusDeficit, MaxSamplesSurplus); bool hardCorrected = false; @@ -137,7 +185,7 @@ namespace BizHawk.Client.EmuHawk } bufferSampleCount = _buffer.Count / ChannelCount; - extraSampleCount = bufferSampleCount - idealSampleCount; + extraSampleCount = bufferSampleCount - _targetExtraSamples - idealSampleCount; int outputSampleCount = Math.Min(idealSampleCount, bufferSampleCount); @@ -154,9 +202,7 @@ namespace BizHawk.Client.EmuHawk scaleFactor); } - sampleCount = outputSampleCount; - samples = GetOutputBuffer(sampleCount); - GetSamplesFromBuffer(samples, sampleCount); + return outputSampleCount; } private void GetSamplesFromBase(ref double scaleFactor) diff --git a/BizHawk.Client.EmuHawk/Sound/Utilities/SyncToAsyncProvider.cs b/BizHawk.Client.EmuHawk/Sound/Utilities/SyncToAsyncProvider.cs index 1309b0a435..a09c812c7f 100644 --- a/BizHawk.Client.EmuHawk/Sound/Utilities/SyncToAsyncProvider.cs +++ b/BizHawk.Client.EmuHawk/Sound/Utilities/SyncToAsyncProvider.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using BizHawk.Emulation.Common; @@ -7,41 +6,16 @@ namespace BizHawk.Client.EmuHawk { public class SyncToAsyncProvider : ISoundProvider { - private const int SampleRate = 44100; - private const int ChannelCount = 2; - private const double MinExpectedFrameRate = 50; + private readonly SoundOutputProvider _outputProvider = new SoundOutputProvider(standaloneMode: true); - private readonly SoundOutputProvider _outputProvider = new SoundOutputProvider(); - private readonly int _bufferSizeSamples; - private readonly Queue _buffer; - - public SyncToAsyncProvider(ISoundProvider baseProvider, double bufferSizeMs) + public SyncToAsyncProvider(ISoundProvider baseProvider) { _outputProvider.BaseSoundProvider = baseProvider; - _bufferSizeSamples = (int)Math.Ceiling(bufferSizeMs * SampleRate / 1000.0); - _buffer = new Queue((_bufferSizeSamples + (int)Math.Ceiling(SampleRate / MinExpectedFrameRate)) * ChannelCount); - - DiscardSamples(); } public void DiscardSamples() { - _buffer.Clear(); _outputProvider.DiscardSamples(); - - for (int i = 0; i < _bufferSizeSamples * ChannelCount; i++) - { - _buffer.Enqueue(0); - } - } - - public void GetSamplesAsync(short[] samples) - { - GetSamplesFromBase(samples.Length / ChannelCount); - for (int i = 0; i < samples.Length; i++) - { - samples[i] = _buffer.Dequeue(); - } } public bool CanProvideAsync @@ -67,17 +41,9 @@ namespace BizHawk.Client.EmuHawk throw new InvalidOperationException("Sync mode is not supported."); } - private void GetSamplesFromBase(int minResultingSampleCount) + public void GetSamplesAsync(short[] samples) { - int idealSampleCount = Math.Max(_bufferSizeSamples + minResultingSampleCount - (_buffer.Count / ChannelCount), 0); - short[] samples; - int samplesProvided; - _outputProvider.MaxSamplesDeficit = _bufferSizeSamples; - _outputProvider.GetSamples(idealSampleCount, out samples, out samplesProvided); - for (int i = 0; i < samplesProvided * ChannelCount; i++) - { - _buffer.Enqueue(samples[i]); - } + _outputProvider.GetSamples(samples); } } }