StrikerX3/Ymir

TAS movie recording support

Open

#35 opened on Apr 30, 2025

View on GitHub
 (2 comments) (0 reactions) (0 assignees)C++ (52 forks)auto 404
frontend-sdl3help wanted

Repository metrics

Stars
 (988 stars)
PR merge metrics
 (PR metrics pending)

Description

Before getting into details, the first thing to know is that, in my view, an emulator core should deal exclusively with system emulation and provide supporting features that enable frontends to implement advanced features like movie recording and scripting. This means that many of the desired TAS features are going to be implemented on the frontend, with a few supporting features added to the core as needed.

Ymir's emulator core (the ymir-core library) very likely already has all the basic features needed to support movie recordings and TASing. All of the major missing features I can think of are frontend concerns:

  • Input recording and playback: Just like a real console, the emulator core only exposes a simple interface for receiving input. And just like a real console, you shouldn't need to mod it to be able to record and playback inputs. TASBot can send arbitrary inputs by simply plugging into the controller port. Therefore, this should be entirely implemented on the frontend on top of the existing input callback. Note that the input callback is invoked once per INTBACK peripheral report request or PDR1/2 write, so it may be invoked multiple times per frame.
  • Save state and movie management: The core already provides a mechanism to save and load states. Anything beyond that is a frontend concern - managing save states, keeping track of history, rewinding, calculating deltas, etc. should all be done outside the core. Movies are simply a bunch of metadata and sequences of inputs; all the frontend needs to do is read from the movie sequence instead of reading from host input devices.
  • Deterministic mode (aka movie mode): The only sources of nondeterminism in the core (as far as I'm aware at the time of this writing) are the RTC, backup memories and peripherals. The RTC has a deterministic mode: emulated RTC with reset to fixed point in time or preserve time. Backup memories need a feature to load them from memory instead of a file; alternatively, simply create a file with the predefined image then load that file. Peripherals are going to be entirely controlled by the movie system.

If there is a concern that this would lead to repeated code across different frontends, one could easily introduce an ymir-frontend-commons library that links to ymir-core and provides all of this functionality in a frontend-agnostic manner.

As for accuracy, Ymir takes some shortcuts and has some simplifications when dealing with timings. There are lots of complex interactions between processors and buses on the Saturn that Ymir does not emulate. Compatibility is moderate - the small subset of games I have access to seem to work mostly fine, except for #7 and #40. If anything, this is probably going to be the most important area of focus at first.


This TASVideos article enumerates desirable features for a rerecording emulator. There's also The Laws of TAS which lists more requirements for emulators to be accepted as TAS tools.

Listed below is the current state of the emulator as of commit a211cf9fee350a969b9aad048456c30b9a2c01ee as well as my thoughts on how to implement each of them and how difficult it seems to be:

🔴 Not implemented 🟡 Partially implemented 🟢 Implemented

Savestates

  1. 🔴Bulletproof recording: Input recording is not implemented. Assuming it is, it sounds fairly easy to implement - just include the full movie data with the save states. It should be possible to conserve a bit of memory by adding a predecessor link to save states and only save the inputs since the last save state. With this design, rebuilding a movie means following the links and concatenating the input lists of all linked states. Save state files with movies would include the entire movie, obviously.
  2. 🔴Resume Recording From Savestate: Input recording is not implemented. If item 1 is implemented, this should come for free.
  3. 🟡Savestate Undo (low priority): Not implemented on a single save state slot, but one could use different slots to keep "backups". Ideally, a single slot would keep track of a save state history.
  4. 🔴Branches Tree (low priority): The backend portion would require a bit of work to be able to navigate up and down the tree. The frontend portion sounds like a nightmare to do with the current tech stack. But it sounds too awesome not to have.

Timing

  1. 🟢Frame Advance: Both forwards and backwards, but missing the "hold to run at normal speed" interaction.
  2. 🟢Slow Motion: Implemented as of 09612afcc5eff76fb2971bdf336aa07409ef0ba4.
  3. 🟢Fast Forward: Unlimited speed variant was implemented since the emulator's inception. Limited speed variant implemented as of 09612afcc5eff76fb2971bdf336aa07409ef0ba4.
  4. 🟡Frame Search (low priority): Rewinding is already supported, but the frame search itself isn't. Needs a bit of state management to implement (the save state to reload, number of frames to advance, desired state checks). Seems to be average difficulty.

Usability

  1. 🟢Key remapping: Pretty much every action listed on the page can be remapped to any key or gamepad button.
  2. 🔴Read-only Toggle: Needs to be implemented. Tricky to implement as there's interactions with the input callback, save states system and movie system.
  3. 🔴Information Display: Fairly easy to implement thanks to ImGui.
  4. 🔴Export To AVI: AVI is obsolete, but I guess the requirement is still there. Sounds a bit troublesome to implement, considering they suggest using Windows APIs and some Linux-specific libraries, and limiting file sizes to 2 GB.
  5. 🔴Memory Search: Can be built on top of the debugger framework (the memory viewer in particular). See #2.
  6. 🔴Autofire (low priority): Sounds easy to implement, just a bit of extra state to track when to press and release buttons.
  7. 🔴Auto-hold (low priority): Again, fairly easy to implement. Simply add a new set of actions that flip the corresponding button states instead of responding to press and release.
  8. 🔴Combos or macros (low priority): If we can record and play back entire movies, we should be able to record and play back short snippets. Hard, but doable.
  9. 🟡Rewind (low priority): There is a short-term buffer that stores every frame for the past 60 seconds (3600 frames at 60 fps). It would also need to store movie/input data and long-term history (see #13) to store rewind states for the entire duration of the movie.

Emulation features

  1. 🟡Proper emulation of power cycling: The Reset button is properly implemented to raise/lower the NMI signal and guest code reacts to it appropriately, but it's currently being set asynchronously. For movie recordings, it could be updated in the input callbacks or at frame boundaries. Hard resets are deterministic. Soft resets are probably deterministic.
  2. 🟢Disabling layers (low priority): Implemented as of commit 9aba7dc6db12446b68eab3a1da6a09e4205c2e08.
  3. 🟡Accurate emulation of soft resets (low priority): The Reset button is emulated, but timings are very likely off. In addition to that, the soft reset behavior might not be entirely accurate.

Additional Emulator features

  1. 🔴Scripting Support (e.g. Lua, Python, Tcl): Very hard and laborious to do, but possible.
  2. 🔴Lag Counter: Easy to implement - just set a flag whenever the input callback is invoked and clear it every frame callback. If the flag was not set when the frame callback is invoked, increment the lag counter.
  3. 🔴Option for frame advance to skip lag frames (low priority): Again, sounds easy enough to implement - on frame advance, emulate until the input callback sets the input requested flag. Might get tricky with timings, though.
  4. 🔴Built-in Input Editor: Seems too useful not to do, but also probably very annoying to implement the UI for it.

Since the goal of the issue is to implement movie recording, these items should be used as guidelines and obviously none of them are implemented. Remember The Laws of TAS and the site's requirements.

Movie features

  1. Storing and loading emulator settings and ROM data: Pretty much mandatory. The system has PAL/NTSC variants and a number of IPL ROMs. The discs would need to be hashed in full as well, so the existing hash wouldn't work.
  2. Starting recording from power-on: Also mandatory. Backup memory must be initialized properly too.
  3. Recording peripherals (low priority): Highly recommended in order to support the various Saturn peripherals.
  4. Recording resets: Nice to have... who knows what kinds of ACE the TASers might find from hard resets at strategic points?
  5. Movie chapters (low priority): Optional.
  6. Embedded Subtitles (low priority): Optional.

Input formats

  1. Input data in binary: Either this or text is required, obviously.
  2. Input data in text: Either this or binary is required, obviously.
  3. Frame-by-frame input data: Extremely useful and very easy to do.
  4. Timestamp-based input data: Depends on how movies are implemented. Could come for free, could require a ton of work.
  5. Context-independent input data: Meaning "store the entire input state instead of a delta". Clearly very easy to do.

Contributor guide