using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { public class TapeFilePlayer : ISupportsTapeBlockPlayback { private readonly BinaryReader _reader; private TapeBlockSetPlayer _player; /// /// Data blocks to play back /// public List DataBlocks { get; private set; } /// /// Signs that the player completed playing back the file /// public bool Eof => _player.Eof; /// /// Initializes the player from the specified reader /// /// BinaryReader instance to get tape file data from public TapeFilePlayer(BinaryReader reader) { _reader = reader; } /// /// Reads in the content of the tape file so that it can be played /// /// True, if read was successful; otherwise, false public bool ReadContent() { // --- First try TzxReader var tzxReader = new TzxReader(_reader); var readerFound = false; try { readerFound = tzxReader.ReadContent(); } catch (Exception) { // --- This exception is intentionally ingnored } if (readerFound) { // --- This is a .TZX format DataBlocks = tzxReader.DataBlocks.Where(b => b is ISupportsTapeBlockPlayback) .Cast() .ToList(); _player = new TapeBlockSetPlayer(DataBlocks); return true; } // --- Let's assume .TAP tap format _reader.BaseStream.Seek(0, SeekOrigin.Begin); var tapReader = new TapReader(_reader); readerFound = tapReader.ReadContent(); DataBlocks = tapReader.DataBlocks.Cast() .ToList(); _player = new TapeBlockSetPlayer(DataBlocks); return readerFound; } /// /// Gets the currently playing block's index /// public int CurrentBlockIndex => _player.CurrentBlockIndex; /// /// The current playable block /// public ISupportsTapeBlockPlayback CurrentBlock => _player.CurrentBlock; /// /// The current playing phase /// public PlayPhase PlayPhase => _player.PlayPhase; /// /// The tact count of the CPU when playing starts /// public long StartCycle => _player.StartCycle; /// /// Initializes the player /// public void InitPlay(long startCycle) { _player.InitPlay(startCycle); } /// /// Gets the EAR bit value for the specified cycle /// /// Tacts to retrieve the EAR bit /// /// A tuple of the EAR bit and a flag that indicates it is time to move to the next block /// public bool GetEarBit(long currentCycle) => _player.GetEarBit(currentCycle); /// /// Moves the current block index to the next playable block /// /// Tacts time to start the next block public void NextBlock(long currentCycle) => _player.NextBlock(currentCycle); } }