private int ReverseReadAudio(byte[] buffer, int offset, int samplesRequested) { int totalSamplesWritten = 0; int currentSamplesRequested = samplesRequested; lock (_snapshots) { SnapshotInfo currentSnapshot = _snapshots.LastOrDefault(); while (totalSamplesWritten < samplesRequested && currentSnapshot != null) { int samplesWritten = currentSnapshot.AudioBuffer.Render16BitStereo(Volume, buffer, offset, currentSamplesRequested, true); if (samplesWritten == 0) { _core.PushRequest(CoreRequest.RevertToSnapshot(currentSnapshot.Id, currentSnapshot)); _core.PushRequest(CoreRequest.DeleteSnapshot(currentSnapshot.Id)); _snapshots.RemoveAt(_snapshots.Count - 1); currentSnapshot = _snapshots.LastOrDefault(); } totalSamplesWritten += samplesWritten; currentSamplesRequested -= samplesWritten; offset += 4 * samplesWritten; } } return(totalSamplesWritten); }
static public void CoreRequestToBytes(MemoryByteStream stream, CoreRequest request) { switch (request.Type) { case CoreRequest.Types.KeyPress: stream.Write(_coreActionKeyPress); stream.Write(request.KeyCode); stream.Write(request.KeyDown); break; case CoreRequest.Types.Reset: stream.Write(_coreActionReset); break; case CoreRequest.Types.LoadDisc: stream.Write(_coreActionLoadDisc); stream.Write(request.Drive); stream.WriteArray(request.MediaBuffer.GetBytes()); break; case CoreRequest.Types.LoadTape: stream.Write(_coreActionLoadTape); stream.WriteArray(request.MediaBuffer.GetBytes()); break; case CoreRequest.Types.RunUntil: stream.Write(_coreActionRunUntil); stream.Write(request.StopTicks); break; case CoreRequest.Types.LoadCore: stream.Write(_coreActionLoadCore); stream.WriteArray(request.CoreState.GetBytes()); break; case CoreRequest.Types.CoreVersion: stream.Write(_coreActionCoreVersion); stream.Write(request.Version); break; case CoreRequest.Types.CreateSnapshot: stream.Write(_coreActionCreateSnapshot); stream.Write(request.SnapshotId); break; case CoreRequest.Types.DeleteSnapshot: stream.Write(_coreActionDeleteSnapshot); stream.Write(request.SnapshotId); break; case CoreRequest.Types.RevertToSnapshot: stream.Write(_coreActionRevertToSnapshot); stream.Write(request.SnapshotId); break; default: throw new Exception(String.Format("Unknown CoreRequest type {0}!", request.Type)); } }
public void PushRequest(CoreRequest request) { lock (_requests) { _requests.Enqueue(request); _requestQueueNonEmpty.Set(); } }
private void TakeSnapshot() { if (SnapshotLimit > 0) { int snapshotId = ++_lastTakenSnapshotId; _core.PushRequest(CoreRequest.CreateSnapshot(snapshotId)); } }
private void OnNewMessage(byte[] msg) { MemoryByteStream bs = new MemoryByteStream(msg); byte id = bs.ReadByte(); switch (id) { case _idSelectMachine: { string machineName = Serializer.SelectMachineFromBytes(bs); ReceiveSelectMachine?.Invoke(machineName); } break; case _idAvailableMachines: { List <string> machines = Serializer.AvailableMachinesFromBytes(bs); ReceiveAvailableMachines?.Invoke(machines); } break; case _idCoreAction: { CoreAction coreAction = Serializer.CoreActionFromBytes(bs); ReceiveCoreAction?.Invoke(coreAction); } break; case _idPing: { bool response = bs.ReadBool(); UInt64 pid = bs.ReadUInt64(); ReceivePing?.Invoke(response, pid); } break; case _idRequestAvailableMachines: { ReceiveRequestAvailableMachines?.Invoke(); } break; case _idName: { string machineName = bs.ReadString(); ReceiveName?.Invoke(machineName); } break; case _idCoreRequest: { CoreRequest coreRequest = Serializer.CoreRequestFromBytes(bs); ReceiveCoreRequest?.Invoke(coreRequest); } break; } }
public void SendCoreRequest(CoreRequest coreRequest) { MemoryByteStream bs = new MemoryByteStream(); bs.Write(_idCoreRequest); Serializer.CoreRequestToBytes(bs, coreRequest); SendMessage(bs.AsBytes()); }
static public CoreRequest DeleteSnapshot(Int32 snapshotId) { CoreRequest request = new CoreRequest(Types.DeleteSnapshot) { SnapshotId = snapshotId }; return(request); }
static public CoreRequest RunUntil(UInt64 stopTicks) { CoreRequest request = new CoreRequest(Types.RunUntil) { StopTicks = stopTicks }; return(request); }
static public CoreRequest LoadTape(byte[] buffer) { CoreRequest request = new CoreRequest(Types.LoadTape) { MediaBuffer = new MemoryBlob((byte[])buffer?.Clone()) }; return(request); }
static public CoreRequest CoreVersion(int version) { CoreRequest request = new CoreRequest(Types.CoreVersion) { Version = version }; return(request); }
static public CoreRequest LoadCore(IBlob state) { CoreRequest request = new CoreRequest(Types.LoadCore) { CoreState = state }; return(request); }
static public CoreRequest CreateSnapshot(Int32 parentSnapshotId) { CoreRequest request = new CoreRequest(Types.CreateSnapshot) { SnapshotId = parentSnapshotId }; return(request); }
static public CoreRequest RevertToSnapshot(Int32 snapshotId, object userData) { CoreRequest request = new CoreRequest(Types.RevertToSnapshot) { SnapshotId = snapshotId, UserData = userData }; return(request); }
static public CoreRequest LoadDisc(byte drive, byte[] buffer) { CoreRequest request = new CoreRequest(Types.LoadDisc) { Drive = drive, MediaBuffer = new MemoryBlob((byte[])buffer?.Clone()) }; return(request); }
static public CoreRequest KeyPress(byte keycode, bool down) { CoreRequest request = new CoreRequest(Types.KeyPress) { KeyCode = keycode, KeyDown = down }; return(request); }
private void RequestProcessed(Core core, CoreRequest request, CoreAction action) { if (core == _core && action != null) { if (action.Type == CoreAction.Types.RevertToSnapshot) { // Ensure to update the display. Display.CopyScreenAsync(); } } }
private void SeekToBookmark(int bookmarkEventIndex) { Core core; int startIndex = 0; // First find the bookmark. if (bookmarkEventIndex == -1) { core = Core.Create(Core.LatestVersion, Core.Type.CPC6128); Display.GetFromBookmark(null); } else { Bookmark bookmark = (_historyEvents[bookmarkEventIndex] as BookmarkHistoryEvent).Bookmark; core = Core.Create(bookmark.Version, bookmark.State.GetBytes()); Display.GetFromBookmark(bookmark); startIndex = bookmarkEventIndex; } for (int i = startIndex; i < _historyEvents.Count; i++) { HistoryEvent historyEvent = _historyEvents[i]; if (historyEvent is CoreActionHistoryEvent coreActionHistoryEvent) { core.PushRequest(CoreRequest.RunUntil(coreActionHistoryEvent.Ticks)); core.PushRequest(coreActionHistoryEvent.CoreAction); } } core.PushRequest(CoreRequest.RunUntil(_endTicks)); Core = core; Core.Auditors = RequestProcessed; Core.IdleRequest += IdleRequest; SetCoreRunning(); }
/// <summary> /// Asynchronously loads a tape and begins playing it. /// </summary> /// <param name="tapeImage">A byte array containing an uncompressed .CDT image.</param> public void LoadTape(byte[] tapeImage) { PushRequest(CoreRequest.LoadTape(tapeImage)); }
private bool ProcessNextRequest() { bool success = true; CoreRequest firstRequest = FirstRequest(); bool removeFirst = true; CoreRequest request = firstRequest; CoreAction action = null; if (request == null) { removeFirst = false; if (IdleRequest != null) { request = IdleRequest(); } if (request == null) { _requestQueueNonEmpty.WaitOne(20); return(false); } } UInt64 ticks = Ticks; switch (request.Type) { case CoreRequest.Types.KeyPress: lock (_lockObject) { if (_coreCLR.KeyPress(request.KeyCode, request.KeyDown)) { action = CoreAction.KeyPress(ticks, request.KeyCode, request.KeyDown); } } break; case CoreRequest.Types.Reset: lock (_lockObject) { _coreCLR.Reset(); } action = CoreAction.Reset(ticks); break; case CoreRequest.Types.LoadDisc: lock (_lockObject) { _coreCLR.LoadDisc(request.Drive, request.MediaBuffer.GetBytes()); } action = CoreAction.LoadDisc(ticks, request.Drive, request.MediaBuffer); break; case CoreRequest.Types.LoadTape: lock (_lockObject) { _coreCLR.LoadTape(request.MediaBuffer.GetBytes()); } action = CoreAction.LoadTape(ticks, request.MediaBuffer); break; case CoreRequest.Types.RunUntil: { action = RunForAWhile(request.StopTicks); success = (request.StopTicks <= Ticks); } break; case CoreRequest.Types.CoreVersion: lock (_lockObject) { byte[] state = GetState(); ICore newCore = Core.CreateVersionedCore(request.Version); newCore.LoadState(state); newCore.SetScreen(Display.Pitch, Display.Height, Display.Width); _coreCLR.Dispose(); _coreCLR = newCore; } break; case CoreRequest.Types.LoadCore: lock (_lockObject) { _coreCLR.LoadState(request.CoreState.GetBytes()); } action = CoreAction.LoadCore(ticks, request.CoreState); break; case CoreRequest.Types.CreateSnapshot: lock (_lockObject) { action = CreateSnapshot(request.SnapshotId); } break; case CoreRequest.Types.DeleteSnapshot: lock (_lockObject) { action = DeleteSnapshot(request.SnapshotId); } break; case CoreRequest.Types.RevertToSnapshot: lock (_lockObject) { action = RevertToSnapshot(request.SnapshotId); } break; default: Diagnostics.Trace("Unknown core request type {0}. Ignoring request.", request.Type); break; } if (removeFirst && success) { RemoveFirstRequest(); } Auditors?.Invoke(this, request, action); return(false); }
private void ReceiveCoreRequest(CoreRequest request) { _machine.Core.PushRequest(request); }
public void LoadTape(byte[] tapeBuffer) { _remote.SendCoreRequest(CoreRequest.LoadTape(tapeBuffer)); }
public void Reset() { _remote.SendCoreRequest(CoreRequest.Reset()); }
static public CoreRequest CoreRequestFromBytes(MemoryByteStream stream) { byte type = stream.ReadByte(); switch (type) { case _coreActionKeyPress: { byte keyCode = stream.ReadByte(); bool keyDown = stream.ReadBool(); return(CoreRequest.KeyPress(keyCode, keyDown)); } case _coreActionReset: { return(CoreRequest.Reset()); } case _coreActionLoadDisc: { byte drive = stream.ReadByte(); byte[] media = stream.ReadArray(); return(CoreRequest.LoadDisc(drive, media)); } case _coreActionLoadTape: { byte[] media = stream.ReadArray(); return(CoreRequest.LoadTape(media)); } case _coreActionRunUntil: { UInt64 stopTicks = stream.ReadUInt64(); return(CoreRequest.RunUntil(stopTicks)); } case _coreActionLoadCore: { byte[] state = stream.ReadArray(); return(CoreRequest.LoadCore(new MemoryBlob(state))); } case _coreActionCoreVersion: { Int32 version = stream.ReadInt32(); return(CoreRequest.CoreVersion(version)); } case _coreActionCreateSnapshot: { Int32 snapshotId = stream.ReadInt32(); return(CoreRequest.CreateSnapshot(snapshotId)); } case _coreActionDeleteSnapshot: { Int32 snapshotId = stream.ReadInt32(); return(CoreRequest.DeleteSnapshot(snapshotId)); } case _coreActionRevertToSnapshot: { Int32 snapshotId = stream.ReadInt32(); return(CoreRequest.RevertToSnapshot(snapshotId, null)); } default: throw new Exception(String.Format("Unknown CoreRequest type {0}!", type)); } }
/// <summary> /// Delegate for logging core actions. /// </summary> /// <param name="core">The core the request was made for.</param> /// <param name="request">The original request.</param> /// <param name="action">The action taken.</param> private void RequestProcessed(Core core, CoreRequest request, CoreAction action) { Auditors?.Invoke(action); }
public CoreRequest IdleRequest() { return((RunningState == RunningState.Running) ? CoreRequest.RunUntil(Ticks + 1000) : null); }
/// <summary> /// Asynchronously loads a disc. /// </summary> /// <param name="drive">Specifies which drive to load. 0 for drive A and 1 for drive B.</param> /// <param name="discImage">A byte array containing an uncompressed .DSK image.</param> public void LoadDisc(byte drive, byte[] discImage) { PushRequest(CoreRequest.LoadDisc(drive, discImage)); }
public void Key(byte keycode, bool down) { _remote.SendCoreRequest(CoreRequest.KeyPress(keycode, down)); }
public void LoadDisc(byte drive, byte[] diskBuffer) { _remote.SendCoreRequest(CoreRequest.LoadDisc(drive, diskBuffer)); }
/// <summary> /// Delegate for logging core actions. /// </summary> /// <param name="core">The core the request was made for.</param> /// <param name="request">The original request.</param> /// <param name="action">The action taken.</param> private void RequestProcessed(Core core, CoreRequest request, CoreAction action) { if (core == _core) { if (action != null) { Auditors?.Invoke(action); if (action.Type != CoreAction.Types.CreateSnapshot && action.Type != CoreAction.Types.DeleteSnapshot && action.Type != CoreAction.Types.RevertToSnapshot) { HistoryEvent e = _history.AddCoreAction(action); switch (action.Type) { case CoreRequest.Types.LoadDisc: Status = (action.MediaBuffer.GetBytes() != null) ? "Loaded disc" : "Ejected disc"; break; case CoreRequest.Types.LoadTape: Status = (action.MediaBuffer.GetBytes() != null) ? "Loaded tape" : "Ejected tape"; break; case CoreRequest.Types.Reset: Status = "Reset"; break; } } if (action.Type == CoreAction.Types.RunUntil) { lock (_snapshots) { SnapshotInfo newSnapshot = _snapshots.LastOrDefault(); if (newSnapshot != null && action.AudioSamples != null) { newSnapshot.AudioBuffer.Write(action.AudioSamples); } } } else if (action.Type == CoreAction.Types.RevertToSnapshot) { HistoryEvent historyEvent = ((SnapshotInfo)request.UserData).HistoryEvent; if (_history.CurrentEvent != historyEvent) { _history.CurrentEvent = historyEvent; } Display.CopyScreenAsync(); } else if (action.Type == CoreAction.Types.CreateSnapshot) { lock (_snapshots) { // Figure out what history event should be set as current if we revert to this snapshot. // If the current event is a RunUntil, it may not be "finalized" yet (i.e. it may still // be updated), so go with its parent. HistoryEvent historyEvent = _history.MostRecentClosedEvent(_history.CurrentEvent); SnapshotInfo newSnapshot = new SnapshotInfo(action.SnapshotId, historyEvent); _snapshots.Add(newSnapshot); while (_snapshots.Count > _snapshotLimit) { SnapshotInfo snapshot = _snapshots[0]; _snapshots.RemoveAt(0); _core.PushRequest(CoreRequest.DeleteSnapshot(snapshot.Id)); } } } } } }
/// <summary> /// Asynchronously performs a soft reset of the core. /// </summary> public void Reset() { PushRequest(CoreRequest.Reset()); }