diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index aefb1900ae..f108d03e54 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -256,22 +256,11 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -288,7 +277,6 @@
-
@@ -298,20 +286,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/DefaultTapeProvider.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/DefaultTapeProvider.cs
deleted file mode 100644
index 2ee8ef6f63..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/DefaultTapeProvider.cs
+++ /dev/null
@@ -1,135 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- public class DefaultTapeProvider : ITapeProvider
- {
- public const string RESOURCE_FOLDER = "TzxResources";
- public const string DEFAULT_SAVE_FILE_DIR = @"C:\Temp\ZxSpectrumSavedFiles";
- public const string DEFAULT_NAME = "SavedFile";
- public const string DEFAULT_EXT = ".tzx";
- private string _suggestedName;
- private string _fullFileName;
- private int _dataBlockCount;
-
- private byte[] _file;
-
- ///
- /// The directory files should be saved to
- ///
- public string SaveFileFolder { get; }
-
-
-
- public DefaultTapeProvider(byte[] file, string saveFolder = null)
- {
- SaveFileFolder = string.IsNullOrWhiteSpace(saveFolder)
- ? DEFAULT_SAVE_FILE_DIR
- : saveFolder;
-
- _file = file;
- }
-
- ///
- /// The component provider should be able to reset itself
- ///
- ///
-
- public void Reset()
- {
- _dataBlockCount = 0;
- _suggestedName = null;
- _fullFileName = null;
- }
-
-
- ///
- /// Tha tape set to load the content from
- ///
- public string TapeSetName { get; set; }
-
- ///
- /// Gets a binary reader that provider TZX content
- ///
- /// BinaryReader instance to obtain the content from
- public BinaryReader GetTapeContent()
- {
- Stream stream = new MemoryStream(_file);
- var reader = new BinaryReader(stream);
- return reader;
- }
-
- ///
- /// Creates a tape file with the specified name
- ///
- ///
- public void CreateTapeFile()
- {
- //Reset();
- }
-
- ///
- /// This method sets the name of the file according to the
- /// Spectrum SAVE HEADER information
- ///
- ///
- public void SetName(string name)
- {
- _suggestedName = name;
- }
-
- ///
- /// Appends the TZX block to the tape file
- ///
- ///
- public void SaveTapeBlock(ITapeDataSerialization block)
- {
- if (_dataBlockCount == 0)
- {
- if (!Directory.Exists(SaveFileFolder))
- {
- Directory.CreateDirectory(SaveFileFolder);
- }
- var baseFileName = $"{_suggestedName ?? DEFAULT_NAME}_{DateTime.Now:yyyyMMdd_HHmmss}{DEFAULT_EXT}";
- _fullFileName = Path.Combine(SaveFileFolder, baseFileName);
- using (var writer = new BinaryWriter(File.Create(_fullFileName)))
- {
- var header = new TzxHeader();
- header.WriteTo(writer);
- }
- }
- _dataBlockCount++;
-
- var stream = File.Open(_fullFileName, FileMode.Append);
- using (var writer = new BinaryWriter(stream))
- {
- block.WriteTo(writer);
- }
- }
-
- ///
- /// The tape provider can finalize the tape when all
- /// TZX blocks are written.
- ///
- public void FinalizeTapeFile()
- {
- }
-
- ///
- /// Obtains the specified resource stream ot the given assembly
- ///
- /// Assembly to get the resource stream from
- /// Resource name
- private static Stream GetFileResource(Assembly asm, string resourceName)
- {
- var resourceFullName = $"{asm.GetName().Name}.{RESOURCE_FOLDER}.{resourceName}";
- return asm.GetManifestResourceStream(resourceFullName);
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/IKeyboard.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/IKeyboard.cs
similarity index 100%
rename from BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/IKeyboard.cs
rename to BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/IKeyboard.cs
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/KempstonJoystick.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/KempstonJoystick.cs
similarity index 100%
rename from BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/KempstonJoystick.cs
rename to BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/KempstonJoystick.cs
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ISaveToTapeProvider.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ISaveToTapeProvider.cs
deleted file mode 100644
index 05a4de9e06..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ISaveToTapeProvider.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This interface describes the behavior of an object that
- /// provides tape content
- ///
- public interface ISaveToTapeProvider
- {
- ///
- /// Creates a tape file with the specified name
- ///
- ///
- void CreateTapeFile();
-
- ///
- /// This method sets the name of the file according to the
- /// Spectrum SAVE HEADER information
- ///
- ///
- void SetName(string name);
-
- ///
- /// Appends the tape block to the tape file
- ///
- ///
- void SaveTapeBlock(ITapeDataSerialization block);
-
- ///
- /// The tape provider can finalize the tape when all
- /// tape blocks are written.
- ///
- void FinalizeTapeFile();
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ISupportsTapeBlockPlayback.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ISupportsTapeBlockPlayback.cs
deleted file mode 100644
index 8d1c47645b..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ISupportsTapeBlockPlayback.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using BizHawk.Common;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This interface represents that the implementing class supports
- /// emulating tape playback of a single tape block
- ///
- public interface ISupportsTapeBlockPlayback
- {
- ///
- /// The current playing phase
- ///
- PlayPhase PlayPhase { get; }
-
- ///
- /// The tact count of the CPU when playing starts
- ///
- long StartCycle { get; }
-
- ///
- /// Initializes the player
- ///
- void InitPlay(long startCycle);
-
- ///
- /// Gets the EAR bit value for the specified tact
- ///
- /// Tacts to retrieve the EAR bit
- ///
- /// The EAR bit value to play back
- ///
- bool GetEarBit(long currentCycle);
-
-
- void SyncState(Serializer ser);
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ISupportsTapeBlockSetPlayback.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ISupportsTapeBlockSetPlayback.cs
deleted file mode 100644
index 1312761e51..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ISupportsTapeBlockSetPlayback.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This interface represents that the implementing class supports
- /// emulating tape playback of a set of subsequent tape blocks
- ///
- public interface ISupportsTapeBlockSetPlayback : ISupportsTapeBlockPlayback
- {
- ///
- /// Moves the player to the next playable block
- ///
- /// Tacts time to start the next block
- void NextBlock(long currentCycle);
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ITapeContentProvider.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ITapeContentProvider.cs
deleted file mode 100644
index 62f8c6f814..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ITapeContentProvider.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-
-using System.IO;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This interface describes the behavior of an object that
- /// provides tape content
- ///
- public interface ITapeContentProvider
- {
- ///
- /// Tha tape set to load the content from
- ///
- string TapeSetName { get; set; }
-
- ///
- /// Gets a binary reader that provides tape content
- ///
- /// BinaryReader instance to obtain the content from
- BinaryReader GetTapeContent();
-
- void Reset();
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ITapeData.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ITapeData.cs
deleted file mode 100644
index 5879c57536..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ITapeData.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Represetns the data in the tape
- ///
- public interface ITapeData
- {
- ///
- /// Block Data
- ///
- byte[] Data { get; }
-
- ///
- /// Pause after this block (given in milliseconds)
- ///
- ushort PauseAfter { get; }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ITapeDataSerialization.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ITapeDataSerialization.cs
deleted file mode 100644
index 9f48e9097e..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ITapeDataSerialization.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Defines the serialization operations of a TZX record
- ///
- public interface ITapeDataSerialization
- {
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- void ReadFrom(BinaryReader reader);
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- void WriteTo(BinaryWriter writer);
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ITapeProvider.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ITapeProvider.cs
deleted file mode 100644
index 91a4457a31..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Interfaces/ITapeProvider.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-using System.IO;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This interface describes the behavior of an object that
- /// provides TZX tape content
- ///
- public interface ITapeProvider
- {
- ///
- /// Tha tape set to load the content from
- ///
- string TapeSetName { get; set; }
-
- ///
- /// Gets a binary reader that provider TZX content
- ///
- /// BinaryReader instance to obtain the content from
- BinaryReader GetTapeContent();
-
- ///
- /// Creates a tape file with the specified name
- ///
- ///
- void CreateTapeFile();
-
- ///
- /// This method sets the name of the file according to the
- /// Spectrum SAVE HEADER information
- ///
- ///
- void SetName(string name);
-
- ///
- /// Appends the TZX block to the tape file
- ///
- ///
- void SaveTapeBlock(ITapeDataSerialization block);
-
- ///
- /// The tape provider can finalize the tape when all
- /// TZX blocks are written.
- ///
- void FinalizeTapeFile();
-
- ///
- /// Provider can reset itself
- ///
- void Reset();
-
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/RomData.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Rom/RomData.cs
similarity index 100%
rename from BizHawk.Emulation.Cores/Computers/SinclairSpectrum/RomData.cs
rename to BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Rom/RomData.cs
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/AY38912.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/AY38912.cs
similarity index 100%
rename from BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/AY38912.cs
rename to BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/AY38912.cs
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Buzzer.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/Buzzer.cs
similarity index 100%
rename from BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Buzzer.cs
rename to BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/Buzzer.cs
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Pulse.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/Pulse.cs
similarity index 100%
rename from BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Pulse.cs
rename to BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/Pulse.cs
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Tape.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Tape.cs
deleted file mode 100644
index fd29eb3855..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Tape.cs
+++ /dev/null
@@ -1,814 +0,0 @@
-using BizHawk.Common;
-using BizHawk.Emulation.Cores.Components.Z80A;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- /*
- * Much of the TAPE implementation has been taken from: https://github.com/Dotneteer/spectnetide
- *
- * MIT License
-
- Copyright (c) 2017 Istvan Novak
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- */
-
- ///
- /// Represents the tape device (or DATACORDER as AMSTRAD liked to call it)
- ///
- public class Tape
- {
- private SpectrumBase _machine { get; set; }
- private Z80A _cpu { get; set; }
- private Buzzer _buzzer { get; set; }
-
- private TapeOperationMode _currentMode;
- private TapeFilePlayer _tapePlayer;
- private bool _micBitState;
- private long _lastMicBitActivityCycle;
- private SavePhase _savePhase;
- private int _pilotPulseCount;
- private int _bitOffset;
- private byte _dataByte;
- private int _dataLength;
- private byte[] _dataBuffer;
- private int _dataBlockCount;
- private MicPulseType _prevDataPulse;
-
- ///
- /// Number of tacts after save mod can be exited automatically
- ///
- public const int SAVE_STOP_SILENCE = 17500000;
-
- ///
- /// The address of the ERROR routine in the Spectrum ROM
- ///
- public const ushort ERROR_ROM_ADDRESS = 0x0008;
-
- ///
- /// The maximum distance between two scans of the EAR bit
- ///
- public const int MAX_TACT_JUMP = 10000;
-
- ///
- /// The width tolerance of save pulses
- ///
- public const int SAVE_PULSE_TOLERANCE = 24;
-
- ///
- /// Minimum number of pilot pulses before SYNC1
- ///
- public const int MIN_PILOT_PULSE_COUNT = 3000;
-
- ///
- /// Lenght of the data buffer to allocate for the SAVE operation
- ///
- public const int DATA_BUFFER_LENGTH = 0x10000;
-
- ///
- /// Gets the tape content provider
- ///
- public ITapeProvider TapeProvider { get; }
-
- ///
- /// The TapeFilePlayer that can playback tape content
- ///
- public TapeFilePlayer TapeFilePlayer => _tapePlayer;
-
- ///
- /// The current operation mode of the tape
- ///
- public TapeOperationMode CurrentMode => _currentMode;
-
-
- private bool _fastLoad = false;
-
-
- public virtual void Init(SpectrumBase machine)
- {
- _machine = machine;
- _cpu = _machine.CPU;
- _buzzer = machine.BuzzerDevice;
- Reset();
- }
-
- public Tape(ITapeProvider tapeProvider)
- {
- TapeProvider = tapeProvider;
- }
-
- public virtual void Reset()
- {
- TapeProvider?.Reset();
- _tapePlayer = null;
- _currentMode = TapeOperationMode.Passive;
- _savePhase = SavePhase.None;
- _micBitState = true;
- }
-
- public void CPUFrameCompleted()
- {
- SetTapeMode();
- if (CurrentMode == TapeOperationMode.Load
- && _fastLoad
- && TapeFilePlayer != null
- && TapeFilePlayer.PlayPhase != PlayPhase.Completed
- && _cpu.RegPC == 1529) //_machine.RomData.LoadBytesRoutineAddress)
- {
-
- if (FastLoadFromTzx())
- {
- //FastLoadCompleted?.Invoke(this, EventArgs.Empty);
- }
-
- }
- }
-
- ///
- /// Sets the current tape mode according to the current PC register
- /// and the MIC bit state
- ///
- public void SetTapeMode()
- {
- switch (_currentMode)
- {
- case TapeOperationMode.Passive:
- if (_cpu.RegPC == 1523) // _machine.RomData.LoadBytesRoutineAddress) //1529
- {
- EnterLoadMode();
- }
- else if (_cpu.RegPC == 2416) // _machine.RomData.SaveBytesRoutineAddress)
- {
- EnterSaveMode();
- }
-
- var res = _cpu.RegPC;
- var res2 = _machine.Spectrum.RegPC;
-
- return;
- case TapeOperationMode.Save:
- if (_cpu.RegPC == ERROR_ROM_ADDRESS
- || (int)(_cpu.TotalExecutedCycles - _lastMicBitActivityCycle) > SAVE_STOP_SILENCE)
- {
- LeaveSaveMode();
- }
- return;
- case TapeOperationMode.Load:
- if ((_tapePlayer?.Eof ?? false) || _cpu.RegPC == ERROR_ROM_ADDRESS)
- {
- LeaveLoadMode();
- }
- return;
- }
- }
-
- ///
- /// Puts the device in save mode. From now on, every MIC pulse is recorded
- ///
- private void EnterSaveMode()
- {
- _currentMode = TapeOperationMode.Save;
- _savePhase = SavePhase.None;
- _micBitState = true;
- _lastMicBitActivityCycle = _cpu.TotalExecutedCycles;
- _pilotPulseCount = 0;
- _prevDataPulse = MicPulseType.None;
- _dataBlockCount = 0;
- TapeProvider?.CreateTapeFile();
- }
-
- ///
- /// Leaves the save mode. Stops recording MIC pulses
- ///
- private void LeaveSaveMode()
- {
- _currentMode = TapeOperationMode.Passive;
- TapeProvider?.FinalizeTapeFile();
- }
-
- ///
- /// Puts the device in load mode. From now on, EAR pulses are played by a device
- ///
- private void EnterLoadMode()
- {
- _currentMode = TapeOperationMode.Load;
-
- var contentReader = TapeProvider?.GetTapeContent();
- if (contentReader == null) return;
-
- // --- Play the content
- _tapePlayer = new TapeFilePlayer(contentReader);
- _tapePlayer.ReadContent();
- _tapePlayer.InitPlay(_cpu.TotalExecutedCycles);
- _buzzer.SetTapeMode(true);
- }
-
- ///
- /// Leaves the load mode. Stops the device that playes EAR pulses
- ///
- private void LeaveLoadMode()
- {
- _currentMode = TapeOperationMode.Passive;
- _tapePlayer = null;
- TapeProvider?.Reset();
- _buzzer.SetTapeMode(false);
- }
-
- ///
- /// Loads the next TZX player block instantly without emulation
- /// EAR bit processing
- ///
- /// True, if fast load is operative
- private bool FastLoadFromTzx()
- {
- var c = _machine.Spectrum;
-
- var blockType = TapeFilePlayer.CurrentBlock.GetType();
- bool canFlash = TapeFilePlayer.CurrentBlock is ITapeData;
-
- // --- Check, if we can load the current block in a fast way
- if (!(TapeFilePlayer.CurrentBlock is ITapeData)
- || TapeFilePlayer.PlayPhase == PlayPhase.Completed)
- {
- // --- We cannot play this block
- return false;
- }
-
- var currentData = TapeFilePlayer.CurrentBlock as ITapeData;
-
- var regs = _cpu.Regs;
-
- //regs.AF = regs._AF_;
- //c.Set16BitAF(c.Get16BitAF_());
- _cpu.A = _cpu.A_s;
- _cpu.F = _cpu.F_s;
-
- // --- Check if the operation is LOAD or VERIFY
- var isVerify = (c.RegAF & 0xFF01) == 0xFF00;
-
- // --- At this point IX contains the address to load the data,
- // --- DE shows the #of bytes to load. A contains 0x00 for header,
- // --- 0xFF for data block
- var data = currentData.Data;
- if (data[0] != regs[_cpu.A])
- {
- // --- This block has a different type we're expecting
- regs[_cpu.A] = (byte)(regs[_cpu.A] ^ regs[_cpu.L]);
- regs[_cpu.F] &= (byte)ZXSpectrum.FlagsResetMask.Z;
- regs[_cpu.F] &= (byte)ZXSpectrum.FlagsResetMask.C;
- c.RegPC = _machine.RomData.LoadBytesInvalidHeaderAddress;
-
- // --- Get the next block
- TapeFilePlayer.NextBlock(_cpu.TotalExecutedCycles);
- return true;
- }
-
- // --- It is time to load the block
- var curIndex = 1;
- //var memory = _machine.me MemoryDevice;
- regs[_cpu.H] = regs[_cpu.A];
- while (c.RegDE > 0)
- {
- var de16 = c.RegDE;
- var ix16 = c.RegIX;
- if (curIndex > data.Length - 1)
- {
- // --- No more data to read
- //break;
- }
-
- regs[_cpu.L] = data[curIndex];
- if (isVerify && regs[_cpu.L] != _machine.ReadBus(c.RegIX))
- {
- // --- Verify failed
- regs[_cpu.A] = (byte)(_machine.ReadBus(c.RegIX) ^ regs[_cpu.L]);
- regs[_cpu.F] &= (byte)ZXSpectrum.FlagsResetMask.Z;
- regs[_cpu.F] &= (byte)ZXSpectrum.FlagsResetMask.C;
- c.RegPC = _machine.RomData.LoadBytesInvalidHeaderAddress;
- return true;
- }
-
- // --- Store the loaded data byte
- _machine.WriteBus(c.RegIX, (byte)regs[_cpu.L]);
- regs[_cpu.H] ^= regs[_cpu.L];
- curIndex++;
- //regs.IX++;
- //c.Set16BitIX((ushort)((int)c.Get16BitIX() + 1));
- c.RegIX++;
- //regs.DE--;
- //c.Set16BitDE((ushort)((int)c.Get16BitDE() - 1));
- //_cpu.Regs[_cpu.E]--;
- c.RegDE--;
- var te = c.RegDE;
- }
-
- // --- Check the parity byte at the end of the data stream
- if (curIndex > data.Length - 1 || regs[_cpu.H] != data[curIndex])
- {
- // --- Carry is reset to sign an error
- regs[_cpu.F] &= (byte)ZXSpectrum.FlagsResetMask.C;
- }
- else
- {
- // --- Carry is set to sign success
- regs[_cpu.F] |= (byte)ZXSpectrum.FlagsSetMask.C;
- }
- c.RegPC = _machine.RomData.LoadBytesResumeAddress;
-
- // --- Get the next block
- TapeFilePlayer.NextBlock(_cpu.TotalExecutedCycles);
- return true;
- }
-
-
- ///
- /// the EAR bit read from tape
- ///
- ///
- ///
- public virtual bool GetEarBit(int cpuCycles)
- {
- if (_currentMode != TapeOperationMode.Load)
- {
- return true;
- }
-
- var earBit = _tapePlayer?.GetEarBit(cpuCycles) ?? true;
- _buzzer.ProcessPulseValue(true, earBit);
- return earBit;
- }
-
- ///
- /// Processes the mic bit change
- ///
- ///
- public virtual void ProcessMicBit(bool micBit)
- {
- if (_currentMode != TapeOperationMode.Save
- || _micBitState == micBit)
- {
- return;
- }
-
- var length = _cpu.TotalExecutedCycles - _lastMicBitActivityCycle;
-
- // --- Classify the pulse by its width
- var pulse = MicPulseType.None;
- if (length >= TapeDataBlockPlayer.BIT_0_PL - SAVE_PULSE_TOLERANCE
- && length <= TapeDataBlockPlayer.BIT_0_PL + SAVE_PULSE_TOLERANCE)
- {
- pulse = MicPulseType.Bit0;
- }
- else if (length >= TapeDataBlockPlayer.BIT_1_PL - SAVE_PULSE_TOLERANCE
- && length <= TapeDataBlockPlayer.BIT_1_PL + SAVE_PULSE_TOLERANCE)
- {
- pulse = MicPulseType.Bit1;
- }
- if (length >= TapeDataBlockPlayer.PILOT_PL - SAVE_PULSE_TOLERANCE
- && length <= TapeDataBlockPlayer.PILOT_PL + SAVE_PULSE_TOLERANCE)
- {
- pulse = MicPulseType.Pilot;
- }
- else if (length >= TapeDataBlockPlayer.SYNC_1_PL - SAVE_PULSE_TOLERANCE
- && length <= TapeDataBlockPlayer.SYNC_1_PL + SAVE_PULSE_TOLERANCE)
- {
- pulse = MicPulseType.Sync1;
- }
- else if (length >= TapeDataBlockPlayer.SYNC_2_PL - SAVE_PULSE_TOLERANCE
- && length <= TapeDataBlockPlayer.SYNC_2_PL + SAVE_PULSE_TOLERANCE)
- {
- pulse = MicPulseType.Sync2;
- }
- else if (length >= TapeDataBlockPlayer.TERM_SYNC - SAVE_PULSE_TOLERANCE
- && length <= TapeDataBlockPlayer.TERM_SYNC + SAVE_PULSE_TOLERANCE)
- {
- pulse = MicPulseType.TermSync;
- }
- else if (length < TapeDataBlockPlayer.SYNC_1_PL - SAVE_PULSE_TOLERANCE)
- {
- pulse = MicPulseType.TooShort;
- }
- else if (length > TapeDataBlockPlayer.PILOT_PL + 2 * SAVE_PULSE_TOLERANCE)
- {
- pulse = MicPulseType.TooLong;
- }
-
- _micBitState = micBit;
- _lastMicBitActivityCycle = _cpu.TotalExecutedCycles;
-
- // --- Lets process the pulse according to the current SAVE phase and pulse width
- var nextPhase = SavePhase.Error;
- switch (_savePhase)
- {
- case SavePhase.None:
- if (pulse == MicPulseType.TooShort || pulse == MicPulseType.TooLong)
- {
- nextPhase = SavePhase.None;
- }
- else if (pulse == MicPulseType.Pilot)
- {
- _pilotPulseCount = 1;
- nextPhase = SavePhase.Pilot;
- }
- break;
- case SavePhase.Pilot:
- if (pulse == MicPulseType.Pilot)
- {
- _pilotPulseCount++;
- nextPhase = SavePhase.Pilot;
- }
- else if (pulse == MicPulseType.Sync1 && _pilotPulseCount >= MIN_PILOT_PULSE_COUNT)
- {
- nextPhase = SavePhase.Sync1;
- }
- break;
- case SavePhase.Sync1:
- if (pulse == MicPulseType.Sync2)
- {
- nextPhase = SavePhase.Sync2;
- }
- break;
- case SavePhase.Sync2:
- if (pulse == MicPulseType.Bit0 || pulse == MicPulseType.Bit1)
- {
- // --- Next pulse starts data, prepare for receiving it
- _prevDataPulse = pulse;
- nextPhase = SavePhase.Data;
- _bitOffset = 0;
- _dataByte = 0;
- _dataLength = 0;
- _dataBuffer = new byte[DATA_BUFFER_LENGTH];
- }
- break;
- case SavePhase.Data:
- if (pulse == MicPulseType.Bit0 || pulse == MicPulseType.Bit1)
- {
- if (_prevDataPulse == MicPulseType.None)
- {
- // --- We are waiting for the second half of the bit pulse
- _prevDataPulse = pulse;
- nextPhase = SavePhase.Data;
- }
- else if (_prevDataPulse == pulse)
- {
- // --- We received a full valid bit pulse
- nextPhase = SavePhase.Data;
- _prevDataPulse = MicPulseType.None;
-
- // --- Add this bit to the received data
- _bitOffset++;
- _dataByte = (byte)(_dataByte * 2 + (pulse == MicPulseType.Bit0 ? 0 : 1));
- if (_bitOffset == 8)
- {
- // --- We received a full byte
- _dataBuffer[_dataLength++] = _dataByte;
- _dataByte = 0;
- _bitOffset = 0;
- }
- }
- }
- else if (pulse == MicPulseType.TermSync)
- {
- // --- We received the terminating pulse, the datablock has been completed
- nextPhase = SavePhase.None;
- _dataBlockCount++;
-
- // --- Create and save the data block
- var dataBlock = new TzxStandardSpeedDataBlock
- {
- Data = _dataBuffer,
- DataLength = (ushort)_dataLength
- };
-
- // --- If this is the first data block, extract the name from the header
- if (_dataBlockCount == 1 && _dataLength == 0x13)
- {
- // --- It's a header!
- var sb = new StringBuilder(16);
- for (var i = 2; i <= 11; i++)
- {
- sb.Append((char)_dataBuffer[i]);
- }
- var name = sb.ToString().TrimEnd();
- TapeProvider?.SetName(name);
- }
- TapeProvider?.SaveTapeBlock(dataBlock);
- }
- break;
- }
- _savePhase = nextPhase;
- }
-
- public void SyncState(Serializer ser)
- {
- ser.BeginSection("TapeDevice");
- ser.Sync("_micBitState", ref _micBitState);
- ser.Sync("_lastMicBitActivityCycle", ref _lastMicBitActivityCycle);
- ser.Sync("_pilotPulseCount", ref _pilotPulseCount);
- ser.Sync("_bitOffset", ref _bitOffset);
- ser.Sync("_dataByte", ref _dataByte);
- ser.Sync("_dataLength", ref _dataLength);
- ser.Sync("_dataBlockCount", ref _dataBlockCount);
- ser.Sync("_dataBuffer", ref _dataBuffer, false);
- ser.SyncEnum("_currentMode", ref _currentMode);
- ser.SyncEnum("_savePhase", ref _savePhase);
- ser.SyncEnum("_prevDataPulse", ref _prevDataPulse);
-
- ser.EndSection();
- }
- }
-
- ///
- /// This enum represents the operation mode of the tape
- ///
- public enum TapeOperationMode : byte
- {
- ///
- /// The tape device is passive
- ///
- Passive = 0,
-
- ///
- /// The tape device is saving information (MIC pulses)
- ///
- Save,
-
- ///
- /// The tape device generates EAR pulses from a player
- ///
- Load
- }
-
- ///
- /// This class represents a spectrum tape header
- ///
- public class SpectrumTapeHeader
- {
- private const int HEADER_LEN = 19;
- private const int TYPE_OFFS = 1;
- private const int NAME_OFFS = 2;
- private const int NAME_LEN = 10;
- private const int DATA_LEN_OFFS = 12;
- private const int PAR1_OFFS = 14;
- private const int PAR2_OFFS = 16;
- private const int CHK_OFFS = 18;
-
- ///
- /// The bytes of the header
- ///
- public byte[] HeaderBytes { get; }
-
- ///
- /// Initializes a new instance of the class.
- ///
- public SpectrumTapeHeader()
- {
- HeaderBytes = new byte[HEADER_LEN];
- for (var i = 0; i < HEADER_LEN; i++) HeaderBytes[i] = 0x00;
- CalcChecksum();
- }
-
- ///
- /// Initializes a new instance with the specified header data.
- ///
- /// Header data
- public SpectrumTapeHeader(byte[] header)
- {
- if (header == null) throw new ArgumentNullException(nameof(header));
- if (header.Length != HEADER_LEN)
- {
- throw new ArgumentException($"Header must be exactly {HEADER_LEN} bytes long");
- }
- HeaderBytes = new byte[HEADER_LEN];
- header.CopyTo(HeaderBytes, 0);
- CalcChecksum();
- }
-
- ///
- /// Gets or sets the type of the header
- ///
- public byte Type
- {
- get { return HeaderBytes[TYPE_OFFS]; }
- set
- {
- HeaderBytes[TYPE_OFFS] = (byte)(value & 0x03);
- CalcChecksum();
- }
- }
-
- ///
- /// Gets or sets the program name
- ///
- public string Name
- {
- get
- {
- var name = new StringBuilder(NAME_LEN + 4);
- for (var i = NAME_OFFS; i < NAME_OFFS + NAME_LEN; i++)
- {
- name.Append((char)HeaderBytes[i]);
- }
- return name.ToString().TrimEnd();
- }
- set
- {
- if (value == null) throw new ArgumentNullException(nameof(value));
- if (value.Length > NAME_LEN) value = value.Substring(0, NAME_LEN);
- else if (value.Length < NAME_LEN) value = value.PadRight(NAME_LEN, ' ');
- for (var i = NAME_OFFS; i < NAME_OFFS + NAME_LEN; i++)
- {
- HeaderBytes[i] = (byte)value[i - NAME_OFFS];
- }
- CalcChecksum();
- }
- }
-
- ///
- /// Gets or sets the Data Length
- ///
- public ushort DataLength
- {
- get { return GetWord(DATA_LEN_OFFS); }
- set { SetWord(DATA_LEN_OFFS, value); }
- }
-
- ///
- /// Gets or sets Parameter1
- ///
- public ushort Parameter1
- {
- get { return GetWord(PAR1_OFFS); }
- set { SetWord(PAR1_OFFS, value); }
- }
-
- ///
- /// Gets or sets Parameter2
- ///
- public ushort Parameter2
- {
- get { return GetWord(PAR2_OFFS); }
- set { SetWord(PAR2_OFFS, value); }
- }
-
- ///
- /// Gets the value of checksum
- ///
- public byte Checksum => HeaderBytes[CHK_OFFS];
-
- ///
- /// Calculate the checksum
- ///
- private void CalcChecksum()
- {
- var chk = 0x00;
- for (var i = 0; i < HEADER_LEN - 1; i++) chk ^= HeaderBytes[i];
- HeaderBytes[CHK_OFFS] = (byte)chk;
- }
-
- ///
- /// Gets the word value from the specified offset
- ///
- private ushort GetWord(int offset) =>
- (ushort)(HeaderBytes[offset] + 256 * HeaderBytes[offset + 1]);
-
- ///
- /// Sets the word value at the specified offset
- ///
- private void SetWord(int offset, ushort value)
- {
- HeaderBytes[offset] = (byte)(value & 0xff);
- HeaderBytes[offset + 1] = (byte)(value >> 8);
- CalcChecksum();
- }
- }
-
- ///
- /// This enum defines the MIC pulse types according to their widths
- ///
- public enum MicPulseType : byte
- {
- ///
- /// No pulse information
- ///
- None = 0,
-
- ///
- /// Too short to be a valid pulse
- ///
- TooShort,
-
- ///
- /// Too long to be a valid pulse
- ///
- TooLong,
-
- ///
- /// PILOT pulse (Length: 2168 cycles)
- ///
- Pilot,
-
- ///
- /// SYNC1 pulse (Length: 667 cycles)
- ///
- Sync1,
-
- ///
- /// SYNC2 pulse (Length: 735 cycles)
- ///
- Sync2,
-
- ///
- /// BIT0 pulse (Length: 855 cycles)
- ///
- Bit0,
-
- ///
- /// BIT1 pulse (Length: 1710 cycles)
- ///
- Bit1,
-
- ///
- /// TERM_SYNC pulse (Length: 947 cycles)
- ///
- TermSync
- }
-
- ///
- /// Represents the playing phase of the current block
- ///
- public enum PlayPhase
- {
- ///
- /// The player is passive
- ///
- None = 0,
-
- ///
- /// Pilot signals
- ///
- Pilot,
-
- ///
- /// Sync signals at the end of the pilot
- ///
- Sync,
-
- ///
- /// Bits in the data block
- ///
- Data,
-
- ///
- /// Short terminating sync signal before pause
- ///
- TermSync,
-
- ///
- /// Pause after the data block
- ///
- Pause,
-
- ///
- /// The entire block has been played back
- ///
- Completed
- }
-
- ///
- /// This enumeration defines the phases of the SAVE operation
- ///
- public enum SavePhase : byte
- {
- /// No SAVE operation is in progress
- None = 0,
-
- /// Emitting PILOT impulses
- Pilot,
-
- /// Emitting SYNC1 impulse
- Sync1,
-
- /// Emitting SYNC2 impulse
- Sync2,
-
- /// Emitting BIT0/BIT1 impulses
- Data,
-
- /// Unexpected pulse detected
- Error
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/TapeBlockSetPlayer.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/TapeBlockSetPlayer.cs
deleted file mode 100644
index 6d5b149f9e..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/TapeBlockSetPlayer.cs
+++ /dev/null
@@ -1,143 +0,0 @@
-using BizHawk.Common;
-using System.Collections.Generic;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This class is responsible to "play" a tape file.
- ///
- public class TapeBlockSetPlayer : ISupportsTapeBlockSetPlayback
- {
- ///
- /// All data blocks that can be played back
- ///
- public List DataBlocks { get; }
-
- ///
- /// Signs that the player completed playing back the file
- ///
- private bool eof;
- public bool Eof
- {
- get { return eof; }
- set { eof = value; }
- }
-
-
- ///
- /// Gets the currently playing block's index
- ///
- private int currentBlockIndex;
- public int CurrentBlockIndex
- {
- get { return currentBlockIndex; }
- set { currentBlockIndex = value; }
- }
-
- ///
- /// The current playable block
- ///
- private ISupportsTapeBlockPlayback currentBlock;
- public ISupportsTapeBlockPlayback CurrentBlock
- {
- get { return DataBlocks[CurrentBlockIndex]; }
- //set { currentBlock = value; }
- }
-
-
- ///
- /// The current playing phase
- ///
- private PlayPhase playPhase;
- public PlayPhase PlayPhase
- {
- get { return playPhase; }
- set { playPhase = value; }
- }
-
-
- ///
- /// The cycle count of the CPU when playing starts
- ///
- private long startCycle;
- public long StartCycle
- {
- get { return startCycle; }
- set { startCycle = value; }
- }
-
-
- public TapeBlockSetPlayer(List dataBlocks)
- {
- DataBlocks = dataBlocks;
- Eof = dataBlocks.Count == 0;
- }
-
- ///
- /// Initializes the player
- ///
- public void InitPlay(long startTact)
- {
- CurrentBlockIndex = -1;
- NextBlock(startTact);
- PlayPhase = PlayPhase.None;
- StartCycle = startTact;
- }
-
- ///
- /// Gets the EAR bit value for the specified cycle
- ///
- /// Cycles 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)
- {
- // --- Check for EOF
- if (CurrentBlockIndex == DataBlocks.Count - 1
- && (CurrentBlock.PlayPhase == PlayPhase.Pause || CurrentBlock.PlayPhase == PlayPhase.Completed))
- {
- Eof = true;
- }
- if (CurrentBlockIndex >= DataBlocks.Count || CurrentBlock == null)
- {
- // --- After all playable block played back, there's nothing more to do
- PlayPhase = PlayPhase.Completed;
- return true;
- }
- var earbit = CurrentBlock.GetEarBit(currentCycle);
- if (CurrentBlock.PlayPhase == PlayPhase.Completed)
- {
- NextBlock(currentCycle);
- }
- return earbit;
- }
-
- ///
- /// Moves the current block index to the next playable block
- ///
- /// Cycles time to start the next block
- public void NextBlock(long currentCycle)
- {
- if (CurrentBlockIndex >= DataBlocks.Count - 1)
- {
- PlayPhase = PlayPhase.Completed;
- Eof = true;
- return;
- }
- CurrentBlockIndex++;
- CurrentBlock.InitPlay(currentCycle);
- }
-
- public void SyncState(Serializer ser)
- {
- ser.BeginSection("TapeBlockSetPlayer");
- ser.Sync("eof", ref eof);
- ser.Sync("currentBlockIndex", ref currentBlockIndex);
- ser.SyncEnum("playPhase", ref playPhase);
- ser.Sync("startCycle", ref startCycle);
- currentBlock.SyncState(ser);
- ser.EndSection();
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/TapeDataBlockPlayer.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/TapeDataBlockPlayer.cs
deleted file mode 100644
index 0c7dae4f14..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/TapeDataBlockPlayer.cs
+++ /dev/null
@@ -1,279 +0,0 @@
-
-using BizHawk.Common;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Represents the standard speed data block in a tape file
- ///
- public class TapeDataBlockPlayer : ISupportsTapeBlockPlayback, ITapeData
- {
- ///
- /// Pause after this block (default: 1000ms)
- ///
- private ushort pauseAfter;
- public ushort PauseAfter
- {
- get { return pauseAfter; }
- }
-
- ///
- /// Block Data
- ///
- private byte[] data;
- public byte[] Data
- {
- get { return data; }
- }
-
- ///
- /// Initializes a new instance
- ///
- public TapeDataBlockPlayer(byte[] _data, ushort _pauseAfter)
- {
- pauseAfter = _pauseAfter;
- data = _data;
- }
-
- ///
- /// Pilot pulse length
- ///
- public const int PILOT_PL = 2168;
-
- ///
- /// Pilot pulses in the ROM header block
- ///
- public const int HEADER_PILOT_COUNT = 8063;
-
- ///
- /// Pilot pulses in the ROM data block
- ///
- public const int DATA_PILOT_COUNT = 3223;
-
- ///
- /// Sync 1 pulse length
- ///
- public const int SYNC_1_PL = 667;
-
- ///
- /// Sync 2 pulse lenth
- ///
- public const int SYNC_2_PL = 735;
-
- ///
- /// Bit 0 pulse length
- ///
- public const int BIT_0_PL = 855;
-
- ///
- /// Bit 1 pulse length
- ///
- public const int BIT_1_PL = 1710;
-
- ///
- /// End sync pulse length
- ///
- public const int TERM_SYNC = 947;
-
- ///
- /// 1 millisecond pause
- ///
- public const int PAUSE_MS = 3500;
-
- private int _pilotEnds;
- private int _sync1Ends;
- private int _sync2Ends;
- private int _bitStarts;
- private int _bitPulseLength;
- private bool _currentBit;
- private long _termSyncEnds;
- private long _pauseEnds;
-
- ///
- /// The index of the currently playing byte
- ///
- private int byteIndex;
- public int ByteIndex
- {
- get { return byteIndex; }
- set { byteIndex = value; }
- }
-
- ///
- /// The mask of the currently playing bit in the current byte
- ///
- private byte bitMask;
- public byte BitMask
- {
- get { return bitMask; }
- set { bitMask = value; }
- }
-
- ///
- /// The current playing phase
- ///
- private PlayPhase playPhase;
- public PlayPhase PlayPhase
- {
- get { return playPhase; }
- set { playPhase = value; }
- }
-
- ///
- /// The cycle count of the CPU when playing starts
- ///
- private long startCycle;
- public long StartCycle
- {
- get { return startCycle; }
- set { startCycle = value; }
- }
-
- ///
- /// Last cycle queried
- ///
- private long lastCycle;
- public long LastCycle
- {
- get { return lastCycle; }
- set { lastCycle = value; }
- }
-
- ///
- /// Initializes the player
- ///
- public void InitPlay(long startTact)
- {
- PlayPhase = PlayPhase.Pilot;
- StartCycle = LastCycle = startTact;
- _pilotEnds = ((Data[0] & 0x80) == 0 ? HEADER_PILOT_COUNT : DATA_PILOT_COUNT) * PILOT_PL;
- _sync1Ends = _pilotEnds + SYNC_1_PL;
- _sync2Ends = _sync1Ends + SYNC_2_PL;
- ByteIndex = 0;
- BitMask = 0x80;
- }
-
- ///
- /// Gets the EAR bit value for the specified cycle
- ///
- /// Tacts to retrieve the EAR bit
- ///
- /// The EAR bit value to play back
- ///
- public bool GetEarBit(long currentCycle)
- {
- var pos = (int)(currentCycle - StartCycle);
- LastCycle = currentCycle;
-
- if (PlayPhase == PlayPhase.Pilot || PlayPhase == PlayPhase.Sync)
- {
- // --- Generate the appropriate pilot or sync EAR bit
- if (pos <= _pilotEnds)
- {
- // --- Alternating pilot pulses
- return (pos / PILOT_PL) % 2 == 0;
- }
- if (pos <= _sync1Ends)
- {
- // --- 1st sync pulse
- PlayPhase = PlayPhase.Sync;
- return false;
- }
- if (pos <= _sync2Ends)
- {
- // --- 2nd sync pulse
- PlayPhase = PlayPhase.Sync;
- return true;
- }
- PlayPhase = PlayPhase.Data;
- _bitStarts = _sync2Ends;
- _currentBit = (Data[ByteIndex] & BitMask) != 0;
- _bitPulseLength = _currentBit ? BIT_1_PL : BIT_0_PL;
- }
- if (PlayPhase == PlayPhase.Data)
- {
- // --- Data block playback
- // --- Generate current bit pulse
- var bitPos = pos - _bitStarts;
- if (bitPos < _bitPulseLength)
- {
- // --- First pulse of the bit
- return false;
- }
- if (bitPos < 2 * _bitPulseLength)
- {
- // --- Second pulse of the bit
- return true;
- }
-
- // --- Move to the next bit, or byte
- if ((BitMask >>= 1) == 0)
- {
- BitMask = 0x80;
- ByteIndex++;
- }
-
- // --- Prepare the next bit
- if (ByteIndex < Data.Length)
- {
- _bitStarts += 2 * _bitPulseLength;
- _currentBit = (Data[ByteIndex] & BitMask) != 0;
- _bitPulseLength = _currentBit ? BIT_1_PL : BIT_0_PL;
- // --- We're in the first pulse of the next bit
- return false;
- }
-
- // --- We've played back all data bytes, send terminating pulse
- PlayPhase = PlayPhase.TermSync;
- _termSyncEnds = currentCycle + TERM_SYNC;
- return false;
- }
-
- if (PlayPhase == PlayPhase.TermSync)
- {
- if (currentCycle < _termSyncEnds)
- {
- return false;
- }
-
- // --- We've played back all data, not, it's pause time
- PlayPhase = PlayPhase.Pause;
- _pauseEnds = currentCycle + PAUSE_MS * PauseAfter;
- return true;
- }
-
- // --- We need to produce pause signs
- if (currentCycle > _pauseEnds)
- {
- PlayPhase = PlayPhase.Completed;
- }
- return true;
- }
-
-
- public void SyncState(Serializer ser)
- {
- ser.BeginSection("TapeDataBlockPlayer");
-
- ser.Sync("pauseAfter", ref pauseAfter);
- ser.Sync("data", ref data, false);
-
- ser.Sync("_pilotEnds", ref _pilotEnds);
- ser.Sync("_sync1Ends", ref _sync1Ends);
- ser.Sync("_sync2Ends", ref _sync2Ends);
- ser.Sync("_bitStarts", ref _bitStarts);
- ser.Sync("_bitPulseLength", ref _bitPulseLength);
- ser.Sync("_currentBit", ref _currentBit);
- ser.Sync("_termSyncEnds", ref _termSyncEnds);
- ser.Sync("_pauseEnds", ref _pauseEnds);
-
- ser.Sync("byteIndex", ref byteIndex);
- ser.Sync("bitMask", ref bitMask);
- ser.SyncEnum("playPhase", ref playPhase);
- ser.Sync("startCycle", ref startCycle);
- ser.Sync("lastCycle", ref lastCycle);
-
- ser.EndSection();
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/TapeFilePlayer.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/TapeFilePlayer.cs
deleted file mode 100644
index 92c32dbc95..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/TapeFilePlayer.cs
+++ /dev/null
@@ -1,128 +0,0 @@
-using BizHawk.Common;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This class recognizes .TZX and .TAP files, and playes back
- /// the content accordingly.
- ///
- public class TapeFilePlayer : ISupportsTapeBlockPlayback
- {
- private readonly BinaryReader _reader;
- private TapeBlockSetPlayer _player;
- private int _numberOfDataBlocks;
-
- ///
- /// 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);
-
- public void SyncState(Serializer ser)
- {
- ser.BeginSection("TapeFilePlayer");
- ReadContent();
- ser.Sync("_numberOfDataBlocks", ref _numberOfDataBlocks);
- _player.SyncState(ser);
- ser.EndSection();
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Sound.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Sound.cs
deleted file mode 100644
index 994e32df80..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Sound.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// The abstract class that all emulated models will inherit from
- /// * Sound *
- ///
- public abstract partial class SpectrumBase
- {
-
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapDataBlock.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapDataBlock.cs
deleted file mode 100644
index 0682b32752..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapDataBlock.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-
-using BizHawk.Common;
-using System.IO;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This class describes a TAP Block
- ///
- public sealed class TapDataBlock :
- ITapeData,
- ITapeDataSerialization,
- ISupportsTapeBlockPlayback
- {
- private TapeDataBlockPlayer _player;
-
- ///
- /// Block Data
- ///
- private byte[] data;
- public byte[] Data
- {
- get { return data; }
- set { data = value; }
- }
-
- ///
- /// Pause after this block (given in milliseconds)
- ///
- public ushort PauseAfter => 1000;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public void ReadFrom(BinaryReader reader)
- {
- var length = reader.ReadUInt16();
- Data = reader.ReadBytes(length);
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public void WriteTo(BinaryWriter writer)
- {
- writer.Write((ushort)Data.Length);
- writer.Write(Data);
- }
-
- ///
- /// The index of the currently playing byte
- ///
- /// This proprty is made public for test purposes
- public int ByteIndex => _player.ByteIndex;
-
- ///
- /// The mask of the currently playing bit in the current byte
- ///
- public byte BitMask => _player.BitMask;
-
- ///
- /// The current playing phase
- ///
- public PlayPhase PlayPhase => _player.PlayPhase;
-
- ///
- /// The tact count of the CPU when playing starts
- ///
- public long StartCycle => _player.StartCycle;
-
- ///
- /// Last tact queried
- ///
- public long LastCycle => _player.LastCycle;
-
- ///
- /// Initializes the player
- ///
- public void InitPlay(long startTact)
- {
- _player = new TapeDataBlockPlayer(Data, PauseAfter);
- _player.InitPlay(startTact);
- }
-
- ///
- /// Gets the EAR bit value for the specified tact
- ///
- /// Tacts to retrieve the EAR bit
- ///
- /// The EAR bit value to play back
- ///
- public bool GetEarBit(long currentTact) => _player.GetEarBit(currentTact);
-
- public void SyncState(Serializer ser)
- {
- ser.BeginSection("TapDataBlock");
-
- ser.Sync("data", ref data, false);
-
- ser.EndSection();
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapPlayer.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapPlayer.cs
deleted file mode 100644
index 0c24566e37..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapPlayer.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-
-using BizHawk.Common;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This class is responsible to "play" a TAP file.
- ///
- public class TapPlayer : TapReader, ISupportsTapeBlockPlayback
- {
- private TapeBlockSetPlayer _player;
-
- ///
- /// 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 TZX file data from
- public TapPlayer(BinaryReader reader) : base(reader)
- {
- }
-
- ///
- /// Reads in the content of the TZX file so that it can be played
- ///
- /// True, if read was successful; otherwise, false
- public override bool ReadContent()
- {
- var success = base.ReadContent();
-
- var blocks = DataBlocks.Cast()
- .ToList();
- _player = new TapeBlockSetPlayer(blocks);
- return success;
- }
-
- ///
- /// 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 tact
- ///
- /// 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);
-
-
- public void SyncState(Serializer ser)
- {
- ser.BeginSection("TapePlayer");
-
- _player.SyncState(ser);
-
- ser.EndSection();
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapReader.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapReader.cs
deleted file mode 100644
index b915daf0fc..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapReader.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-
-using System.Collections.Generic;
-using System.IO;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This class reads a TAP file
- ///
- public class TapReader
- {
- private readonly BinaryReader _reader;
-
- ///
- /// Data blocks of this TZX file
- ///
- public IList DataBlocks { get; }
-
- ///
- /// Initializes the player from the specified reader
- ///
- ///
- public TapReader(BinaryReader reader)
- {
- _reader = reader;
- DataBlocks = new List();
- }
-
- ///
- /// Reads in the content of the TZX file so that it can be played
- ///
- /// True, if read was successful; otherwise, false
- public virtual bool ReadContent()
- {
- try
- {
- while (_reader.BaseStream.Position != _reader.BaseStream.Length)
- {
- var tapBlock = new TapDataBlock();
- tapBlock.ReadFrom(_reader);
- DataBlocks.Add(tapBlock);
- }
- return true;
- }
- catch
- {
- // --- This exception is intentionally ignored
- return false;
- }
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/BlockAbstraction.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/BlockAbstraction.cs
deleted file mode 100644
index a5145928e9..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/BlockAbstraction.cs
+++ /dev/null
@@ -1,172 +0,0 @@
-
-using System;
-using System.IO;
-using System.Text;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This class describes a TZX Block
- ///
- public abstract class TzxDataBlockBase : ITapeDataSerialization
- {
- ///
- /// The ID of the block
- ///
- public abstract int BlockId { get; }
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public abstract void ReadFrom(BinaryReader reader);
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public abstract void WriteTo(BinaryWriter writer);
-
- ///
- /// Override this method to check the content of the block
- ///
- public virtual bool IsValid => true;
-
- ///
- /// Reads the specified number of words from the reader.
- ///
- /// Reader to obtain the input from
- /// Number of words to get
- /// Word array read from the input
- public static ushort[] ReadWords(BinaryReader reader, int count)
- {
- var result = new ushort[count];
- var bytes = reader.ReadBytes(2 * count);
- for (var i = 0; i < count; i++)
- {
- result[i] = (ushort)(bytes[i * 2] + bytes[i * 2 + 1] << 8);
- }
- return result;
- }
-
- ///
- /// Writes the specified array of words to the writer
- ///
- /// Output
- /// Word array
- public static void WriteWords(BinaryWriter writer, ushort[] words)
- {
- foreach (var word in words)
- {
- writer.Write(word);
- }
- }
-
- ///
- /// Converts the provided bytes to an ASCII string
- ///
- /// Bytes to convert
- /// First byte offset
- /// Number of bytes
- /// ASCII string representation
- public static string ToAsciiString(byte[] bytes, int offset = 0, int count = -1)
- {
- if (count < 0) count = bytes.Length - offset;
- var sb = new StringBuilder();
- for (var i = offset; i < count; i++)
- {
- sb.Append(Convert.ToChar(bytes[i]));
- }
- return sb.ToString();
- }
- }
-
- ///
- /// Base class for all TZX block type with data length of 3 bytes
- ///
- public abstract class Tzx3ByteDataBlockBase : TzxDataBlockBase
- {
- ///
- /// Used bits in the last byte (other bits should be 0)
- ///
- ///
- /// (e.g. if this is 6, then the bits used(x) in the last byte are:
- /// xxxxxx00, where MSb is the leftmost bit, LSb is the rightmost bit)
- ///
- public byte LastByteUsedBits { get; set; }
-
- ///
- /// Lenght of block data
- ///
- public byte[] DataLength { get; set; }
-
- ///
- /// Block Data
- ///
- public byte[] Data { get; set; }
-
- ///
- /// Override this method to check the content of the block
- ///
- public override bool IsValid => GetLength() == Data.Length;
-
- ///
- /// Calculates data length
- ///
- protected int GetLength()
- {
- return DataLength[0] + DataLength[1] << 8 + DataLength[2] << 16;
- }
- }
-
- ///
- /// This class represents a TZX data block with empty body
- ///
- public abstract class TzxBodylessDataBlockBase : TzxDataBlockBase
- {
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- }
- }
-
- ///
- /// This class represents a deprecated block
- ///
- public abstract class TzxDeprecatedDataBlockBase : TzxDataBlockBase
- {
- ///
- /// Reads through the block infromation, and does not store it
- ///
- /// Stream to read the block from
- public abstract void ReadThrough(BinaryReader reader);
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- throw new InvalidOperationException("Deprecated TZX data blocks cannot be written.");
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/DataBlocks.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/DataBlocks.cs
deleted file mode 100644
index cfd694d544..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/DataBlocks.cs
+++ /dev/null
@@ -1,1433 +0,0 @@
-
-using BizHawk.Common;
-using System.IO;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Represents the standard speed data block in a TZX file
- ///
- public class TzxArchiveInfoDataBlock : Tzx3ByteDataBlockBase
- {
- ///
- /// Length of the whole block (without these two bytes)
- ///
- public ushort Length { get; set; }
-
- ///
- /// Number of text strings
- ///
- public byte StringCount { get; set; }
-
- ///
- /// List of text strings
- ///
- public TzxText[] TextStrings { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x32;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- Length = reader.ReadUInt16();
- StringCount = reader.ReadByte();
- TextStrings = new TzxText[StringCount];
- for (var i = 0; i < StringCount; i++)
- {
- var text = new TzxText();
- text.ReadFrom(reader);
- TextStrings[i] = text;
- }
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(Length);
- writer.Write(StringCount);
- foreach (var text in TextStrings)
- {
- text.WriteTo(writer);
- }
- }
- }
-
- ///
- /// This block was created to support the Commodore 64 standard
- /// ROM and similar tape blocks.
- ///
- public class TzxC64RomTypeDataBlock : TzxDeprecatedDataBlockBase
- {
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x16;
-
- ///
- /// Reads through the block infromation, and does not store it
- ///
- /// Stream to read the block from
- public override void ReadThrough(BinaryReader reader)
- {
- var length = reader.ReadInt32();
- reader.ReadBytes(length - 4);
- }
- }
-
- ///
- /// This block is made to support another type of encoding that is
- /// commonly used by the C64.
- ///
- public class TzxC64TurboTapeDataBlock : TzxDeprecatedDataBlockBase
- {
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x17;
-
- ///
- /// Reads through the block infromation, and does not store it
- ///
- /// Stream to read the block from
- public override void ReadThrough(BinaryReader reader)
- {
- var length = reader.ReadInt32();
- reader.ReadBytes(length - 4);
- }
- }
-
- ///
- /// This block is an analogue of the CALL Subroutine statement.
- ///
- ///
- /// It basically executes a sequence of blocks that are somewhere
- /// else and then goes back to the next block. Because more than
- /// one call can be normally used you can include a list of sequences
- /// to be called. The 'nesting' of call blocks is also not allowed
- /// for the simplicity reasons. You can, of course, use the CALL
- /// blocks in the LOOP sequences and vice versa.
- ///
- public class TzxCallSequenceDataBlock : TzxDataBlockBase
- {
- ///
- /// Number of group name
- ///
- public byte NumberOfCalls { get; set; }
-
- ///
- /// Group name bytes
- ///
- public ushort[] BlockOffsets { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x26;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- NumberOfCalls = reader.ReadByte();
- BlockOffsets = ReadWords(reader, NumberOfCalls);
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(NumberOfCalls);
- WriteWords(writer, BlockOffsets);
- }
- }
-
- ///
- /// Represents the standard speed data block in a TZX file
- ///
- public class TzxCswRecordingDataBlock : TzxDataBlockBase
- {
- ///
- /// Block length (without these four bytes)
- ///
- public uint BlockLength { get; set; }
-
- ///
- /// Pause after this block
- ///
- public ushort PauseAfter { get; set; }
-
- ///
- /// Sampling rate
- ///
- public byte[] SamplingRate { get; set; }
-
- ///
- /// Compression type
- ///
- ///
- /// 0x01=RLE, 0x02=Z-RLE
- ///
- public byte CompressionType { get; set; }
-
- ///
- /// Number of stored pulses (after decompression, for validation purposes)
- ///
- public uint PulseCount { get; set; }
-
- ///
- /// CSW data, encoded according to the CSW file format specification
- ///
- public byte[] Data { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x18;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- BlockLength = reader.ReadUInt32();
- PauseAfter = reader.ReadUInt16();
- SamplingRate = reader.ReadBytes(3);
- CompressionType = reader.ReadByte();
- PulseCount = reader.ReadUInt32();
- var length = (int)BlockLength - 4 /* PauseAfter*/ - 3 /* SamplingRate */
- - 1 /* CompressionType */ - 4 /* PulseCount */;
- Data = reader.ReadBytes(length);
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(BlockLength);
- writer.Write(PauseAfter);
- writer.Write(SamplingRate);
- writer.Write(CompressionType);
- writer.Write(PulseCount);
- writer.Write(Data);
- }
-
- ///
- /// Override this method to check the content of the block
- ///
- public override bool IsValid => BlockLength == 4 + 3 + 1 + 4 + Data.Length;
- }
-
- ///
- /// Represents the standard speed data block in a TZX file
- ///
- public class TzxCustomInfoDataBlock : Tzx3ByteDataBlockBase
- {
- ///
- /// Identification string (in ASCII)
- ///
- public byte[] Id { get; set; }
-
- ///
- /// String representation of the ID
- ///
- public string IdText => ToAsciiString(Id);
-
- ///
- /// Length of the custom info
- ///
- public uint Length { get; set; }
-
- ///
- /// Custom information
- ///
- public byte[] CustomInfo { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x35;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- Id = reader.ReadBytes(10);
- Length = reader.ReadUInt32();
- CustomInfo = reader.ReadBytes((int)Length);
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(Id);
- writer.Write(Length);
- writer.Write(CustomInfo);
- }
- }
-
- ///
- /// Represents the standard speed data block in a TZX file
- ///
- public class TzxDirectRecordingDataBlock : Tzx3ByteDataBlockBase
- {
- ///
- /// Number of T-states per sample (bit of data)
- ///
- public ushort TactsPerSample { get; set; }
-
- ///
- /// Pause after this block
- ///
- public ushort PauseAfter { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x15;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- TactsPerSample = reader.ReadUInt16();
- PauseAfter = reader.ReadUInt16();
- LastByteUsedBits = reader.ReadByte();
- DataLength = reader.ReadBytes(3);
- Data = reader.ReadBytes(GetLength());
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(TactsPerSample);
- writer.Write(PauseAfter);
- writer.Write(LastByteUsedBits);
- writer.Write(DataLength);
- writer.Write(Data);
- }
- }
-
- ///
- /// This is a special block that would normally be generated only by emulators.
- ///
- public class TzxEmulationInfoDataBlock : TzxDeprecatedDataBlockBase
- {
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x34;
-
- ///
- /// Reads through the block infromation, and does not store it
- ///
- /// Stream to read the block from
- public override void ReadThrough(BinaryReader reader)
- {
- reader.ReadBytes(8);
- }
- }
-
- ///
- /// Represents a generalized data block in a TZX file
- ///
- public class TzxGeneralizedDataBlock : TzxDataBlockBase
- {
- ///
- /// Block length (without these four bytes)
- ///
- public uint BlockLength { get; set; }
-
- ///
- /// Pause after this block
- ///
- public ushort PauseAfter { get; set; }
-
- ///
- /// Total number of symbols in pilot/sync block (can be 0)
- ///
- public uint Totp { get; set; }
-
- ///
- /// Maximum number of pulses per pilot/sync symbol
- ///
- public byte Npp { get; set; }
-
- ///
- /// Number of pilot/sync symbols in the alphabet table (0=256)
- ///
- public byte Asp { get; set; }
-
- ///
- /// Total number of symbols in data stream (can be 0)
- ///
- public uint Totd { get; set; }
-
- ///
- /// Maximum number of pulses per data symbol
- ///
- public byte Npd { get; set; }
-
- ///
- /// Number of data symbols in the alphabet table (0=256)
- ///
- public byte Asd { get; set; }
-
- ///
- /// Pilot and sync symbols definition table
- ///
- ///
- /// This field is present only if Totp > 0
- ///
- public TzxSymDef[] PilotSymDef { get; set; }
-
- ///
- /// Pilot and sync data stream
- ///
- ///
- /// This field is present only if Totd > 0
- ///
- public TzxPrle[] PilotStream { get; set; }
-
- ///
- /// Data symbols definition table
- ///
- ///
- /// This field is present only if Totp > 0
- ///
- public TzxSymDef[] DataSymDef { get; set; }
-
- ///
- /// Data stream
- ///
- ///
- /// This field is present only if Totd > 0
- ///
- public TzxPrle[] DataStream { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x19;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- BlockLength = reader.ReadUInt32();
- PauseAfter = reader.ReadUInt16();
- Totp = reader.ReadUInt32();
- Npp = reader.ReadByte();
- Asp = reader.ReadByte();
- Totd = reader.ReadUInt32();
- Npd = reader.ReadByte();
- Asd = reader.ReadByte();
-
- PilotSymDef = new TzxSymDef[Asp];
- for (var i = 0; i < Asp; i++)
- {
- var symDef = new TzxSymDef(Npp);
- symDef.ReadFrom(reader);
- PilotSymDef[i] = symDef;
- }
-
- PilotStream = new TzxPrle[Totp];
- for (var i = 0; i < Totp; i++)
- {
- PilotStream[i].Symbol = reader.ReadByte();
- PilotStream[i].Repetitions = reader.ReadUInt16();
- }
-
- DataSymDef = new TzxSymDef[Asd];
- for (var i = 0; i < Asd; i++)
- {
- var symDef = new TzxSymDef(Npd);
- symDef.ReadFrom(reader);
- DataSymDef[i] = symDef;
- }
-
- DataStream = new TzxPrle[Totd];
- for (var i = 0; i < Totd; i++)
- {
- DataStream[i].Symbol = reader.ReadByte();
- DataStream[i].Repetitions = reader.ReadUInt16();
- }
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(BlockLength);
- writer.Write(PauseAfter);
- writer.Write(Totp);
- writer.Write(Npp);
- writer.Write(Asp);
- writer.Write(Totd);
- writer.Write(Npd);
- writer.Write(Asd);
- for (var i = 0; i < Asp; i++)
- {
- PilotSymDef[i].WriteTo(writer);
- }
- for (var i = 0; i < Totp; i++)
- {
- writer.Write(PilotStream[i].Symbol);
- writer.Write(PilotStream[i].Repetitions);
- }
-
- for (var i = 0; i < Asd; i++)
- {
- DataSymDef[i].WriteTo(writer);
- }
-
- for (var i = 0; i < Totd; i++)
- {
- writer.Write(DataStream[i].Symbol);
- writer.Write(DataStream[i].Repetitions);
- }
- }
- }
-
- ///
- /// This block is generated when you merge two ZX Tape files together.
- ///
- ///
- /// It is here so that you can easily copy the files together and use
- /// them. Of course, this means that resulting file would be 10 bytes
- /// longer than if this block was not used. All you have to do if
- /// you encounter this block ID is to skip next 9 bytes.
- ///
- public class TzxGlueDataBlock : TzxDataBlockBase
- {
- ///
- /// Value: { "XTape!", 0x1A, MajorVersion, MinorVersion }
- ///
- ///
- /// Just skip these 9 bytes and you will end up on the next ID.
- ///
- public byte[] Glue { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x5A;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- Glue = reader.ReadBytes(9);
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(Glue);
- }
- }
-
- ///
- /// This indicates the end of a group. This block has no body.
- ///
- public class TzxGroupEndDataBlock : TzxBodylessDataBlockBase
- {
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x22;
- }
-
- ///
- /// This block marks the start of a group of blocks which are
- /// to be treated as one single (composite) block.
- ///
- public class TzxGroupStartDataBlock : TzxDataBlockBase
- {
- ///
- /// Number of group name
- ///
- public byte Length { get; set; }
-
- ///
- /// Group name bytes
- ///
- public byte[] Chars { get; set; }
-
- ///
- /// Gets the group name
- ///
- public string GroupName => ToAsciiString(Chars);
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x21;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- Length = reader.ReadByte();
- Chars = reader.ReadBytes(Length);
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(Length);
- writer.Write(Chars);
- }
- }
-
- ///
- ///
- ///
- public class TzxHardwareInfoDataBlock : TzxDataBlockBase
- {
- ///
- /// Number of machines and hardware types for which info is supplied
- ///
- public byte HwCount { get; set; }
-
- ///
- /// List of machines and hardware
- ///
- public TzxHwInfo[] HwInfo { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x33;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- HwCount = reader.ReadByte();
- HwInfo = new TzxHwInfo[HwCount];
- for (var i = 0; i < HwCount; i++)
- {
- var hw = new TzxHwInfo();
- hw.ReadFrom(reader);
- HwInfo[i] = hw;
- }
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(HwCount);
- foreach (var hw in HwInfo)
- {
- hw.WriteTo(writer);
- }
- }
- }
-
- ///
- /// This block will enable you to jump from one block to another within the file.
- ///
- ///
- /// Jump 0 = 'Loop Forever' - this should never happen
- /// Jump 1 = 'Go to the next block' - it is like NOP in assembler
- /// Jump 2 = 'Skip one block'
- /// Jump -1 = 'Go to the previous block'
- ///
- public class TzxJumpDataBlock : TzxDataBlockBase
- {
- ///
- /// Relative jump value
- ///
- ///
- ///
- public short Jump { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x23;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- Jump = reader.ReadInt16();
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(Jump);
- }
- }
-
- ///
- /// It means that the utility should jump back to the start
- /// of the loop if it hasn't been run for the specified number
- /// of times.
- ///
- public class TzxLoopEndDataBlock : TzxBodylessDataBlockBase
- {
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x25;
- }
-
- ///
- /// If you have a sequence of identical blocks, or of identical
- /// groups of blocks, you can use this block to tell how many
- /// times they should be repeated.
- ///
- public class TzxLoopStartDataBlock : TzxDataBlockBase
- {
- ///
- /// Number of repetitions (greater than 1)
- ///
- public ushort Loops { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x24;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- Loops = reader.ReadUInt16();
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(Loops);
- }
- }
-
- ///
- /// This will enable the emulators to display a message for a given time.
- ///
- ///
- /// This should not stop the tape and it should not make silence. If the
- /// time is 0 then the emulator should wait for the user to press a key.
- ///
- public class TzxMessageDataBlock : TzxDataBlockBase
- {
- ///
- /// Time (in seconds) for which the message should be displayed
- ///
- public byte Time { get; set; }
-
- ///
- /// Length of the description
- ///
- public byte MessageLength { get; set; }
-
- ///
- /// The description bytes
- ///
- public byte[] Message;
-
- ///
- /// The string form of description
- ///
- public string MessageText => ToAsciiString(Message);
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x31;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- Time = reader.ReadByte();
- MessageLength = reader.ReadByte();
- Message = reader.ReadBytes(MessageLength);
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(Time);
- writer.Write(MessageLength);
- writer.Write(Message);
- }
- }
-
- ///
- /// Represents the standard speed data block in a TZX file
- ///
- public class TzxPulseSequenceDataBlock : TzxDataBlockBase
- {
- ///
- /// Pause after this block
- ///
- public byte PulseCount { get; set; }
-
- ///
- /// Lenght of block data
- ///
- public ushort[] PulseLengths { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x13;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- PulseCount = reader.ReadByte();
- PulseLengths = ReadWords(reader, PulseCount);
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(PulseCount);
- WriteWords(writer, PulseLengths);
- }
-
- ///
- /// Override this method to check the content of the block
- ///
- public override bool IsValid => PulseCount == PulseLengths.Length;
- }
-
- ///
- /// Represents the standard speed data block in a TZX file
- ///
- public class TzxPureDataBlock : Tzx3ByteDataBlockBase
- {
- ///
- /// Length of the zero bit
- ///
- public ushort ZeroBitPulseLength { get; set; }
-
- ///
- /// Length of the one bit
- ///
- public ushort OneBitPulseLength { get; set; }
-
- ///
- /// Pause after this block
- ///
- public ushort PauseAfter { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x14;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- ZeroBitPulseLength = reader.ReadUInt16();
- OneBitPulseLength = reader.ReadUInt16();
- LastByteUsedBits = reader.ReadByte();
- PauseAfter = reader.ReadUInt16();
- DataLength = reader.ReadBytes(3);
- Data = reader.ReadBytes(GetLength());
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(ZeroBitPulseLength);
- writer.Write(OneBitPulseLength);
- writer.Write(LastByteUsedBits);
- writer.Write(PauseAfter);
- writer.Write(DataLength);
- writer.Write(Data);
- }
- }
-
- ///
- /// Represents the standard speed data block in a TZX file
- ///
- public class TzxPureToneDataBlock : TzxDataBlockBase
- {
- ///
- /// Pause after this block
- ///
- public ushort PulseLength { get; private set; }
-
- ///
- /// Lenght of block data
- ///
- public ushort PulseCount { get; private set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x12;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- PulseLength = reader.ReadUInt16();
- PulseCount = reader.ReadUInt16();
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(PulseLength);
- writer.Write(PulseCount);
- }
- }
-
- ///
- /// This block indicates the end of the Called Sequence.
- /// The next block played will be the block after the last
- /// CALL block
- ///
- public class TzxReturnFromSequenceDataBlock : TzxBodylessDataBlockBase
- {
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x27;
- }
-
- ///
- /// Pause (silence) or 'Stop the Tape' block
- ///
- public class TzxSelectDataBlock : TzxDataBlockBase
- {
- ///
- /// Length of the whole block (without these two bytes)
- ///
- public ushort Length { get; set; }
-
- ///
- /// Number of selections
- ///
- public byte SelectionCount { get; set; }
-
- ///
- /// List of selections
- ///
- public TzxSelect[] Selections { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x28;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- Length = reader.ReadUInt16();
- SelectionCount = reader.ReadByte();
- Selections = new TzxSelect[SelectionCount];
- foreach (var selection in Selections)
- {
- selection.ReadFrom(reader);
- }
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(Length);
- writer.Write(SelectionCount);
- foreach (var selection in Selections)
- {
- selection.WriteTo(writer);
- }
- }
- }
-
- ///
- /// This block sets the current signal level to the specified value (high or low).
- ///
- public class TzxSetSignalLevelDataBlock : TzxDataBlockBase
- {
- ///
- /// Length of the block without these four bytes
- ///
- public uint Lenght { get; } = 1;
-
- ///
- /// Signal level (0=low, 1=high)
- ///
- public byte SignalLevel { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x2B;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- reader.ReadUInt32();
- SignalLevel = reader.ReadByte();
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(Lenght);
- writer.Write(SignalLevel);
- }
- }
-
- ///
- /// Pause (silence) or 'Stop the Tape' block
- ///
- public class TzxSilenceDataBlock : TzxDataBlockBase
- {
- ///
- /// Duration of silence
- ///
- ///
- /// This will make a silence (low amplitude level (0)) for a given time
- /// in milliseconds. If the value is 0 then the emulator or utility should
- /// (in effect) STOP THE TAPE, i.e. should not continue loading until
- /// the user or emulator requests it.
- ///
- public ushort Duration { get; set; }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x20;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- Duration = reader.ReadUInt16();
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(Duration);
- }
- }
-
- ///
- /// This block was created to support the Commodore 64 standard
- /// ROM and similar tape blocks.
- ///
- public class TzxSnapshotBlock : TzxDeprecatedDataBlockBase
- {
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x40;
-
- ///
- /// Reads through the block infromation, and does not store it
- ///
- /// Stream to read the block from
- public override void ReadThrough(BinaryReader reader)
- {
- var length = reader.ReadInt32();
- length = length & 0x00FFFFFF;
- reader.ReadBytes(length);
- }
- }
-
- ///
- /// Represents the standard speed data block in a TZX file
- ///
- public class TzxStandardSpeedDataBlock : TzxDataBlockBase, ISupportsTapeBlockPlayback, ITapeData
- {
- private TapeDataBlockPlayer _player;
-
- ///
- /// Pause after this block (default: 1000ms)
- ///
- public ushort PauseAfter { get; set; } = 1000;
-
- ///
- /// Lenght of block data
- ///
- private ushort dataLength;
- public ushort DataLength
- {
- get { return dataLength; }
- set { dataLength = value; }
- }
-
- ///
- /// Block Data
- ///
- private byte[] data;
- public byte[] Data
- {
- get { return data; }
- set { data = value; }
- }
-
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x10;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- PauseAfter = reader.ReadUInt16();
- DataLength = reader.ReadUInt16();
- Data = reader.ReadBytes(DataLength);
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write((byte)BlockId);
- writer.Write(PauseAfter);
- writer.Write(DataLength);
- writer.Write(Data, 0, DataLength);
- }
-
- ///
- /// The index of the currently playing byte
- ///
- /// This proprty is made public for test purposes
- public int ByteIndex => _player.ByteIndex;
-
- ///
- /// The mask of the currently playing bit in the current byte
- ///
- public byte BitMask => _player.BitMask;
-
- ///
- /// The current playing phase
- ///
- public PlayPhase PlayPhase => _player.PlayPhase;
-
- ///
- /// The tact count of the CPU when playing starts
- ///
- public long StartCycle=> _player.StartCycle;
-
- ///
- /// Last tact queried
- ///
- public long LastTact => _player.LastCycle;
-
- ///
- /// Initializes the player
- ///
- public void InitPlay(long startCycle)
- {
- _player = new TapeDataBlockPlayer(Data, PauseAfter);
- _player.InitPlay(startCycle);
- }
-
- ///
- /// Gets the EAR bit value for the specified tact
- ///
- /// Tacts to retrieve the EAR bit
- ///
- /// The EAR bit value to play back
- ///
- public bool GetEarBit(long currentCycle) => _player.GetEarBit(currentCycle);
-
- public void SyncState(Serializer ser)
- {
- ser.BeginSection("TzxStandardSpeedDataBlock");
-
- ser.Sync("dataLength", ref dataLength);
- ser.Sync("data", ref data, false);
-
- ser.EndSection();
- }
- }
-
- ///
- /// When this block is encountered, the tape will stop ONLY if
- /// the machine is an 48K Spectrum.
- ///
- ///
- /// This block is to be used for multiloading games that load one
- /// level at a time in 48K mode, but load the entire tape at once
- /// if in 128K mode. This block has no body of its own, but follows
- /// the extension rule.
- ///
- public class TzxStopTheTape48DataBlock : TzxDataBlockBase
- {
- ///
- /// Length of the block without these four bytes (0)
- ///
- public uint Lenght { get; } = 0;
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x2A;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- reader.ReadUInt32();
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(Lenght);
- }
- }
-
- ///
- /// This is meant to identify parts of the tape, so you know where level 1 starts,
- /// where to rewind to when the game ends, etc.
- ///
- ///
- /// This description is not guaranteed to be shown while the tape is playing,
- /// but can be read while browsing the tape or changing the tape pointer.
- ///
- public class TzxTextDescriptionDataBlock : TzxDataBlockBase
- {
- ///
- /// Length of the description
- ///
- public byte DescriptionLength { get; set; }
-
- ///
- /// The description bytes
- ///
- public byte[] Description;
-
- ///
- /// The string form of description
- ///
- public string DescriptionText => ToAsciiString(Description);
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x30;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- DescriptionLength = reader.ReadByte();
- Description = reader.ReadBytes(DescriptionLength);
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(DescriptionLength);
- writer.Write(Description);
- }
- }
-
- ///
- /// Represents the standard speed data block in a TZX file
- ///
- public class TzxTurboSpeedDataBlock : Tzx3ByteDataBlockBase
- {
- ///
- /// Length of pilot pulse
- ///
- public ushort PilotPulseLength { get; set; }
-
- ///
- /// Length of the first sync pulse
- ///
- public ushort Sync1PulseLength { get; set; }
-
- ///
- /// Length of the second sync pulse
- ///
- public ushort Sync2PulseLength { get; set; }
-
- ///
- /// Length of the zero bit
- ///
- public ushort ZeroBitPulseLength { get; set; }
-
- ///
- /// Length of the one bit
- ///
- public ushort OneBitPulseLength { get; set; }
-
- ///
- /// Length of the pilot tone
- ///
- public ushort PilotToneLength { get; set; }
-
- ///
- /// Pause after this block
- ///
- public ushort PauseAfter { get; set; }
-
- public TzxTurboSpeedDataBlock()
- {
- PilotPulseLength = 2168;
- Sync1PulseLength = 667;
- Sync2PulseLength = 735;
- ZeroBitPulseLength = 855;
- OneBitPulseLength = 1710;
- PilotToneLength = 8063;
- LastByteUsedBits = 8;
- }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x11;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- PilotPulseLength = reader.ReadUInt16();
- Sync1PulseLength = reader.ReadUInt16();
- Sync2PulseLength = reader.ReadUInt16();
- ZeroBitPulseLength = reader.ReadUInt16();
- OneBitPulseLength = reader.ReadUInt16();
- PilotToneLength = reader.ReadUInt16();
- LastByteUsedBits = reader.ReadByte();
- PauseAfter = reader.ReadUInt16();
- DataLength = reader.ReadBytes(3);
- Data = reader.ReadBytes(GetLength());
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(PilotPulseLength);
- writer.Write(Sync1PulseLength);
- writer.Write(Sync2PulseLength);
- writer.Write(ZeroBitPulseLength);
- writer.Write(OneBitPulseLength);
- writer.Write(PilotToneLength);
- writer.Write(LastByteUsedBits);
- writer.Write(PauseAfter);
- writer.Write(DataLength);
- writer.Write(Data);
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/Info.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/Info.cs
deleted file mode 100644
index 0a83aa3bfc..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/Info.cs
+++ /dev/null
@@ -1,250 +0,0 @@
-
-using System.IO;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This blocks contains information about the hardware that the programs on this tape use.
- ///
- public class TzxHwInfo : ITapeDataSerialization
- {
- ///
- /// Hardware type
- ///
- public byte HwType { get; set; }
-
- ///
- /// Hardwer Id
- ///
- public byte HwId { get; set; }
-
- ///
- /// Information about the tape
- ///
- ///
- /// 00 - The tape RUNS on this machine or with this hardware,
- /// but may or may not use the hardware or special features of the machine.
- /// 01 - The tape USES the hardware or special features of the machine,
- /// such as extra memory or a sound chip.
- /// 02 - The tape RUNS but it DOESN'T use the hardware
- /// or special features of the machine.
- /// 03 - The tape DOESN'T RUN on this machine or with this hardware.
- ///
- public byte TapeInfo;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public void ReadFrom(BinaryReader reader)
- {
- HwType = reader.ReadByte();
- HwId = reader.ReadByte();
- TapeInfo = reader.ReadByte();
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public void WriteTo(BinaryWriter writer)
- {
- writer.Write(HwType);
- writer.Write(HwId);
- writer.Write(TapeInfo);
- }
- }
-
- ///
- /// Symbol repetitions
- ///
- public struct TzxPrle
- {
- ///
- /// Symbol represented
- ///
- public byte Symbol;
-
- ///
- /// Number of repetitions
- ///
- public ushort Repetitions;
- }
-
- ///
- /// This block represents an extremely wide range of data encoding techniques.
- ///
- ///
- /// The basic idea is that each loading component (pilot tone, sync pulses, data)
- /// is associated to a specific sequence of pulses, where each sequence (wave) can
- /// contain a different number of pulses from the others. In this way we can have
- /// a situation where bit 0 is represented with 4 pulses and bit 1 with 8 pulses.
- ///
- public class TzxSymDef : ITapeDataSerialization
- {
- ///
- /// Bit 0 - Bit 1: Starting symbol polarity
- ///
- ///
- /// 00: opposite to the current level (make an edge, as usual) - default
- /// 01: same as the current level(no edge - prolongs the previous pulse)
- /// 10: force low level
- /// 11: force high level
- ///
- public byte SymbolFlags;
-
- ///
- /// The array of pulse lengths
- ///
- public ushort[] PulseLengths;
-
- public TzxSymDef(byte maxPulses)
- {
- PulseLengths = new ushort[maxPulses];
- }
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public void ReadFrom(BinaryReader reader)
- {
- SymbolFlags = reader.ReadByte();
- PulseLengths = TzxDataBlockBase.ReadWords(reader, PulseLengths.Length);
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public void WriteTo(BinaryWriter writer)
- {
- writer.Write(SymbolFlags);
- TzxDataBlockBase.WriteWords(writer, PulseLengths);
- }
- }
-
- ///
- /// This is meant to identify parts of the tape, so you know where level 1 starts,
- /// where to rewind to when the game ends, etc.
- ///
- ///
- /// This description is not guaranteed to be shown while the tape is playing,
- /// but can be read while browsing the tape or changing the tape pointer.
- ///
- public class TzxText : ITapeDataSerialization
- {
- ///
- /// Text identification byte.
- ///
- ///
- /// 00 - Full title
- /// 01 - Software house/publisher
- /// 02 - Author(s)
- /// 03 - Year of publication
- /// 04 - Language
- /// 05 - Game/utility type
- /// 06 - Price
- /// 07 - Protection scheme/loader
- /// 08 - Origin
- /// FF - Comment(s)
- ///
- public byte Type { get; set; }
-
- ///
- /// Length of the description
- ///
- public byte Length { get; set; }
-
- ///
- /// The description bytes
- ///
- public byte[] TextBytes;
-
- ///
- /// The string form of description
- ///
- public string Text => TzxDataBlockBase.ToAsciiString(TextBytes);
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public void ReadFrom(BinaryReader reader)
- {
- Type = reader.ReadByte();
- Length = reader.ReadByte();
- TextBytes = reader.ReadBytes(Length);
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public void WriteTo(BinaryWriter writer)
- {
- writer.Write(Type);
- writer.Write(Length);
- writer.Write(TextBytes);
- }
- }
-
- ///
- /// This block represents select structure
- ///
- public class TzxSelect : ITapeDataSerialization
- {
- ///
- /// Bit 0 - Bit 1: Starting symbol polarity
- ///
- ///
- /// 00: opposite to the current level (make an edge, as usual) - default
- /// 01: same as the current level(no edge - prolongs the previous pulse)
- /// 10: force low level
- /// 11: force high level
- ///
- public ushort BlockOffset;
-
- ///
- /// Length of the description
- ///
- public byte DescriptionLength { get; set; }
-
- ///
- /// The description bytes
- ///
- public byte[] Description;
-
- ///
- /// The string form of description
- ///
- public string DescriptionText => TzxDataBlockBase.ToAsciiString(Description);
-
- public TzxSelect(byte length)
- {
- DescriptionLength = length;
- }
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public void ReadFrom(BinaryReader reader)
- {
- BlockOffset = reader.ReadUInt16();
- DescriptionLength = reader.ReadByte();
- Description = reader.ReadBytes(DescriptionLength);
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public void WriteTo(BinaryWriter writer)
- {
- writer.Write(BlockOffset);
- writer.Write(DescriptionLength);
- writer.Write(Description);
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/Types.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/Types.cs
deleted file mode 100644
index 8742a35679..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/Types.cs
+++ /dev/null
@@ -1,282 +0,0 @@
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Identified AD or DA converter types
- ///
- public enum TzxAdOrDaConverterType : byte
- {
- HarleySystemsAdc8P2 = 0x00,
- BlackboardElectronics = 0x01
- }
-
- ///
- /// Identified computer types
- ///
- public enum TzxComputerType : byte
- {
- ZxSpectrum16 = 0x00,
- ZxSpectrum48OrPlus = 0x01,
- ZxSpectrum48Issue1 = 0x02,
- ZxSpectrum128 = 0x03,
- ZxSpectrum128P2 = 0x04,
- ZxSpectrum128P2AOr3 = 0x05,
- Tc2048 = 0x06,
- Ts2068 = 0x07,
- Pentagon128 = 0x08,
- SamCoupe = 0x09,
- DidaktikM = 0x0A,
- DidaktikGama = 0x0B,
- Zx80 = 0x0C,
- Zx81 = 0x0D,
- ZxSpectrum128Spanish = 0x0E,
- ZxSpectrumArabic = 0x0F,
- Tk90X = 0x10,
- Tk95 = 0x11,
- Byte = 0x12,
- Elwro800D3 = 0x13,
- ZsScorpion256 = 0x14,
- AmstradCpc464 = 0x15,
- AmstradCpc664 = 0x16,
- AmstradCpc6128 = 0x17,
- AmstradCpc464P = 0x18,
- AmstradCpc6128P = 0x19,
- JupiterAce = 0x1A,
- Enterprise = 0x1B,
- Commodore64 = 0x1C,
- Commodore128 = 0x1D,
- InvesSpectrumP = 0x1E,
- Profi = 0x1F,
- GrandRomMax = 0x20,
- Kay1024 = 0x21,
- IceFelixHc91 = 0x22,
- IceFelixHc2000 = 0x23,
- AmaterskeRadioMistrum = 0x24,
- Quorum128 = 0x25,
- MicroArtAtm = 0x26,
- MicroArtAtmTurbo2 = 0x27,
- Chrome = 0x28,
- ZxBadaloc = 0x29,
- Ts1500 = 0x2A,
- Lambda = 0x2B,
- Tk65 = 0x2C,
- Zx97 = 0x2D
- }
-
- ///
- /// Identified digitizer types
- ///
- public enum TzxDigitizerType : byte
- {
- RdDigitalTracer = 0x00,
- DkTronicsLightPen = 0x01,
- MicrographPad = 0x02,
- RomnticRobotVideoface = 0x03
- }
-
- ///
- /// Identified EPROM programmer types
- ///
- public enum TzxEpromProgrammerType : byte
- {
- OrmeElectronics = 0x00
- }
-
- ///
- /// Identified external storage types
- ///
- public enum TzxExternalStorageType : byte
- {
- ZxMicroDrive = 0x00,
- OpusDiscovery = 0x01,
- MgtDisciple = 0x02,
- MgtPlusD = 0x03,
- RobotronicsWafaDrive = 0x04,
- TrDosBetaDisk = 0x05,
- ByteDrive = 0x06,
- Watsford = 0x07,
- Fiz = 0x08,
- Radofin = 0x09,
- DidaktikDiskDrive = 0x0A,
- BsDos = 0x0B,
- ZxSpectrumP3DiskDrive = 0x0C,
- JloDiskInterface = 0x0D,
- TimexFdd3000 = 0x0E,
- ZebraDiskDrive = 0x0F,
- RamexMillenia = 0x10,
- Larken = 0x11,
- KempstonDiskInterface = 0x12,
- Sandy = 0x13,
- ZxSpectrumP3EHardDisk = 0x14,
- ZxAtaSp = 0x15,
- DivIde = 0x16,
- ZxCf = 0x17
- }
-
- ///
- /// Identified graphics types
- ///
- public enum TzxGraphicsType : byte
- {
- WrxHiRes = 0x00,
- G007 = 0x01,
- Memotech = 0x02,
- LambdaColour = 0x03
- }
-
- ///
- /// Represents the hardware types that can be defined
- ///
- public enum TzxHwType : byte
- {
- Computer = 0x00,
- ExternalStorage = 0x01,
- RomOrRamTypeAddOn = 0x02,
- SoundDevice = 0x03,
- JoyStick = 0x04,
- Mouse = 0x05,
- OtherController = 0x06,
- SerialPort = 0x07,
- ParallelPort = 0x08,
- Printer = 0x09,
- Modem = 0x0A,
- Digitizer = 0x0B,
- NetworkAdapter = 0x0C,
- Keyboard = 0x0D,
- AdOrDaConverter = 0x0E,
- EpromProgrammer = 0x0F,
- Graphics = 0x10
- }
-
- ///
- /// Identified joystick types
- ///
- public enum TzxJoystickType
- {
- Kempston = 0x00,
- ProtekCursor = 0x01,
- Sinclair2Left = 0x02,
- Sinclair1Right = 0x03,
- Fuller = 0x04
- }
-
- ///
- /// Identified keyboard and keypad types
- ///
- public enum TzxKeyboardType : byte
- {
- KeypadForZxSpectrum128K = 0x00
- }
-
- ///
- /// Identified modem types
- ///
- public enum TzxModemTypes : byte
- {
- PrismVtx5000 = 0x00,
- Westridge2050 = 0x01
- }
-
- ///
- /// Identified mouse types
- ///
- public enum TzxMouseType : byte
- {
- AmxMouse = 0x00,
- KempstonMouse = 0x01
- }
-
- ///
- /// Identified network adapter types
- ///
- public enum TzxNetworkAdapterType : byte
- {
- ZxInterface1 = 0x00
- }
-
- ///
- /// Identified other controller types
- ///
- public enum TzxOtherControllerType : byte
- {
- Trisckstick = 0x00,
- ZxLightGun = 0x01,
- ZebraGraphicTablet = 0x02,
- DefnederLightGun = 0x03
- }
-
- ///
- /// Identified parallel port types
- ///
- public enum TzxParallelPortType : byte
- {
- KempstonS = 0x00,
- KempstonE = 0x01,
- ZxSpectrum3P = 0x02,
- Tasman = 0x03,
- DkTronics = 0x04,
- Hilderbay = 0x05,
- InesPrinterface = 0x06,
- ZxLprintInterface3 = 0x07,
- MultiPrint = 0x08,
- OpusDiscovery = 0x09,
- Standard8255 = 0x0A
- }
-
- ///
- /// Identified printer types
- ///
- public enum TzxPrinterType : byte
- {
- ZxPrinter = 0x00,
- GenericPrinter = 0x01,
- EpsonCompatible = 0x02
- }
-
- ///
- /// Identifier ROM or RAM add-on types
- ///
- public enum TzxRomRamAddOnType : byte
- {
- SamRam = 0x00,
- MultifaceOne = 0x01,
- Multiface128K = 0x02,
- MultifaceP3 = 0x03,
- MultiPrint = 0x04,
- Mb02 = 0x05,
- SoftRom = 0x06,
- Ram1K = 0x07,
- Ram16K = 0x08,
- Ram48K = 0x09,
- Mem8To16KUsed = 0x0A
- }
-
- ///
- /// Identified serial port types
- ///
- public enum TzxSerialPortType : byte
- {
- ZxInterface1 = 0x00,
- ZxSpectrum128 = 0x01
- }
-
- ///
- /// Identified sound device types
- ///
- public enum TzxSoundDeviceType : byte
- {
- ClassicAy = 0x00,
- FullerBox = 0x01,
- CurrahMicroSpeech = 0x02,
- SpectDrum = 0x03,
- MelodikAyAcbStereo = 0x04,
- AyAbcStereo = 0x05,
- RamMusinMachine = 0x06,
- Covox = 0x07,
- GeneralSound = 0x08,
- IntecEdiB8001 = 0x09,
- ZonXAy = 0x0A,
- QuickSilvaAy = 0x0B,
- JupiterAce = 0x0C
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxException.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxException.cs
deleted file mode 100644
index 8ebe4921e5..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxException.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This class represents a TZX-related exception
- ///
- public class TzxException : Exception
- {
- ///
- /// Initializes the exception with the specified message
- ///
- /// Exception message
- public TzxException(string message) : base(message)
- {
- }
-
- ///
- /// Initializes the exception with the specified message
- /// and inner exception
- ///
- /// Exception message
- /// Inner exception
- public TzxException(string message, Exception innerException) : base(message, innerException)
- {
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxHeader.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxHeader.cs
deleted file mode 100644
index e6901b4d7b..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxHeader.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.IO;
-using System.Linq;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Represents the header of the TZX file
- ///
- public class TzxHeader : TzxDataBlockBase
- {
- public static IReadOnlyList TzxSignature =
- new ReadOnlyCollection(new byte[] { 0x5A, 0x58, 0x54, 0x61, 0x70, 0x65, 0x21 });
- public byte[] Signature { get; private set; }
- public byte Eot { get; private set; }
- public byte MajorVersion { get; private set; }
- public byte MinorVersion { get; private set; }
-
- public TzxHeader(byte majorVersion = 1, byte minorVersion = 20)
- {
- Signature = TzxSignature.ToArray();
- Eot = 0x1A;
- MajorVersion = majorVersion;
- MinorVersion = minorVersion;
- }
-
- ///
- /// The ID of the block
- ///
- public override int BlockId => 0x00;
-
- ///
- /// Reads the content of the block from the specified binary stream.
- ///
- /// Stream to read the block from
- public override void ReadFrom(BinaryReader reader)
- {
- Signature = reader.ReadBytes(7);
- Eot = reader.ReadByte();
- MajorVersion = reader.ReadByte();
- MinorVersion = reader.ReadByte();
- }
-
- ///
- /// Writes the content of the block to the specified binary stream.
- ///
- /// Stream to write the block to
- public override void WriteTo(BinaryWriter writer)
- {
- writer.Write(Signature);
- writer.Write(Eot);
- writer.Write(MajorVersion);
- writer.Write(MinorVersion);
- }
-
- #region Overrides of TzxDataBlockBase
-
- ///
- /// Override this method to check the content of the block
- ///
- public override bool IsValid => Signature.SequenceEqual(TzxSignature)
- && Eot == 0x1A
- && MajorVersion == 1;
-
- #endregion
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxPlayer.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxPlayer.cs
deleted file mode 100644
index a9ac846467..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxPlayer.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-using BizHawk.Common;
-using System.IO;
-using System.Linq;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This class is responsible to "play" a TZX file.
- ///
- public class TzxPlayer : TzxReader, ISupportsTapeBlockPlayback
- {
- private TapeBlockSetPlayer _player;
-
- ///
- /// 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 TZX file data from
- public TzxPlayer(BinaryReader reader) : base(reader)
- {
- }
-
- ///
- /// Reads in the content of the TZX file so that it can be played
- ///
- /// True, if read was successful; otherwise, false
- public override bool ReadContent()
- {
- var success = base.ReadContent();
- var blocks = DataBlocks.Where(b => b is ISupportsTapeBlockPlayback)
- .Cast()
- .ToList();
- _player = new TapeBlockSetPlayer(blocks);
- return success;
- }
-
- ///
- /// 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 startTact)
- {
- _player.InitPlay(startTact);
- }
-
- ///
- /// Gets the EAR bit value for the specified tact
- ///
- /// 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 currentTact) => _player.GetEarBit(currentTact);
-
- ///
- /// Moves the current block index to the next playable block
- ///
- /// Tacts time to start the next block
- public void NextBlock(long currentTact) => _player.NextBlock(currentTact);
-
-
- public void SyncState(Serializer ser)
- {
- ser.BeginSection("TzxPlayer");
-
- _player.SyncState(ser);
-
- ser.EndSection();
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxReader.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxReader.cs
deleted file mode 100644
index ad7ea786ab..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxReader.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This class reads a TZX file
- ///
- public class TzxReader
- {
- private readonly BinaryReader _reader;
-
- public static Dictionary DataBlockTypes = new Dictionary
- {
- {0x10, typeof(TzxStandardSpeedDataBlock)},
- {0x11, typeof(TzxTurboSpeedDataBlock)},
- {0x12, typeof(TzxPureToneDataBlock)},
- {0x13, typeof(TzxPulseSequenceDataBlock)},
- {0x14, typeof(TzxPureDataBlock)},
- {0x15, typeof(TzxDirectRecordingDataBlock)},
- {0x16, typeof(TzxC64RomTypeDataBlock)},
- {0x17, typeof(TzxC64TurboTapeDataBlock)},
- {0x18, typeof(TzxCswRecordingDataBlock)},
- {0x19, typeof(TzxGeneralizedDataBlock)},
- {0x20, typeof(TzxSilenceDataBlock)},
- {0x21, typeof(TzxGroupStartDataBlock)},
- {0x22, typeof(TzxGroupEndDataBlock)},
- {0x23, typeof(TzxJumpDataBlock)},
- {0x24, typeof(TzxLoopStartDataBlock)},
- {0x25, typeof(TzxLoopEndDataBlock)},
- {0x26, typeof(TzxCallSequenceDataBlock)},
- {0x27, typeof(TzxReturnFromSequenceDataBlock)},
- {0x28, typeof(TzxSelectDataBlock)},
- {0x2A, typeof(TzxStopTheTape48DataBlock)},
- {0x2B, typeof(TzxSetSignalLevelDataBlock)},
- {0x30, typeof(TzxTextDescriptionDataBlock)},
- {0x31, typeof(TzxMessageDataBlock)},
- {0x32, typeof(TzxArchiveInfoDataBlock)},
- {0x33, typeof(TzxHardwareInfoDataBlock)},
- {0x34, typeof(TzxEmulationInfoDataBlock)},
- {0x35, typeof(TzxCustomInfoDataBlock)},
- {0x40, typeof(TzxSnapshotBlock)},
- {0x5A, typeof(TzxGlueDataBlock)},
- };
-
- ///
- /// Data blocks of this TZX file
- ///
- public IList DataBlocks { get; }
-
- ///
- /// Major version number of the file
- ///
- public byte MajorVersion { get; private set; }
-
- ///
- /// Minor version number of the file
- ///
- public byte MinorVersion { get; private set; }
-
- ///
- /// Initializes the player from the specified reader
- ///
- ///
- public TzxReader(BinaryReader reader)
- {
- _reader = reader;
- DataBlocks = new List();
- }
-
- ///
- /// Reads in the content of the TZX file so that it can be played
- ///
- /// True, if read was successful; otherwise, false
- public virtual bool ReadContent()
- {
- var header = new TzxHeader();
- try
- {
- header.ReadFrom(_reader);
- if (!header.IsValid)
- {
- throw new TzxException("Invalid TZX header");
- }
- MajorVersion = header.MajorVersion;
- MinorVersion = header.MinorVersion;
-
- while (_reader.BaseStream.Position != _reader.BaseStream.Length)
- {
- var blockType = _reader.ReadByte();
- Type type;
- if (!DataBlockTypes.TryGetValue(blockType, out type))
- {
- throw new TzxException($"Unkonwn TZX block type: {blockType}");
- }
-
- try
- {
- var block = Activator.CreateInstance(type) as TzxDataBlockBase;
- if (block.GetType() == typeof(TzxDeprecatedDataBlockBase))
- {
- ((TzxDeprecatedDataBlockBase)block as TzxDeprecatedDataBlockBase).ReadThrough(_reader);
- }
- else
- {
- block?.ReadFrom(_reader);
- }
- DataBlocks.Add(block);
- }
- catch (Exception ex)
- {
- throw new TzxException($"Cannot read TZX data block {type}.", ex);
- }
- }
- return true;
- }
- catch
- {
- // --- This exception is intentionally ignored
- return false;
- }
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/readme.md b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/readme.md
index afcf6b122f..f4f78dd4fc 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/readme.md
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/readme.md
@@ -1,6 +1,6 @@
## ZXHawk
-At this moment this is still *very* experimental and needs a lot more work.
+At the moment this is very experimental and is still actively being worked on.
### Implemented and sorta working
* IEmulator
@@ -13,21 +13,23 @@ At this moment this is still *very* experimental and needs a lot more work.
* Keyboard input (implementing IInputPollable)
* Kempston joystick (mapped to J1 currently)
* Tape device that will load spectrum games in realtime (*.tzx and *.tap)
+* Most tape protection/loading schemes that I've tested are currently working (see caveat below)
* IStatable
* ISettable core settings
-* IMemoryDomains (I think)
### Work in progress
* Exact emulator timings
* Floating memory bus emulation
* Tape auto-loading routines (currently you have to manually start and stop the virtual tape device)
+* TASStudio (need to verify that this works as it should)
### Not working
-* IDebuggable
+* IDebuggable (probably IMemoryDomains is setup incorrectly)
* ZX Spectrum Plus3 emulation
* Default keyboard keymappings (you have to configure yourself in the core controller settings)
### Known bugs
-* Audible 'popping' from the emulated buzzer after a load state operation
+* Audible 'popping' from the emulated buzzer after a load state operation (maybe this is a normal thing)
+* Speedlock tape protection scheme doesn't appear to load correctly
-Asnivor