fm2

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 25, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package fm2 reads and writes FCEUX .fm2 movie files: a small text header identifying the ROM, then one input line per frame. It is the interchange format for recorded play, interactive test-ROM automation, and existing TAS movies. The package is self-contained: it depends only on the standard library and knows nothing about the emulator core, so it is reusable by any NES project.

Index

Constants

View Source
const (
	BtnA      uint8 = 1 << 0
	BtnB      uint8 = 1 << 1
	BtnSelect uint8 = 1 << 2
	BtnStart  uint8 = 1 << 3
	BtnUp     uint8 = 1 << 4
	BtnDown   uint8 = 1 << 5
	BtnLeft   uint8 = 1 << 6
	BtnRight  uint8 = 1 << 7
)

Button bitmasks in NES controller serial-shift order (A first). fm2 keeps its own copy of these, identical by the standard hardware convention to the emulator's, so the package has no dependency on the emulator core. A Frame's port bytes use this layout, so they can be handed straight to a controller.

Variables

This section is empty.

Functions

This section is empty.

Types

type Frame

type Frame struct {
	Reset bool  // soft reset (.fm2 command bit 0), applied before this frame
	Power bool  // hard reset / power cycle (.fm2 command bit 1)
	Port0 uint8 // controller 1 buttons
	Port1 uint8 // controller 2 buttons
}

Frame is one frame of recorded input: the controller state for both ports plus any console command (soft reset / power) applied at the start of that frame. The button fields use the Btn* bitmasks.

type Movie

type Movie struct {
	ROMChecksum string // .fm2 "romChecksum" (e.g. "base64:..."); "" if absent
	PAL         bool   // .fm2 "palFlag"
	// Savestate, when non-nil, is an opaque machine snapshot the movie begins
	// from instead of power-on (the FCEUX "movie from savestate" idea). fm2 keeps
	// it as raw bytes and knows nothing of its format; the caller that owns the
	// emulator produces it (SaveState) and consumes it (LoadState). It is stored
	// base64-encoded in a "savestate" header line; an undecodable value is ignored
	// so foreign movies still parse.
	Savestate []byte
	Frames    []Frame
}

Movie is the parsed contents of a .fm2 file: the header fields tanuki cares about and the per-frame input log. tanuki reads .fm2 liberally (unknown headers are ignored) and writes a clean minimal subset that FCEUX and compatible tools can read back.

func Parse

func Parse(r io.Reader) (*Movie, error)

Parse reads a .fm2 movie. Header lines ("key value") set the known fields; unknown headers are ignored so real TAS movies load cleanly. Lines beginning with '|' are per-frame input records following the |command|port0|port1|...| grammar.

func (*Movie) Encode

func (m *Movie) Encode(w io.Writer) error

Encode writes the movie as a minimal .fm2 file: a header with the fields FCEUX needs to load it, then one input line per frame.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL