From d7bd6dc3dd89010a87fb67771396f778c19126a7 Mon Sep 17 00:00:00 2001 From: voytas Date: Fri, 3 Apr 2026 20:04:52 +0100 Subject: [PATCH 1/2] Implement screen effects: add Blur and CRT options to UI and ViewModel --- src/Spectron/Controls/MainMenu.axaml | 6 +++ src/Spectron/Controls/NativeMainMenu.cs | 42 +++++++++++++++++++ .../Converters/EnumHasValueConverter.cs | 21 ++++++++++ src/Spectron/Screen/ScreenEffect.cs | 11 +++++ src/Spectron/Settings/Preferences.cs | 2 + .../ViewModels/MainWindowViewModel.Display.cs | 12 ++++++ .../ViewModels/MainWindowViewModel.Window.cs | 2 + .../ViewModels/MainWindowViewModel.cs | 6 +++ src/Spectron/Views/MainWindow.axaml | 23 +++++++++- 9 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/Spectron/Converters/EnumHasValueConverter.cs create mode 100644 src/Spectron/Screen/ScreenEffect.cs diff --git a/src/Spectron/Controls/MainMenu.axaml b/src/Spectron/Controls/MainMenu.axaml index 39ae9fd..401aec5 100644 --- a/src/Spectron/Controls/MainMenu.axaml +++ b/src/Spectron/Controls/MainMenu.axaml @@ -20,6 +20,7 @@ + @@ -123,6 +124,11 @@ + + + + + diff --git a/src/Spectron/Controls/NativeMainMenu.cs b/src/Spectron/Controls/NativeMainMenu.cs index cefa208..cfc74cf 100644 --- a/src/Spectron/Controls/NativeMainMenu.cs +++ b/src/Spectron/Controls/NativeMainMenu.cs @@ -27,6 +27,7 @@ public sealed class NativeMainMenu private readonly Dictionary _mouseTypes = new(); private readonly Dictionary _emulationSpeeds = new(); private readonly Dictionary _borderSizes = new(); + private readonly Dictionary _screenEffects = new(); private readonly Dictionary _tapeLoadingSpeeds = new(); private readonly Dictionary _microdrives = new(); private readonly Dictionary _diskDrives = new(); @@ -49,6 +50,7 @@ public NativeMainMenu(MainWindowViewModel viewModel) CreateMouseTypeMenu(); CreateSpeedOptionMenu(); CreateBorderSizeMenu(); + CreateScreenEffectMenu(); CreateTapeLoadingSpeedMenu(); _viewModel.PropertyChanged += (_, e) => ViewModelPropertyChanged(e.PropertyName); @@ -145,6 +147,14 @@ private void ViewModelPropertyChanged(string? propertyName) break; + case nameof(MainWindowViewModel.ScreenEffect): + foreach (var screenEffect in _screenEffects.Keys) + { + _screenEffects[screenEffect].IsChecked = _viewModel.ScreenEffect.HasFlag(screenEffect); + } + + break; + case nameof(MainWindowViewModel.IsFullScreen): _fullScreenMenuItem?.Header = _viewModel.IsFullScreen ? "Exit Full Screen" : "Full Screen"; @@ -460,6 +470,17 @@ private NativeMenuItem CreateViewMenu() ] }, + new NativeMenuItem("Effect") + { + Menu = + [ + _screenEffects[ScreenEffect.Blur], + _screenEffects[ScreenEffect.Crt], + ] + }, + + new NativeMenuItemSeparator(), + new NativeMenuItem("Trainers") { Command = _viewModel.ShowTrainersCommand, @@ -923,6 +944,27 @@ private void CreateBorderSizeMenu() } } + private void CreateScreenEffectMenu() + { + var effects = new[] + { + new { Effect = ScreenEffect.Blur, DisplayName = "Blur" }, + new { Effect = ScreenEffect.Crt, DisplayName = "CRT" }, + }; + + foreach (var effect in effects) + { + _screenEffects[effect.Effect] = new NativeMenuItem(effect.DisplayName) + { + ToggleType = NativeMenuItemToggleType.CheckBox, + Command = _viewModel.ChangeScreenEffectCommand, + CommandParameter = effect.Effect, + IsChecked = _viewModel.ScreenEffect.HasFlag(effect.Effect), + IsEnabled = true + }; + } + } + private void CreateTapeLoadingSpeedMenu() { var speeds = new[] diff --git a/src/Spectron/Converters/EnumHasValueConverter.cs b/src/Spectron/Converters/EnumHasValueConverter.cs new file mode 100644 index 0000000..9abe9be --- /dev/null +++ b/src/Spectron/Converters/EnumHasValueConverter.cs @@ -0,0 +1,21 @@ +using System; +using System.Globalization; +using Avalonia.Data.Converters; + +namespace OldBit.Spectron.Converters; + +public class EnumHasValueConverter : IValueConverter +{ + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is not Enum enumValue || parameter is not Enum parameterValue) + { + return false; + } + + return enumValue.HasFlag(parameterValue); + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => + throw new NotImplementedException(); +} \ No newline at end of file diff --git a/src/Spectron/Screen/ScreenEffect.cs b/src/Spectron/Screen/ScreenEffect.cs new file mode 100644 index 0000000..9e2f9fa --- /dev/null +++ b/src/Spectron/Screen/ScreenEffect.cs @@ -0,0 +1,11 @@ +using System; + +namespace OldBit.Spectron.Screen; + +[Flags] +public enum ScreenEffect +{ + None = 0x00, + Blur = 0x01, + Crt = 0x02, +} diff --git a/src/Spectron/Settings/Preferences.cs b/src/Spectron/Settings/Preferences.cs index 6000363..e3d94db 100644 --- a/src/Spectron/Settings/Preferences.cs +++ b/src/Spectron/Settings/Preferences.cs @@ -23,6 +23,8 @@ public class Preferences public BorderSize BorderSize { get; set; } = BorderSize.Medium; + public ScreenEffect ScreenEffect { get; set; } = ScreenEffect.None; + public ComputerType ComputerType { get; init; } = ComputerType.Spectrum48K; public RomType RomType { get; init; } = RomType.Original; diff --git a/src/Spectron/ViewModels/MainWindowViewModel.Display.cs b/src/Spectron/ViewModels/MainWindowViewModel.Display.cs index ca8a6b5..8375fd3 100644 --- a/src/Spectron/ViewModels/MainWindowViewModel.Display.cs +++ b/src/Spectron/ViewModels/MainWindowViewModel.Display.cs @@ -17,6 +17,18 @@ private void HandleChangeBorderSize(BorderSize borderSize) SpectrumScreen = _frameBufferConverter.ScreenBitmap; } + private void HandleChangeScreenEffect(ScreenEffect screenEffect) + { + if (ScreenEffect.HasFlag(screenEffect)) + { + ScreenEffect &= ~screenEffect; + } + else + { + ScreenEffect |= screenEffect; + } + } + private void HandleToggleFullScreen() => WindowState = WindowState == WindowState.FullScreen ? WindowState.Normal : WindowState.FullScreen; diff --git a/src/Spectron/ViewModels/MainWindowViewModel.Window.cs b/src/Spectron/ViewModels/MainWindowViewModel.Window.cs index 697a9d0..d630a91 100644 --- a/src/Spectron/ViewModels/MainWindowViewModel.Window.cs +++ b/src/Spectron/ViewModels/MainWindowViewModel.Window.cs @@ -61,6 +61,7 @@ private async Task WindowOpenedAsync() ConfigureShiftKeys(_preferences.Keyboard); HandleChangeBorderSize(CommandLineArgs?.BorderSize ?? _preferences.BorderSize); + HandleChangeScreenEffect(_preferences.ScreenEffect); TapeLoadSpeed = CommandLineArgs?.TapeLoadSpeed ?? _preferences.Tape.LoadSpeed; @@ -191,6 +192,7 @@ private async Task WindowClosingAsync(WindowClosingEventArgs args) _preferences.Audio.IsMuted = IsAudioMuted; _preferences.BorderSize = BorderSize; + _preferences.ScreenEffect = ScreenEffect; await Task.WhenAll( _preferencesService.SaveAsync(_preferences), diff --git a/src/Spectron/ViewModels/MainWindowViewModel.cs b/src/Spectron/ViewModels/MainWindowViewModel.cs index b9e9141..bd7587d 100644 --- a/src/Spectron/ViewModels/MainWindowViewModel.cs +++ b/src/Spectron/ViewModels/MainWindowViewModel.cs @@ -104,6 +104,9 @@ public partial class MainWindowViewModel : ObservableObject [ObservableProperty] public partial BorderSize BorderSize { get; set; } = BorderSize.Medium; + [ObservableProperty] + public partial ScreenEffect ScreenEffect { get; set; } = ScreenEffect.None; + [ObservableProperty] public partial RomType RomType { get; set; } = RomType.Original; @@ -298,6 +301,9 @@ private async Task TakeScreenshot() [RelayCommand] private void ChangeBorderSize(BorderSize borderSize) => HandleChangeBorderSize(borderSize); + [RelayCommand] + private void ChangeScreenEffect(ScreenEffect screenEffect) => HandleChangeScreenEffect(screenEffect); + [RelayCommand] private void ShowTrainers() => OpenTrainersWindow(); diff --git a/src/Spectron/Views/MainWindow.axaml b/src/Spectron/Views/MainWindow.axaml index cd76352..d964c8f 100644 --- a/src/Spectron/Views/MainWindow.axaml +++ b/src/Spectron/Views/MainWindow.axaml @@ -6,6 +6,7 @@ xmlns:viewModels="clr-namespace:OldBit.Spectron.ViewModels" xmlns:converters="clr-namespace:OldBit.Spectron.Converters" xmlns:controls="clr-namespace:OldBit.Spectron.Controls" + xmlns:screen="clr-namespace:OldBit.Spectron.Screen" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="OldBit.Spectron.Views.MainWindow" x:DataType="viewModels:MainWindowViewModel" @@ -35,6 +36,8 @@ + + @@ -91,8 +94,14 @@ PointerMoved="Screen_OnPointerMoved" PointerPressed="Screen_OnPointerPressed" PointerReleased="Screen_OnPointerReleased" - Classes.IsPaused="{Binding IsPauseOverlayVisible}"> + Classes.IsPaused="{Binding IsPauseOverlayVisible}" + Classes.Blur="{Binding ScreenEffect, Converter={StaticResource EnumHasValueConverter}, ConverterParameter={x:Static screen:ScreenEffect.Blur}}"> + + + + + + + + + + + + + From ab115730d65b3d9197da0ccee0b470bac5e5c034 Mon Sep 17 00:00:00 2001 From: voytas Date: Fri, 3 Apr 2026 20:14:00 +0100 Subject: [PATCH 2/2] Update README --- README.md | 184 ++++++++++++++++++++++-------------------------------- 1 file changed, 73 insertions(+), 111 deletions(-) diff --git a/README.md b/README.md index 696d611..7a94263 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,27 @@ ![Build and Test](https://github.com/oldbit-com/Spectron/actions/workflows/build.yml/badge.svg) # Spectron ― ZX Spectrum 16/48/128 Emulator ☺ -Here is my own ZX Spectrum emulator written in C# and Avalonia UI. It emulates classic ZX Spectrum 16K, 48K and -128K computers. +Here is Spectron, my personal ZX Spectrum emulator written in C# and Avalonia UI. It emulates the classic ZX Spectrum 16K, 48K, and 128K computers. -It is quite accurate and stable, it can run most of the games and demos without any issues, load protected -tapes, etc. +It is accurate and stable, capable of running most games and demos without issues, including support for loading protected tapes. -It's a cross-platform emulator that runs on Windows, Linux and macOS. Developed on macOS, so generally well tested -on this platform. Needs some more testing on Linux, seems to be running fine on Windows. +Spectron is a cross-platform emulator that runs on Windows, Linux, and macOS. Developed primarily on macOS, it is well-tested on that platform, while also showing solid performance on Windows. Further testing on Linux is ongoing. -This is purely my hobby project which I always wanted to do. It has been a lot of fun, and quite a challenge. -There are many other emulators available, but this one is my attempt. It is written all by hand, no AI generated code ☺. +This project is a hobby I have always wanted to pursue. It has been both a lot of fun and a rewarding challenge. While many other emulators exist, this is my own personal take. -ZX Spectrum was my first computer and I still love it. I am planning to keep this project alive since -I have created it for my personal use to play games and demos. It is a lot of fun. +The ZX Spectrum was my first computer, and I still have a deep affection for it. I plan to continue maintaining and evolving this project, as I use it personally to enjoy classic games and demos. ![Main Window](docs/default.png?raw=true "Main Window") ## Features -- [x] Emulates classic machines: ZX Spectrum 16K, 48K and 128K -- [x] Time Machine: rewind and continue from a given time point in the past -- [x] Emulator state is persisted and restored when the application is re-started -- [x] Supports SNA, SZX, Z80, TAP, TZX, MDR, TRD and SCL file formats (inside zip, too) -- [x] Supports POK trainer files -- [x] Pretty accurate timings; including memory and IO contention +- [x] Emulation of classic machines: ZX Spectrum 16K, 48K, and 128K +- [x] Time Machine: Rewind and continue from any point in the past +- [x] State persistence: Emulator state is automatically saved and restored on restart +- [x] Wide format support: SNA, SZX, Z80, TAP, TZX, MDR, TRD, and SCL (including ZIP archives) +- [x] Support for POK trainer files +- [x] High accuracy: Precise timings, including memory and I/O contention - [x] Floating bus support -- [x] Supports multicolour screen effects +- [x] Multicolor screen effects - [x] ULA+ support - [x] AY-3-8912 sound chip emulation - [x] DivMMC emulation @@ -34,17 +29,17 @@ I have created it for my personal use to play games and demos. It is a lot of fu - [x] Microdrive emulation - [x] Kempston mouse emulation - [x] ZX Printer emulation -- [x] Tape viewer -- [x] Disk viewer -- [x] Adjustable emulator speed -- [x] Keyboard joystick emulation: Kempston, Sinclair, Cursor & Fuller +- [x] Integrated tape and disk viewers +- [x] Adjustable emulation speed +- [x] Keyboard-based joystick emulation: Kempston, Sinclair, Cursor, and Fuller - [x] Audio and video recording -- [x] Selection of alternative ROMs, custom ROM can also be loaded +- [x] Support for alternative and custom ROMs - [x] Built-in debugger -- [x] Favourites manager -- [x] And more features will come +- [x] Favorites manager +- [x] Screen effects: Blur and CRT/Scanlines +- [x] And more to come... -Spectron relies on several custom libraries that I created for this project: +Spectron relies on several custom libraries developed specifically for this project: | Library | Description | |--------------------------------------------------------|----------------------------------------------| @@ -53,15 +48,16 @@ Spectron relies on several custom libraries that I created for this project: | [Beep](https://github.com/oldbit-com/Beep) | Basic audio player, cross-platform, native | | [Joypad](https://github.com/oldbit-com/Joypad) | Gamepad handler, cross-platform, native | -Solution consists of several projects: +The solution consists of several projects: -| Project | Description | -|------------------------|--------------------------------------------------------| -| Spectron | Avalonia based UI | -| Spectron.Debugger | Fully featured Code debugger, includes UI and controls | -| Spectron.Disassembly | Simple Z80 disassembler, used by the debugger | -| **Spectron.Emulation** | This is the core of the emulator, e.g. the main thing | -| Spectron.Recorder | Audio and Video recording helper | +| Project | Description | +|----------------------|---------------------------------------------------------| +| Spectron | Avalonia-based UI and main application logic | +| Spectron.Debugger | Fully featured code debugger, including UI and controls | +| Spectron.Emulation | Core emulation engine | +| Spectron.Basic | Basic interpreter and related utilities | +| Spectron.Disassembly | Z80 disassembler, used by the debugger | +| Spectron.Recorder | Audio and video recording functionality | ## Quick demo [![Spectron](https://img.youtube.com/vi/Oz70N0VY_2w/default.jpg)](https://youtu.be/Oz70N0VY_2w "Quick demo") @@ -94,119 +90,85 @@ commands is [here](docs/CommandLine.md). Test results can be found in the [Results](https://github.com/oldbit-com/Spectron/tree/main/tests/Results) directory. Test programs can be found in the [Tests](https://github.com/oldbit-com/Spectron/tree/main/tests/Files) directory. -## CPU emulation -I have created my own [Z80 CPU](https://github.com/oldbit-com/Z80/tree/spectron) emulator library for this project. -CPU emulation is quite accurate and supports many undocumented instructions. -Memory and IO contention is also supported. +## CPU Emulation +I have developed a custom [Z80 CPU](https://github.com/oldbit-com/Z80/tree/spectron) emulator library for this project. +The emulation is highly accurate and supports many undocumented instructions, as well as memory and I/O contention. -## Session -When emulator is closed, it saves the current state of the emulator. The state will be restored when you start the emulator again. -This behaviour can be disabled in the settings. +## Session Persistence +When the emulator is closed, it automatically saves its current state, which is then restored upon restart. This behavior can be toggled in the settings. -## Tape loading -Tape loading is supported for **TAP** and **TZX** files (zip is ok). Three loading speeds are supported: -- **Normal** - loads the tape at normal speed, with border and audio effects, -- **Accelerated** - loads the tape running emulator at maximum speed, -- **Instant** - loads the tape instantly into memory. This will skip the tape loading animation and will load the tape instantly. -This mode will only work for files that are using standard ROM loaders. +## Tape Loading +Tape loading is supported for **TAP** and **TZX** files (including ZIP archives). Three loading speeds are available: +- **Normal**: Loads the tape at the original speed, including border and audio effects. +- **Accelerated**: Loads the tape at the maximum possible emulator speed. +- **Instant**: Loads the tape instantly into memory, bypassing the loading sequence. This mode works for files using standard ROM loaders. -## Tape saving -Tape saving is supported for **TAP** and **TZX** formats. Two saving speeds are supported: -- **Normal** - tape is saved at normal speed, with border and audio effects, -- **Instant** - tape is saved instantly reading the memory. +## Tape Saving +Tape saving is supported for **TAP** and **TZX** formats at two speeds: +- **Normal**: Saves at the standard speed with border and audio effects. +- **Instant**: Saves instantly by reading the current memory state. -## Tape browser -Tape browser is a feature that allows you to browse the contents of currently loaded or saved tape. -You can browse the blocks, their types and some basic block information. -You can select a block and load it using standard `LOAD` command. +## Tape Browser +The Tape Browser allows you to inspect the contents of the currently loaded or saved tape. You can view blocks, their types, and basic information. Selecting a block allows you to load it using the standard `LOAD ""` command. ## Snapshots -Emulator supports saving and loading snapshots in **SNA**, **SZX**, **Z80** and custom format. -It is recommended to use a custom **\*.spectron** format when saving a snapshot. This format covers -most of the emulator settings. +The emulator supports saving and loading snapshots in **SNA**, **SZX**, and **Z80** formats. It also features a custom **.spectron** format, which is recommended as it captures most emulator settings. ## Screen -Multicolour screen effects are supported, as well as border effects. Border size can be adjusted. +Multicolor screen effects and border effects are fully supported. The border size can be adjusted in the settings. +Additionally, screen effects like **Blur** and **CRT/Scanlines** can be applied to simulate an old TV feel. -## Floating bus -Floating bus is emulated and supported by both 48K and 128K modes. Only a handful of games require this feature. +## Floating Bus +Floating bus emulation is supported for both 48K and 128K modes, which is required for a small number of specific games. ## Alternative ROMs -Emulator allows selecting an alternative ROM. There are many such ROMs built-in and ready to play with. -Some of them require 128K mode: TR-DOS and BBC Basic. Additionally, custom ROM files can be loaded. +Spectron allows you to select from various built-in alternative ROMs, such as TR-DOS and BBC Basic (which require 128K mode). Custom ROM files can also be loaded. ## Audio -Standard beeper audio is supported, as well as AY audio (mono / stereo ABC or ACB mode). -AY is by default enabled in 48K mode, but can be disabled in the settings. +Standard beeper audio and AY-3-8912 sound (mono or stereo ABC/ACB modes) are supported. AY is enabled by default in 48K mode but can be disabled. -Audio playback is done using [Beep](https://github.com/oldbit-com/Beep) which I created for this project since I couldn't find any simple -cross-platform audio player that would suit my needs. +Audio playback is powered by [Beep](https://github.com/oldbit-com/Beep), a custom cross-platform audio library developed for this project. ## Joystick and Gamepad -Joystick emulation is supported for Kempston, Sinclair, Cursor and Fuller joysticks. External gamepads and joysticks -are supported as well. But this has been only tested with few controllers I have. Controller buttons can be mapped to -joystick or keyboard keys. Standard keyboard can also be used as a joystick, arrow keys for directions and space for fire. +Emulation is supported for Kempston, Sinclair, Cursor, and Fuller joysticks. External gamepads and joysticks are also supported (tested with a variety of controllers). Buttons can be mapped to joystick or keyboard keys. The standard keyboard can also serve as a joystick, using the arrow keys for directions and Space for Fire. > [!NOTE] -> Not all controllers may work, and compatibility depends on the platform. Experimental feature. -## ULA+ support -ULA+ mode is supported and can be enabled in the emulator settings. +> Controller compatibility may vary by platform. This is an experimental feature. +## ULA+ Support +ULA+ mode is supported and can be enabled in the settings. ## DivMMC -DivMMC emulation is supported and can be enabled in the emulator settings. -It is based on [esxDOS 0.8.9](https://esxdos.org/). You will need to use a disk image containing esxDOS files. -Sample disk images can be found [here](https://1drv.ms/u/c/7fd2cf29d9a4c5e1/EdULvNTWM7VLiU1_6GeGDcgBacxN6TanwmMCle2Hz8OBhg?e=3CSLB0). +DivMMC emulation is supported and can be enabled in the settings. It is based on [esxDOS 0.8.9](https://esxdos.org/) and requires a disk image containing the esxDOS system files. +Sample disk images are available [here](https://1drv.ms/u/c/7fd2cf29d9a4c5e1/EdULvNTWM7VLiU1_6GeGDcgBacxN6TanwmMCle2Hz8OBhg?e=3CSLB0). -Two SD card images are supported. Write changes can be persisted. - -You can use [RTC.SYS](https://github.com/oldbit-com/Spectron/tree/main/src/Spectron.Emulation/Devices/DivMmc/RTC) file to enable RTC support. This is not required, but it will enable DivMMC to use current -date and time. +Up to two SD card images are supported, and changes can be persisted to the images. RTC support is available via the [RTC.SYS](https://github.com/oldbit-com/Spectron/tree/main/src/Spectron.Emulation/Devices/DivMmc/RTC) file, allowing DivMMC to use the current system date and time. ## Microdrives -Emulation of microdrives is supported and can be enabled in the emulator settings. -Up to eight drives can be emulated, MDR image files can be loaded/saved. No other features of Interface 1 are emulated -currently. +Microdrive emulation supports up to eight drives and can be enabled in the settings. MDR image files can be loaded and saved. Note that other Interface 1 features are not currently emulated. ## Beta 128 (TR-DOS) -Emulation of Beta 128 Disk Interface is supported and can be enabled in the emulator settings. -Up to four drives can be emulated, MDR and SCL image files can be loaded/saved. ROM version 5.03 is -used. - -To invoke TR-DOS, enter `RANDOMIZE USR 15616` from `BASIC`. Or select Pentagon 128 ROM which provides -easy access to TR-DOS. +Beta 128 Disk Interface emulation supports up to four drives (TRD and SCL formats). It uses ROM version 5.03. +To invoke TR-DOS, use `RANDOMIZE USR 15616` from BASIC, or use the Pentagon 128 ROM for easier access. ## Time Machine -Time Machine is a feature that allows you to go back in time and continue from given time point in the past. -The interval and the number of time points can be adjusted in the settings. - -## Video and Audio recording +The Time Machine feature allows you to rewind the emulation and resume from a previous point in time. The recording interval and history depth are adjustable in the settings. -Audio and video recording is supported in the emulator. This is experimental feature and may not work on all platforms. -You can pause emulator during the recording, however changing emulator settings during the recording may cause -unexpected results. +## Video and Audio Recording +Audio and video recording are supported. This is an experimental feature and performance may vary by platform. Changing emulator settings during recording may lead to unexpected results. ### Audio -Audio can be recorded to a file in **WAV** format. The format is PCM 16-bit, 44,100 Hz, mono or stereo depending on the -current AY mode. No external dependencies are required for audio recording. +Audio is recorded in **WAV** format (PCM 16-bit, 44,100 Hz, mono or stereo). No external dependencies are required. ### Video -Video recording requires **[FFmpeg](https://www.ffmpeg.org)** to be installed on your system. +Video recording requires **[FFmpeg](https://www.ffmpeg.org)**. Videos are encoded as **MP4** using the **H.264** codec at **50 FPS**. Rendering options like scaling and border size are adjustable. -Video is generated as **MP4** using **H.264** codec at **50 FPS**. Some video rendering options like scaling, border size -can be adjusted in the emulator settings. Raw frame buffer data is used internally during the recording. - -Processing of the recorded data starts after the recording is stopped, and it can take some time. This is -done in the background by converting static frames to a video stream with audio, leveraging FFmpeg. +Recording is processed in the background after it stops, leveraging FFmpeg to combine the captured frames and audio. ## Debugger -Debugger is available in the emulator. It is a simple debugger that allows you to inspect the CPU registers, -memory and disassembly. You can step through the code, set breakpoints. -More information can be found [here](docs/Debugger.md). - -## Favourites Manager -Favourites manager allows you to organise your favourite games, demos and other files. -You can access it from the main menu. -More information can be found [here](docs/Favorites.md). +The built-in debugger allows for inspection of CPU registers, memory, and disassembly. It supports code stepping and breakpoints. For more details, see the [Debugger documentation](docs/Debugger.md). + +## Favorites Manager +The Favorites Manager helps organize your favorite games, demos, and files, accessible directly from the main menu. For more details, see the [Favorites documentation](docs/Favorites.md). ### Resources - [Avalonia UI](https://avaloniaui.net/)