BizHawk/ExternalCoreProjects/Virtu/Speaker.cs

116 lines
2.5 KiB
C#

using System;
using System.Runtime.Serialization;
using Newtonsoft.Json;
namespace Jellyfish.Virtu
{
public interface ISpeaker
{
void ToggleOutput();
// ReSharper disable once UnusedMember.Global
void Clear();
// ReSharper disable once UnusedMember.Global
void GetSamples(out short[] samples, out int nSamp);
}
public sealed class Speaker : ISpeaker
{
// ReSharper disable once FieldCanBeMadeReadOnly.Local
private MachineEvents _events;
// ReSharper disable once FieldCanBeMadeReadOnly.Local
private ICpu _cpu;
public Speaker() { }
public Speaker(MachineEvents events, ICpu cpu)
{
_events = events;
_cpu = cpu;
_flushOutputEvent = FlushOutputEvent; // cache delegates; avoids garbage
_events.AddEvent(CyclesPerFlush * _cpu.Multiplier, _flushOutputEvent);
_isHigh = false;
_highCycles = _totalCycles = 0;
}
private const int CyclesPerFlush = 23;
// ReSharper disable once FieldCanBeMadeReadOnly.Local
private Action _flushOutputEvent;
private bool _isHigh;
private int _highCycles;
private int _totalCycles;
private long _lastCycles;
[JsonIgnore] // only relevant if trying to savestate mid-frame
private readonly short[] _buffer = new short[4096];
[JsonIgnore] // only relevant if trying to savestate mid-frame
private int _position;
#region Api
public void Clear()
{
_position = 0;
}
public void GetSamples(out short[] samples, out int nSamp)
{
samples = _buffer;
nSamp = _position / 2;
_position = 0;
}
#endregion
public void ToggleOutput()
{
UpdateCycles();
_isHigh ^= true;
}
private void FlushOutputEvent()
{
UpdateCycles();
// TODO: better than simple decimation here!!
Output(_highCycles * short.MaxValue / _totalCycles);
_highCycles = _totalCycles = 0;
_events.AddEvent(CyclesPerFlush * _cpu.Multiplier, _flushOutputEvent);
}
private void UpdateCycles()
{
int delta = (int)(_cpu.Cycles - _lastCycles);
if (_isHigh)
{
_highCycles += delta;
}
_totalCycles += delta;
_lastCycles = _cpu.Cycles;
}
private void Output(int data) // machine thread
{
data = (int)(data * 0.2);
if (_position < _buffer.Length - 2)
{
_buffer[_position++] = (short)data;
_buffer[_position++] = (short)data;
}
}
[OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
_position = 0;
}
}
}