Virtu/Virtu/Speaker.cs

91 lines
2.4 KiB
C#

using System;
using System.IO;
using Jellyfish.Virtu.Services;
namespace Jellyfish.Virtu
{
public sealed class Speaker : MachineComponent
{
public Speaker(Machine machine) :
base(machine)
{
_flushOutputEvent = FlushOutputEvent; // cache delegates; avoids garbage
}
public override void Initialize()
{
_audioService = Machine.Services.GetService<AudioService>();
Volume = 0.5f;
Machine.Events.AddEvent(CyclesPerFlush * Machine.Cpu.Multiplier, _flushOutputEvent);
}
public override void Reset()
{
_audioService.Reset();
_isHigh = false;
_highCycles = _totalCycles = 0;
}
public override void LoadState(BinaryReader reader, Version version)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}
Volume = reader.ReadSingle();
}
public override void SaveState(BinaryWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
writer.Write(Volume);
}
public void ToggleOutput()
{
UpdateCycles();
_isHigh ^= true;
}
private void FlushOutputEvent()
{
UpdateCycles();
_audioService.Output(_highCycles * short.MaxValue / _totalCycles); // quick and dirty decimation
_highCycles = _totalCycles = 0;
Machine.Events.AddEvent(CyclesPerFlush * Machine.Cpu.Multiplier, _flushOutputEvent);
}
private void UpdateCycles()
{
int delta = (int)(Machine.Cpu.Cycles - _lastCycles);
if (_isHigh)
{
_highCycles += delta;
}
_totalCycles += delta;
_lastCycles = Machine.Cpu.Cycles;
}
public float Volume { get { return _volume; } set { _volume = value; _audioService.SetVolume(_volume); } }
private const int CyclesPerFlush = 23;
private Action _flushOutputEvent;
private AudioService _audioService;
private bool _isHigh;
private int _highCycles;
private int _totalCycles;
private long _lastCycles;
private float _volume;
}
}