Cleanup/fixes/etc.

This commit is contained in:
jdpurcell 2015-01-16 05:04:44 +00:00
parent 1862ddd927
commit 1a34ec6a2e
1 changed files with 90 additions and 121 deletions

View File

@ -35,152 +35,134 @@ namespace BizHawk.Client.EmuHawk
} }
} }
public class Sound : IDisposable public class Sound : IDisposable
{ {
public bool needDiscard; private const int SampleRate = 44100;
private const int BytesPerSample = 2;
private const int ChannelCount = 2;
private const int BufferSize = (SampleRate / 10) * BytesPerSample * ChannelCount; // 1/10th of a second
private bool Muted; private bool _muted;
private readonly bool disposed; private bool _disposed;
private SecondarySoundBuffer DSoundBuffer; private SecondarySoundBuffer _deviceBuffer;
private readonly byte[] SoundBuffer; private readonly BufferedAsync _semiSync = new BufferedAsync();
private const int BufferSize = 4410 * 2 * 2; // 1/10th of a second, 2 bytes per sample, 2 channels; private ISoundProvider _asyncSoundProvider;
//private int SoundBufferPosition; //TODO: use this private ISyncSoundProvider _syncSoundProvider;
private readonly BufferedAsync semisync = new BufferedAsync(); private int _actualWriteOffset = -1;
private ISoundProvider asyncsoundProvider; private long _lastWriteTime;
private ISyncSoundProvider syncsoundProvider;
public Sound(IntPtr handle, DirectSound device) public Sound(IntPtr handle, DirectSound device)
{ {
if (device != null) if (device == null) return;
{
device.SetCooperativeLevel(handle, CooperativeLevel.Priority);
var format = new WaveFormat device.SetCooperativeLevel(handle, CooperativeLevel.Priority);
{
SamplesPerSecond = 44100,
BitsPerSample = 16,
Channels = 2,
FormatTag = WaveFormatTag.Pcm,
BlockAlignment = 4
};
format.AverageBytesPerSecond = format.SamplesPerSecond * format.Channels * (format.BitsPerSample / 8);
var desc = new SoundBufferDescription var format = new WaveFormat
{ {
Format = format, SamplesPerSecond = SampleRate,
Flags = BitsPerSample = BytesPerSample * 8,
BufferFlags.GlobalFocus | BufferFlags.Software | BufferFlags.GetCurrentPosition2 | BufferFlags.ControlVolume, Channels = ChannelCount,
SizeInBytes = BufferSize FormatTag = WaveFormatTag.Pcm,
}; BlockAlignment = BytesPerSample * ChannelCount,
DSoundBuffer = new SecondarySoundBuffer(device, desc); AverageBytesPerSecond = SampleRate * BytesPerSample * ChannelCount
ChangeVolume(Global.Config.SoundVolume); };
}
SoundBuffer = new byte[BufferSize];
disposed = false; var desc = new SoundBufferDescription
{
Format = format,
Flags =
BufferFlags.GlobalFocus | BufferFlags.Software | BufferFlags.GetCurrentPosition2 | BufferFlags.ControlVolume,
SizeInBytes = BufferSize
};
_deviceBuffer = new SecondarySoundBuffer(device, desc);
ChangeVolume(Global.Config.SoundVolume);
} }
public void StartSound() public void StartSound()
{ {
if (disposed) throw new ObjectDisposedException("Sound"); if (_disposed) throw new ObjectDisposedException("Sound");
if (Global.Config.SoundEnabled == false) return; if (Global.Config.SoundEnabled == false) return;
if (DSoundBuffer == null) return; if (_deviceBuffer == null) return;
if (IsPlaying) if (IsPlaying) return;
return;
needDiscard = true; _deviceBuffer.Write(new byte[BufferSize], 0, LockFlags.EntireBuffer);
_deviceBuffer.CurrentPlayPosition = 0;
DSoundBuffer.Write(SoundBuffer, 0, LockFlags.EntireBuffer); _deviceBuffer.Play(0, PlayFlags.Looping);
DSoundBuffer.CurrentPlayPosition = 0;
DSoundBuffer.Play(0, PlayFlags.Looping);
} }
bool IsPlaying bool IsPlaying
{ {
get get
{ {
if (DSoundBuffer == null) return false; if (_deviceBuffer == null) return false;
if ((DSoundBuffer.Status & BufferStatus.Playing) != 0) return true; if ((_deviceBuffer.Status & BufferStatus.Playing) != 0) return true;
return false; return false;
} }
} }
public void StopSound() public void StopSound()
{ {
if (!IsPlaying) if (!IsPlaying) return;
return;
for (int i = 0; i < SoundBuffer.Length; i++) _deviceBuffer.Write(new byte[BufferSize], 0, LockFlags.EntireBuffer);
SoundBuffer[i] = 0; _deviceBuffer.Stop();
DSoundBuffer.Write(SoundBuffer, 0, LockFlags.EntireBuffer);
DSoundBuffer.Stop();
} }
public void Dispose() public void Dispose()
{ {
if (disposed) return; if (_disposed) return;
if (DSoundBuffer != null && DSoundBuffer.Disposed == false) if (_deviceBuffer != null && _deviceBuffer.Disposed == false)
{ {
DSoundBuffer.Dispose(); _deviceBuffer.Dispose();
DSoundBuffer = null; _deviceBuffer = null;
} }
_disposed = true;
} }
public void SetSyncInputPin(ISyncSoundProvider source) public void SetSyncInputPin(ISyncSoundProvider source)
{ {
syncsoundProvider = source; _syncSoundProvider = source;
asyncsoundProvider = null; _asyncSoundProvider = null;
semisync.DiscardSamples(); _semiSync.DiscardSamples();
} }
public void SetAsyncInputPin(ISoundProvider source) public void SetAsyncInputPin(ISoundProvider source)
{ {
syncsoundProvider = null; _syncSoundProvider = null;
asyncsoundProvider = source; _asyncSoundProvider = source;
semisync.BaseSoundProvider = source; _semiSync.BaseSoundProvider = source;
semisync.RecalculateMagic(Global.CoreComm.VsyncRate); _semiSync.RecalculateMagic(Global.CoreComm.VsyncRate);
} }
static int circularDist(int from, int to, int size) private int SNDDXGetAudioSpace()
{ {
if (size == 0) int playOffset = _deviceBuffer.CurrentPlayPosition;
return 0; int writeOffset = _deviceBuffer.CurrentWritePosition;
int diff = (to - from);
while (diff < 0)
diff += size;
return diff;
}
int soundoffset; if (_actualWriteOffset == -1)
int SNDDXGetAudioSpace() {
{ _actualWriteOffset = writeOffset;
if (DSoundBuffer == null) return 0; }
int playcursor = DSoundBuffer.CurrentPlayPosition; int bytesNeeded = (playOffset - _actualWriteOffset + BufferSize) % BufferSize;
int writecursor = DSoundBuffer.CurrentWritePosition; return bytesNeeded / (BytesPerSample * ChannelCount);
int curToWrite = circularDist(soundoffset, writecursor, BufferSize);
int curToPlay = circularDist(soundoffset, playcursor, BufferSize);
if (curToWrite < curToPlay)
return 0; // in-between the two cursors. we shouldn't write anything during this time.
return curToPlay / 4;
} }
public void UpdateSilence() public void UpdateSilence()
{ {
Muted = true; _muted = true;
UpdateSound(); UpdateSound();
Muted = false; _muted = false;
} }
public void UpdateSound() public void UpdateSound()
{ {
if (Global.Config.SoundEnabled == false || disposed) if (Global.Config.SoundEnabled == false || _disposed)
{ {
if (asyncsoundProvider != null) asyncsoundProvider.DiscardSamples(); if (_asyncSoundProvider != null) _asyncSoundProvider.DiscardSamples();
if (syncsoundProvider != null) syncsoundProvider.DiscardSamples(); if (_syncSoundProvider != null) _syncSoundProvider.DiscardSamples();
return; return;
} }
@ -189,23 +171,22 @@ namespace BizHawk.Client.EmuHawk
int samplesProvided; int samplesProvided;
if (_muted)
if (Muted)
{ {
if (samplesNeeded == 0) if (samplesNeeded == 0) return;
return;
samples = new short[samplesNeeded]; samples = new short[samplesNeeded];
samplesProvided = samplesNeeded; samplesProvided = samplesNeeded;
if (asyncsoundProvider != null) asyncsoundProvider.DiscardSamples(); if (_asyncSoundProvider != null) _asyncSoundProvider.DiscardSamples();
if (syncsoundProvider != null) syncsoundProvider.DiscardSamples(); if (_syncSoundProvider != null) _syncSoundProvider.DiscardSamples();
} }
else if (syncsoundProvider != null) else if (_syncSoundProvider != null)
{ {
if (DSoundBuffer == null) return; // can cause SNDDXGetAudioSpace() = 0 if (_deviceBuffer == null) return; // can cause SNDDXGetAudioSpace() = 0
int nsampgot; int nsampgot;
syncsoundProvider.GetSamples(out samples, out nsampgot); _syncSoundProvider.GetSamples(out samples, out nsampgot);
samplesProvided = 2 * nsampgot; samplesProvided = 2 * nsampgot;
@ -216,37 +197,25 @@ namespace BizHawk.Client.EmuHawk
samplesNeeded = SNDDXGetAudioSpace() * 2; samplesNeeded = SNDDXGetAudioSpace() * 2;
} }
} }
else if (asyncsoundProvider != null) else if (_asyncSoundProvider != null)
{ {
samples = new short[samplesNeeded]; samples = new short[samplesNeeded];
//if (asyncsoundProvider != null && Muted == false) //if (asyncsoundProvider != null && Muted == false)
//{ //{
semisync.BaseSoundProvider = asyncsoundProvider; _semiSync.BaseSoundProvider = _asyncSoundProvider;
semisync.GetSamples(samples); _semiSync.GetSamples(samples);
//} //}
//else asyncsoundProvider.DiscardSamples(); //else asyncsoundProvider.DiscardSamples();
if (samplesNeeded == 0)
return; if (samplesNeeded == 0) return;
samplesProvided = samplesNeeded; samplesProvided = samplesNeeded;
} }
else else
return; return;
int cursor = soundoffset;
for (int i = 0; i < samplesProvided; i++)
{
short s = samples[i];
SoundBuffer[cursor++] = (byte)(s & 0xFF);
SoundBuffer[cursor++] = (byte)(s >> 8);
if (cursor >= SoundBuffer.Length) _deviceBuffer.Write(samples, 0, samplesProvided, _actualWriteOffset, LockFlags.None);
cursor = 0; _actualWriteOffset = (_actualWriteOffset + (samplesProvided * BytesPerSample)) % BufferSize;
}
DSoundBuffer.Write(SoundBuffer, 0, LockFlags.EntireBuffer);
soundoffset += samplesProvided * 2;
soundoffset %= BufferSize;
} }
/// <summary> /// <summary>
@ -269,9 +238,9 @@ namespace BizHawk.Client.EmuHawk
public void UpdateSoundSettings() public void UpdateSoundSettings()
{ {
if (!Global.Config.SoundEnabled || Global.Config.SoundVolume == 0) if (!Global.Config.SoundEnabled || Global.Config.SoundVolume == 0)
DSoundBuffer.Volume = -5000; _deviceBuffer.Volume = -5000;
else else
DSoundBuffer.Volume = 0 - ((100 - Global.Config.SoundVolume) * 45); _deviceBuffer.Volume = 0 - ((100 - Global.Config.SoundVolume) * 45);
} }
} }
#else #else