Giter Club home page Giter Club logo

racknes's Introduction

RackNES

A Nintendo Entertainment System (NES) emulator as if it were designed by Bob Moog.

RackNES

Features

  • Clock Source: Use NES frame-rate (FPS) as a clock source for downstream modules
  • Clock Rate Modulation: Control the clock rate of the NES with direct knob and CV
  • NES Audio Output: Sample audio from the NES in real-time at any sampling rate
  • Sampling/Ratcheting: Save and restore the NES state for interesting musical effects
  • Full CV Control: CV inputs for Reset, Player 1, Player 2, and more
  • Channel Mixer: Control the volume level of individual synthesizer channels

See the Manual for more information about the features of this module.

CV Genie

CV Genie is a Game Genie emulator and expander module for RackNES developed by @anlexmatos!

CVGenie

See the Manual for more information about the features of this module.

Acknowledgments

The code for the module derives from:

  1. the NES emulator, SimpleNES;
  2. the NES synthesis library, Nes_Snd_Emu;
  3. the NES NTSC filter library nes_ntsc; and
  4. the Base64 library, cpp-base64.

Contributors

Many thanks to @anlexmatos for developing the CV Genie expander module.

racknes's People

Contributors

anlexmatos avatar kautenja avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

racknes's Issues

Make "Load ROM" dialog filter by .nes files

Adding a file extension filter makes it easier for users to load the correct ROM file. osdialog supports extension filters with the following code.

osdialog_filters *filters = osdialog_filters_parse("NES ROM:nes,NES");
char *path = osdialog_file(OSDIALOG_OPEN, dir.c_str(), NULL, filters);
osdialog_filters_free(filters);

Audio Filters

After combining the two output signals, the final signal may go through a lowpass and highpass filter. For instance, RF demodulation in televisions usually results in a strong lowpass. The NES' RCA output circuitry has a more mild lowpass filter.

It might be nice to implement some optional audio filters (using a simple switch) to emulate the output filtering that occurs on hardware NES. I don't think any of these filters have resonance, so it might be easy enough to fake them using an exponential moving average.

MMC1 is not working for Metroid

Screen Shot 2020-06-22 at 12 29 43 AM

When loading the game, audio is not working correctly and the screen is glitched. The start screen also appears to be missing some assets that are normally rendered.

NTSC Filters in Graphics Pipeline

Is moving the NTSC filters into the graphical pipeline a good idea? Furthermore, would this improve performance by reducing the compute needed in the audio pipeline?

"Read" functionality for CV Genie

Hi, I found RackNES and love it, but I noticed there were some limitations that kept me from really digging into the guts of the NES. For example, I have no means of getting the CVs of the 2A03's sound channel registers, just sampling their total output.

Enter the CV Genie. It looks promising, but it's currently write-only which is less than helpful in this use case. Moreover, it doesn't offer access to arbitrary RAM addresses, and I noticed that was taken out of the roadmap too. Doubly moreover, I want to play around with the music of more advanced titles like Sunsoft's, or indie games like Nova the Squirrel which would unlikely ever be mapped for obscurity. Therefore, would it be possible to create "game" choices that simply map to the 2A03's audio registers, as well as including output CVs from them?

Admittedly I've half a mind to do it myself and send a pull request but I would need to familiarize myself with VCVrack more, but that will take a while, and I want to know if such a feature would be accepted too.

Serialize/unserialize current state and saved state to patch

If you have some way of getting the RAM bytes, you can save/restore it with the following code in dataToJson() and dataFromJson(). I'd recommend base64 as an easy way to encode an arbitrary buffer.

std::vector<uint8_t> ram;
ram.assign(ramData, ramLen);
std::string ramString = string::toBase64(ram);
...
std::vector<uint8_t> ram = string::fromBase64(ramString);

You could also compress it with zlib with string:compress/uncompress, but that's a bit more involved and probably not worth it for 2KiB RAM.

Play / Pause / Hang Emulation

It might be fun to have a CV input for playing / pausing the emulation of the machine. Alternatively, a "hang" input could just pause the emulation when a gate signal goes high and resume when it goes back low.

NES Mappers

Mappers to implement:

  • NROM
  • MMC1 / SxROM
  • UxROM
  • CNROM
  • MMC3
  • AOROM

there are more, but these cover the majority of the games in the library

Serialization of SRAM

