Sound cleanup.

This commit is contained in:
J.D. Purcell 2016-12-14 23:26:01 -05:00
parent a33a8252ff
commit d95edc273e
7 changed files with 56 additions and 45 deletions

View File

@ -717,6 +717,7 @@
<Compile Include="RomStatusPicker.Designer.cs">
<DependentUpon>RomStatusPicker.cs</DependentUpon>
</Compile>
<Compile Include="Sound\Interfaces\ISoundOutput.cs" />
<Compile Include="Sound\Output\DirectSoundSoundOutput.cs" />
<Compile Include="Sound\Output\DummySoundOutput.cs" />
<Compile Include="Sound\Output\OpenALSoundOutput.cs" />

View File

@ -0,0 +1,14 @@
using System;
namespace BizHawk.Client.EmuHawk
{
public interface ISoundOutput : IDisposable
{
void StartSound();
void StopSound();
void ApplyVolumeSettings(double volume);
int MaxSamplesDeficit { get; }
int CalculateSamplesNeeded();
void WriteSamples(short[] samples, int sampleCount);
}
}

View File

@ -15,10 +15,9 @@ namespace BizHawk.Client.EmuHawk
private bool _disposed;
private readonly ISoundOutput _outputDevice;
private readonly SoundOutputProvider _outputProvider = new SoundOutputProvider();
private readonly BufferedAsync _bufferedAsync = new BufferedAsync();
private ISoundProvider _sourceProvider;
private SyncSoundMode _syncMode;
private readonly SoundOutputProvider _outputProvider = new SoundOutputProvider(); // Buffer for Sync sources
private readonly BufferedAsync _bufferedAsync = new BufferedAsync(); // Buffer for Async sources
private IBufferedSoundProvider _bufferedProvider; // One of the preceding buffers, or null if no source is set
public Sound(IntPtr mainWindowHandle)
{
@ -71,8 +70,7 @@ namespace BizHawk.Client.EmuHawk
_outputDevice.StopSound();
_outputProvider.DiscardSamples();
_bufferedAsync.DiscardSamples();
if (_bufferedProvider != null) _bufferedProvider.DiscardSamples();
Global.SoundMaxBufferDeficitMs = 0;
@ -86,28 +84,27 @@ namespace BizHawk.Client.EmuHawk
/// </summary>
public void SetInputPin(ISoundProvider source)
{
_outputProvider.DiscardSamples();
_outputProvider.BaseSoundProvider = null;
_bufferedAsync.DiscardSamples();
_bufferedAsync.BaseSoundProvider = null;
_sourceProvider = source;
if (_sourceProvider == null)
if (_bufferedProvider != null)
{
return;
_bufferedProvider.BaseSoundProvider = null;
_bufferedProvider.DiscardSamples();
_bufferedProvider = null;
}
_syncMode = _sourceProvider.SyncMode;
if (_syncMode == SyncSoundMode.Sync)
if (source == null) return;
if (source.SyncMode == SyncSoundMode.Sync)
{
_outputProvider.BaseSoundProvider = _sourceProvider;
_bufferedProvider = _outputProvider;
}
else
else if (source.SyncMode == SyncSoundMode.Async)
{
_bufferedAsync.BaseSoundProvider = _sourceProvider;
_bufferedAsync.RecalculateMagic(Global.Emulator.CoreComm.VsyncRate);
_bufferedProvider = _bufferedAsync;
}
else throw new InvalidOperationException("Unsupported sync mode.");
_bufferedProvider.BaseSoundProvider = source;
}
public bool LogUnderruns { get; set; }
@ -148,18 +145,12 @@ namespace BizHawk.Client.EmuHawk
public void UpdateSound(float atten)
{
if (!Global.Config.SoundEnabled || !IsStarted || _sourceProvider == null || _disposed)
if (!Global.Config.SoundEnabled || !IsStarted || _bufferedProvider == null || _disposed)
{
if (_sourceProvider != null) _sourceProvider.DiscardSamples();
_outputProvider.DiscardSamples();
if (_bufferedProvider != null) _bufferedProvider.DiscardSamples();
return;
}
if (_sourceProvider.SyncMode != _syncMode)
{
throw new Exception("Sync mode changed unexpectedly.");
}
if (atten < 0) atten = 0;
if (atten > 1) atten = 1;
_outputDevice.ApplyVolumeSettings(atten);
@ -173,14 +164,13 @@ namespace BizHawk.Client.EmuHawk
samples = new short[samplesNeeded * ChannelCount];
samplesProvided = samplesNeeded;
_sourceProvider.DiscardSamples();
_outputProvider.DiscardSamples();
_bufferedProvider.DiscardSamples();
}
else if (_syncMode == SyncSoundMode.Sync)
else if (_bufferedProvider == _outputProvider)
{
if (Global.Config.SoundThrottle)
{
_sourceProvider.GetSamplesSync(out samples, out samplesProvided);
_outputProvider.BaseSoundProvider.GetSamplesSync(out samples, out samplesProvided);
while (samplesNeeded < samplesProvided && !Global.DisableSecondaryThrottling)
{
@ -197,7 +187,7 @@ namespace BizHawk.Client.EmuHawk
_outputProvider.GetSamples(samplesNeeded, out samples, out samplesProvided);
}
}
else if (_syncMode == SyncSoundMode.Async)
else if (_bufferedProvider == _bufferedAsync)
{
samples = new short[samplesNeeded * ChannelCount];
@ -223,14 +213,4 @@ namespace BizHawk.Client.EmuHawk
return samples * 1000.0 / SampleRate;
}
}
public interface ISoundOutput : IDisposable
{
void StartSound();
void StopSound();
void ApplyVolumeSettings(double volume);
int MaxSamplesDeficit { get; }
int CalculateSamplesNeeded();
void WriteSamples(short[] samples, int sampleCount);
}
}

View File

@ -16,7 +16,7 @@ namespace BizHawk.Client.EmuHawk
// perform a "soft" correction by resampling it to hopefully get back inside our
// window shortly. If it ends up going too low or too high, we will perform a
// "hard" correction by generating silence or discarding samples.
public class SoundOutputProvider
public class SoundOutputProvider : IBufferedSoundProvider
{
private const int SampleRate = 44100;
private const int ChannelCount = 2;

View File

@ -117,6 +117,7 @@
<Compile Include="EmulationExceptions.cs" />
<Compile Include="Enums.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="Interfaces\IBufferedSoundProvider.cs" />
<Compile Include="Interfaces\IController.cs" />
<Compile Include="Interfaces\ICoreFileProvider.cs" />
<Compile Include="Interfaces\IEmulator.cs" />

View File

@ -0,0 +1,15 @@
namespace BizHawk.Emulation.Common
{
public interface IBufferedSoundProvider
{
/// <summary>
/// The source audio provider.
/// </summary>
ISoundProvider BaseSoundProvider { get; set; }
/// <summary>
/// Clears any internally buffered samples, and discards samples from the base provider (if set).
/// </summary>
void DiscardSamples();
}
}

View File

@ -28,7 +28,7 @@ namespace BizHawk.Emulation.Common
* TODO: For systems that _really_ don't need BufferedAsync (pce not turbocd, sms), make a way to signal
* that and then bypass the BufferedAsync.
*/
public sealed class BufferedAsync : ISoundProvider
public sealed class BufferedAsync : ISoundProvider, IBufferedSoundProvider
{
public ISoundProvider BaseSoundProvider { get; set; }