diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index c4a5782ada..53eabe7fea 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -731,6 +731,7 @@ + diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 680e9ca2ea..3ce98c973e 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -3142,8 +3142,9 @@ namespace BizHawk.Client.EmuHawk else { _currentSoundProvider.SetSyncMode(SyncSoundMode.Sync); - _aviSoundInputAsync = new MetaspuAsync(_currentSoundProvider, ESynchMethod.ESynchMethod_V); - } + double msPerFrame = 1000.0 * Emulator.CoreComm.VsyncDen / Emulator.CoreComm.VsyncNum; + _aviSoundInputAsync = new SyncToAsyncProvider(_currentSoundProvider, msPerFrame + 10.0); + } } _dumpProxy = new SimpleSyncSoundProvider(); RewireSound(); diff --git a/BizHawk.Client.EmuHawk/Sound/Utilities/SyncToAsyncProvider.cs b/BizHawk.Client.EmuHawk/Sound/Utilities/SyncToAsyncProvider.cs new file mode 100644 index 0000000000..1309b0a435 --- /dev/null +++ b/BizHawk.Client.EmuHawk/Sound/Utilities/SyncToAsyncProvider.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; + +using BizHawk.Emulation.Common; + +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(); + private readonly int _bufferSizeSamples; + private readonly Queue _buffer; + + public SyncToAsyncProvider(ISoundProvider baseProvider, double bufferSizeMs) + { + _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 + { + get { return true; } + } + + public SyncSoundMode SyncMode + { + get { return SyncSoundMode.Async; } + } + + public void SetSyncMode(SyncSoundMode mode) + { + if (mode != SyncSoundMode.Async) + { + throw new NotSupportedException("Sync mode is not supported."); + } + } + + public void GetSamplesSync(out short[] samples, out int nsamp) + { + throw new InvalidOperationException("Sync mode is not supported."); + } + + private void GetSamplesFromBase(int minResultingSampleCount) + { + 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]); + } + } + } +}