Could you please add a way to save the SRAM to a .sav file or load SRAM from a .sav file? This module is sick for rendering tracker music but VCV kills batteries so I'd rather work on loops and patterns in a lighter emulator and import them later to add FX chains.

Cheers.

Consolidation of ROM data

In DAWs like Ableton Live, one can "consolidate" files to ensure that a project file contains all necessary data to run the project (i.e., samples, plugins, etc.). Is it possible to consolidate the ROM file into the VCV Rack JSON? This way the patch can always load even if the ROM file moves between sessions. This would resolve one element in #2 by removing the need to serialize the file path and handle the file not existing when reloading the patch. Do other sample-based modules implement some form of consolidation?

NES Advantage

the NES Advantage controller had two funky features: the turbo A/B buttons, and the slow button. This is all pretty doable already using simple LFOs, but it might be fun to integrate these features into the module

Opcode Lookup

Currently, opcode lookup is accomplished through a series of functions where each function is responsible for a set of opcodes. Each function returns true if the opcode was decoded and executed, false otherwise. A single logical statement calls each of these functions in a short circuit series to stop when the first function that can decode the opcode is found. Typically, large switch operations like this are just handled by a single C++ switch statement that the compiler can hopefully optimize into a one-shot lookup table. Does moving towards this design improve the performance of opcode lookup? In theory, it seems like the answer is yes, but practically, is not known. Assuming performance is not hurt by the change to a switch statement, this design should be favored for reduced function call overhead and better readability.

Vectrex Emulator

