diff --git a/Virtu/Services/AudioService.cs b/Virtu/Services/AudioService.cs index fec46c8..ee4bc33 100644 --- a/Virtu/Services/AudioService.cs +++ b/Virtu/Services/AudioService.cs @@ -1,5 +1,5 @@ using System; -using System.Linq; +using System.Threading; namespace Jellyfish.Virtu.Services { @@ -10,19 +10,26 @@ public AudioService(Machine machine) : { } - public void ToggleOutput() // machine thread + public void Output(int data) // machine thread { - lock (_lock) + _buffer[_index] = (byte)data; + _index = (_index + 1) % SampleSize; + if (_index == 0) { - long cycles = Machine.Cpu.Cycles; - int toggleDelta = (int)(cycles - _toggleCycles); - _toggleCycles = cycles; - - _deltaBuffer[_writeIndex] = toggleDelta; - _writeIndex = (_writeIndex + 1) % DeltaBufferSize; + _readEvent.Set(); + if (Machine.Settings.Cpu.IsThrottled) + { + _writeEvent.WaitOne(); + } } } + public override void Stop() // main thread + { + _readEvent.Set(); // signal events; avoids deadlock + _writeEvent.Set(); + } + protected void Update(int bufferSize, Action updateBuffer) // audio thread { if (updateBuffer == null) @@ -30,39 +37,12 @@ protected void Update(int bufferSize, Action updateBuffer) // audio throw new ArgumentNullException("updateBuffer"); } - lock (_lock) + if (Machine.State == MachineState.Running) { - long cycles = Machine.Cpu.Cycles; - int updateDelta = (int)(cycles - _updateCycles); - _updateCycles = _toggleCycles = cycles; // reset audio frame - - if (updateDelta > 0) - { - double bytesPerCycle = (double)bufferSize / (Machine.Settings.Cpu.IsThrottled ? CyclesPerSample : updateDelta); - - while (_readIndex != _writeIndex) - { - int deltaSize = (int)(_deltaBuffer[_readIndex] * bytesPerCycle); - if (deltaSize > bufferSize) - { - _deltaBuffer[_readIndex] -= (int)((double)bufferSize / bytesPerCycle); - break; - } - - updateBuffer(_isOutputHigh ? SampleHigh : SampleZero, deltaSize); - _isOutputHigh ^= true; - - bufferSize -= deltaSize; - _readIndex = (_readIndex + 1) % DeltaBufferSize; - } - - updateBuffer(_isOutputHigh ? SampleHigh : SampleZero, bufferSize); - } - else - { - updateBuffer(SampleZero, bufferSize); - } + _readEvent.WaitOne(); } + updateBuffer(_buffer, bufferSize); + _writeEvent.Set(); } public const int SampleRate = 44100; // hz @@ -71,20 +51,10 @@ protected void Update(int bufferSize, Action updateBuffer) // audio public const int SampleLatency = 40; // ms public const int SampleSize = (int)(SampleRate * SampleLatency / 1000f) * SampleChannels * SampleBits / 8; - private const int CyclesPerSecond = 1022730; - private const int CyclesPerSample = (int)(CyclesPerSecond * SampleLatency / 1000f); + private byte[] _buffer = new byte[SampleSize]; + private int _index; - private static readonly byte[] SampleHigh = Enumerable.Repeat((byte)0xFF, SampleSize).ToArray(); - private static readonly byte[] SampleZero = new byte[SampleSize]; - - private const int DeltaBufferSize = 8192; - - private int[] _deltaBuffer = new int[DeltaBufferSize]; - private uint _readIndex; - private uint _writeIndex; - private bool _isOutputHigh; - private long _toggleCycles; - private long _updateCycles; - private object _lock = new object(); + private AutoResetEvent _readEvent = new AutoResetEvent(false); + private AutoResetEvent _writeEvent = new AutoResetEvent(false); } }