SoundOutputProvider: Standalone mode to eliminate the need for an external buffer when used with SyncToAsyncProvider.
This commit is contained in:
parent
a7f5bafb72
commit
c58d2929f8
|
@ -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();
|
||||
|
|
|
@ -32,6 +32,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
private const int MinResamplingDistanceSamples = 3;
|
||||
|
||||
private Queue<short> _buffer = new Queue<short>();
|
||||
private bool _standaloneMode;
|
||||
private int _targetExtraSamples;
|
||||
private int _maxSamplesDeficit;
|
||||
|
||||
private Queue<int> _extraCountHistory = new Queue<int>();
|
||||
private Queue<int> _outputCountHistory = new Queue<int>();
|
||||
|
@ -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)
|
||||
|
|
|
@ -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<short> _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<short>((_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue