Fami
Fami copied to clipboard
A fast Nintendo Famicom/NES emulator with audio written in C#
Fami - Famicom/NES Emulator
Fami is a NES emulator written in C#. The name is derived from the Japanese model of the NES, the Family Computer or Famicom.
The main goal was to build a fast NES emulator with sound in C#.
When running in Debug mode, the emulator manages around 40-50 fps, but runs full speed when running in Release mode on a Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz.
Screenshots
Prerequisites
- .NET 5 SDK
- Visual Studio 2019 v16+
Features
- Zapper/Light-gun support
- Support for using controllers
- Save/Load States (only slot 1 right now)
- Rewind (up to 8 seconds)
Todo
- Button mapping through a configuration file
- Menus and dialogs
- Implement more mappers
- Fullscreen
Usage
fami.exe "<path to rom>"
Key mapping
The mappings don't use Space or Enter or Escape since Steam maps the controller to these buttons.
Key | Function |
---|---|
Up | D-Pad Up |
Down | D-Pad Down |
Left | D-Pad Left |
Right | D-Pad Right |
V | Start |
C | Select |
Z | Button A |
X | Button B |
R | Reset |
F2 | Save State |
F4 | Load State |
Backspace | Rewind |
Mappers
- NROM (000)
- MMC1 (001)
- UxROM (002)
- MMC3 (004)
- AxROM (007)
PPU
The PPU is a port of the C++ PPU used in One Lone Coders NES Emulation Tutorial and retains all the comments.
APU
The APU is taken from the BizHawk NES APU found here: https://github.com/TASVideos/BizHawk/blob/master/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs
I decided to use it as it gave the best audio output.
It uses blargg's blip_buf
library to effectively generate samples that are timed against an emulation clock (it coincides with every tick of a CPU cycle) which greatly simplifies synchronization of audio.
Known Issues
Zapper/Light gun
If you move the mouse immediately after firing, the sensor position will move, causing your aim to be off from where you clicked.
Right-clicking to trigger "outside" of the screen kind of works. It's good enough for game mode selection screens, but doesn't work well during actual gameplay. It still registers as a trigger "inside" the screen. This is probably caused by timing issues.