The Vectrex gaming console used the General Instrument AY-3-8910 sound generator (implemented in PotatoChips), and has plenty of existing emulators written in C++ (https://github.com/amaiorano/vectrexy). It would probably not be too difficult to port one of these emulators into VCV as an emulator similar to RackNES.

Expansion ROM Support

Support needs to be added for RAM addresses 0x4020 to 0x6000 in the main bus. These addresses are the expansion ROM addresses

Ugly Dynamic Allocation of Emulator Object in Module

The emulator design currently makes the assumption that emulator ROMs are immutable, and as such, the emulator is allocated dynamically and must be destroyed and recreated every time a new game is loaded by the user. Additionally, the RackNES.cpp module code contains a great deal of nullptr checking that looks ugly and encourages segmentation faults & crashes during development. Changing this assumption to allow an emulator instance to have games "inserted" and "removed" allows the module to initialize and destroy the emulator automatically, which is both more fault tolerant, and easier to keep a mental model of. A new member function for checking if the emulator has a game loaded, i.e., is_game_inserted(), is more expressive than checking for the nullity of an obscure pointer.

Documentation / Manual

A simple Markdown documentation/manual would be nice for explaining the basics of the module. This is particularly useful for the VCV rack distribution, which offers a direct link to a manual.

CV Genie Roadmap

The CV Genie (input) module is under development with the following bucketlist / roadmap of issues to address.

Open Issues

  • moar knobs!
    • some knobs to control the parameters without CV would be fun
    • an input attenuator / attenuverter would be nice for scaling CV inputs
  • determine whether using trademarked title names will be a problem (I think it's probably fine so long as the TM is listed?, i.e. Super Mario Bros.โ„ข)
  • support for multi-RAM-slot parameters
    • some application level parameters use multiple RAM slots. How should this be addressed?
      1. the memory map data structure could be changed to map a single CV to multiple slots
      2. the module could allow chain-able inputs (i.e., optional input normalling) to connect CV inputs together
  • find a way for the memory bus of the emulator to be accessible in a well defined manner
    • it's public at the moment, which is a code smell, refactoring is needed
  • fix triggers for switched parameters
    • sometimes trigger inputs require multiple triggers. This may just require scaling the voltage to the input Schmidt trigger. More review is needed.
  • clamp parameters to prevent undefined behavior from "clipped" inputs
    • clipping is symbolic, V > 10 implies clipping in VCV Rack. The input to the module is quantized and encoded to 8-bit and thus needs clipped to [-10, 10V]
  • support more games
    • this can probably be handled semi-automated by scraping a RAM map repository and generating C++ structs from tabular data. Some human review will be necessary.
    • the format for reporting the RAM maps is not necessarily standardized, they will need to be done by hand
    • https://datacrystal.romhacking.net/wiki/Category:RAM_maps

Graveyard

  • automatic game detection. There is no well-defined way to map a ROM file to an NES title because the file format does not identify the games. Checksums are ineffective because small variations in ROM file for the same title will produce different checksums (including minor ROM hacks).
  • parameter displays. IMO the value of the parameter in binary isn't very useful or interesting to know. There is a linear relationship between the voltage and the parameter, so an oscilloscope can effectively provide this for input and output signals really. There are special cases for triggers and parameters with small ranges, but as of right now this feature seems unnecessary.
  • arbitrary RAM addressing This feature would allow for plenty of accidental discoveries, but would not be very useful for accomplishing semantic tasks (i.e., make Mario move around in a circle). Additionally, it stands to frequently crash the game by writing invalid values to invalid addresses. IMO, it could be an interesting feature, but seems not worth the trouble.

Individual Synthesizer Voice Outputs

Nes_Snd_Emu provides support for blipping individual synth voices to a buffer. Integrating this functionality into the panel would allow for on the fly remixing / equalizing of the voices on the NES.

CV Palette Manipulation

The palette is small enough to allow for CV manipulation of the NTSC color mapping. This would allow for unique visual effects that don't interfere with the emulation process in any meaningful way, i.e., nothing should ever break.

Additional Save States

allowing for more than 1 save state to store and load from would allow users to use the device more effectively as a sampler, i.e., by setting up many save states and triggering loads from different ones. This could be accomplished using an encoder knob or dedicated CV inputs for each save / load state.

NTSC (Video) Filters

Blargg has also some NTSC filters to emulate the NTSC artifacts in the digital space. These would be real neat to have with a simple switch control, or else menu context, to cycle between the four video filters.

Improve Color Palette Memory Organization

  • The module requires screen data to be stored in RGBA for NanoSVG to render. NanoSVG doesn't offer support for RGB, BGR, or BGRA formats, just RGBA. Is there a way to change the memory organization of the palette to be more nano SVG friendly? I.e., can the palette be reorganized such that switching color spaces is no longer necessary (i.e., removing the 2D loop over the screen).

  • In the audio pipeline, the module currently copies the screen every time an NES frame event occurs. This was implemented to remove the flickering effect that happens when the Widget directly renders the screen from the NES. This flickering is thought to be caused by concurrency between the widget and the module that is not properly synchronized. Is there a way to remove this additional copy, but also prevent the UI thread from rendering incorrectly?

    • resolving the first bullet allows the copy loop to at least be replaced with a single copy instruction, opposed to the loop over bytes or pixels
    • simple message passing with flags may allow the copy to be moved to the widget. I.e., the module sets a flag when a screen is produced (NES frame event) and the widget consumes the screen directly from the NES into a local buffer and clears the flag, i.e., basic producer-consumer pattern

Popups for File IO stuff

  • show a popup message when attempting to load a file that is not recognized as an iNES file
  • show a popup when failing to load a ROM from a saved state, i.e., a JSON file

the screen of the NES may be used in place of the popup, if necessary.

CV RAM Manipulation

Working a way to access the RAM of the machine using CV could be interesting.

  • Allowing RAM output would allow a user to select a RAM address and use the value at that address as a modulation source. For games like super mario bros., one could modulate other parameters based on Mario's running speed for instance.

  • Allowing RAM input will need some conceptualizing, but it would act as a sort of digital "circuit bending" technique. Although it could break the emulation, this is true of real world circuit bending and may be desired functionality depending on how the emulation degrades upon breaking.

Emulation Algorithm Embodies Odd Clock Behavior & is Not Optimized

Currently, the emulator uses the rising edge of a clock to trigger NES frame events, where a full video frame is rendered from the NES in 29781 CPU cycles. This works OK for now, but is not very performant: many samples will be fast as the NES emulator is effectively not running, but on cases where a clock rising edge occurs, the process function will be slowed down by the 29781 NES cycles required to complete the step. Additionally, the audio may be impacted by this algorithm because the APU BLIP buffer is filled during each frame event and emptied during the proceeding frames. The lag from rending the single frame may be long enough to also impact the audio.

It could be advantageous to remove the sporadic frame rendering, and instead directly integrate the NES CPU cycling into the audio rate pipeline.

Invalid tag 'Game'

[KautenjaDSP-RackNES] Issues found in `plugin.json`:

RackNES: invalid module tags: Game
-- Valid tags are defined in https://raw.githubusercontent.com/VCVRack/Rack/v1/src/tag.cpp

Game is not a valid tag (yet). The feature request was logged against Rack and will be considered in the next version of Rack.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.