Included missing changes from last checkin.

--HG--
extra : convert_revision : svn%3Affd33b8c-2492-42e0-bdc5-587b920b7d6d/trunk%4043069
This commit is contained in:
Sean Fausett 2010-03-14 22:01:22 +00:00
parent ea2a892113
commit 0d1a883260

View File

@ -1,5 +1,5 @@
using System; using System;
using System.Linq; using System.Threading;
namespace Jellyfish.Virtu.Services 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; _readEvent.Set();
int toggleDelta = (int)(cycles - _toggleCycles); if (Machine.Settings.Cpu.IsThrottled)
_toggleCycles = cycles; {
_writeEvent.WaitOne();
_deltaBuffer[_writeIndex] = toggleDelta; }
_writeIndex = (_writeIndex + 1) % DeltaBufferSize;
} }
} }
public override void Stop() // main thread
{
_readEvent.Set(); // signal events; avoids deadlock
_writeEvent.Set();
}
protected void Update(int bufferSize, Action<byte[], int> updateBuffer) // audio thread protected void Update(int bufferSize, Action<byte[], int> updateBuffer) // audio thread
{ {
if (updateBuffer == null) if (updateBuffer == null)
@ -30,39 +37,12 @@ protected void Update(int bufferSize, Action<byte[], int> updateBuffer) // audio
throw new ArgumentNullException("updateBuffer"); throw new ArgumentNullException("updateBuffer");
} }
lock (_lock) if (Machine.State == MachineState.Running)
{ {
long cycles = Machine.Cpu.Cycles; _readEvent.WaitOne();
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);
}
} }
updateBuffer(_buffer, bufferSize);
_writeEvent.Set();
} }
public const int SampleRate = 44100; // hz public const int SampleRate = 44100; // hz
@ -71,20 +51,10 @@ protected void Update(int bufferSize, Action<byte[], int> updateBuffer) // audio
public const int SampleLatency = 40; // ms public const int SampleLatency = 40; // ms
public const int SampleSize = (int)(SampleRate * SampleLatency / 1000f) * SampleChannels * SampleBits / 8; public const int SampleSize = (int)(SampleRate * SampleLatency / 1000f) * SampleChannels * SampleBits / 8;
private const int CyclesPerSecond = 1022730; private byte[] _buffer = new byte[SampleSize];
private const int CyclesPerSample = (int)(CyclesPerSecond * SampleLatency / 1000f); private int _index;
private static readonly byte[] SampleHigh = Enumerable.Repeat((byte)0xFF, SampleSize).ToArray(); private AutoResetEvent _readEvent = new AutoResetEvent(false);
private static readonly byte[] SampleZero = new byte[SampleSize]; private AutoResetEvent _writeEvent = new AutoResetEvent(false);
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();
} }
} }