FM3 format
FM3 format
The FM3 format is a simple extension of the FM2 format. FM2 files contain data which is needed for replaying the movie, and FM3 just adds Taseditor's working data to the end of FM2 file.
You can read full specifications of FM2 format in the FCEUX Help and on official site.
Every FM3 consists of 3 parts:
- Header (as in fm2)
- Input Log (as in fm2)
- Taseditor data
Header
The Header is always in ASCII plain text format.
It consists of several key-value pairs (lines of text where all symbols before the first space separator are considered to be the keyword and all symbols after this separator are considered to be the text representation of the value).
Newlines may be \r\n or \n.
If a line starts from "|" (pipe), it means the end of Header and the beginning of Input Log.
The key-value pairs may be in any order, except that the first key must be version.
Value text is always terminated by a newline, which the value text does not include.
The value text is parsed differently depending on the keyword, it can be either integer or string.
Keys with integer value:
(also used for booleans, with a 1 for true and 0 for false)
(the value can be stored as int32)
- version (required) – the version of the movie file format; for now it is always 3
- emuVersion (required) – the version of the emulator used to produce the file (e.g. 21060)
- rerecordCount (optional) – the rerecord count
- palFlag (bool) (optional) – true if the movie uses PAL timing
- NewPPU (bool) (optional) – true if the movie uses New PPU
- FDS (bool) (optional) – true if the movie was recorded on a Famicom Disk System (FDS) game
- fourscore (bool) – true if a fourscore was used. If fourscore is not used, then port0 and port1 are required
- port0 – the type of input device attached to the port 0. Supported values are:
- SI_NONE = 0
- SI_GAMEPAD = 1
- SI_ZAPPER = 2
- port1 – the type of input device attached to the port 1. Supported values are:
- SI_NONE = 0
- SI_GAMEPAD = 1
- SI_ZAPPER = 2
- port2 (required) – the type of the FCExp port device which was attached. Supported values are:
- SIFC_NONE = 0
- binary (bool) (optional) – true if Input Log is stored in binary format. FM2 files usually contain Input in text format, for easy editing and splicing. FM3 files usually contain Input in binary format, to save disk space
- length (required in FM3) – movie size (number of frames in the input log). If this key is specified and the number is >= 0, the Input Log ends after specified number of records, and any remaining data should not be parsed (because it's Taseditor data). The Header of FM3s always has this keyword, the Header of FM2s doesn't have it.
Keys with string value:
(their values cannot contain newlines)
romFilename (required) – the name of the file used to record the movie
romChecksum (required) – the base64 of the hexified MD5 hash of the ROM which was used to record the movie
comment (optional) – simply a memo. By convention, the author of the movie should be stored in a comment with the subject "author". Example: "comment author AnS"
subtitle (optional) – a message that will be displayed on screen when movie is played back (unless Subtitles are turned off). Right after the word "subtitle" and following space separator there must be an integer value indicating the frame that the subtitle will be displayed. Any remaining text after the integer and following space separator is considered to be the string displayed. Example: "subtitle 100 Level Two" – at frame 100 the words "Level Two" will be displayed on the screen
guid (required) – a unique identifier for a movie, generated when the movie is created. Meaningless in FM3, because all there's no external savestates associated with the project file.
Input Log
The Input Log section consists of movie records either in the form of text lines or in the form of binary data.
Text format:
Every frame of the movie is represented by line of text beginning and ending with a "|" (pipe).
If fourscore is not used, the fields in the line are as follows:
|commands|port0|port1|port2|
Field commands is a variable length decimal integer which is interpreted as a bit field corresponding to miscellaneous input states which are valid at the start of the frame. Current values for this are:
- bit 0 (number = 1) – Soft Reset
- bit 1 (number = 2) – Power
- bit 2 (number = 4) – Eject/Insert Disk
- bit 3 (number = 8) – Switch Disk Side
The format of port0, port1, port2 depends on which types of devices were attached.
- SI_NONE: the field must be empty
- SI_GAMEPAD: the field consists of eight characters which constitute a bit field. Any character other than ' ' (spacebar) or '.' (dot) means that the button was pressed. By convention, the following mnemonics are used in a column to remind us of which button corresponds to which column: RLDUTSBA (Right, Left, Down, Up, Start, Select, B, A)
- SI_ZAPPER: the field consists of several characters in the following pattern XXX YYY B Q Z
- XXX: %03d – the X position of the mouse
- YYY: %03d – the Y position of the mouse
- B: %01d – 1 if the mouse button is pressed; 0 if not
- Q: %01d – an internal value used by the emulator's zapper code
- Z: %d – a variable-length decimal integer; an internal value used by the emulator's zapper code
If fourscore is used, then port0 and port1 are irrelevant and ignored. The input types must all be gamepads, and each input log record must be in the following format:
|commands|RLDUTSBA|RLDUTSBA|RLDUTSBA|RLDUTSBA|port2|
(commands, player 1, player 2, player 3, player 4, port2)
Binary format:
Input Log section starts with a | (pipe).
Every frame of the movie is represented by a record of a fixed length. The length can be determined by the devices on port0 and port1.
The first byte of each record stores "commands" bit field:
- bit 0 – Soft Reset
- bit 1 – Power
- bit 2 – Eject/Insert Disk
- bit 3 – Switch Disk Side
If fourscore is not used, the remaining bytes in the record depend on which types of devices are attached to port0 and port1:
- SI_NONE: 0 bytes added to the size of record
- SI_GAMEPAD: 1 byte added to the size of record. Bits of the byte represent the state of buttons (bit0 = A, bit1 = B, bit2 = Select, bit3 = SStart, bit4 = Up, bit5 = Down, bit6 = Left, bit7 = Right). If the bit is set, respective button is considered to be pressed, if the bit is clear, the button is not pressed
- SI_ZAPPER: 12 bytes added to the size of record:
- 1st byte – the X position of the mouse
- 2nd byte – the Y position of the mouse
- 3rd byte – 1 if the mouse button is pressed; 0 if not
- 4th byte – an internal value used by the emulator's zapper code
- bytes 5-12 (uint64) – an internal value used by the emulator's zapper code
If fourscore is used, then port0 and port1 are irrelevant and ignored. 4 bytes are added to the size of record. The bits of the 1st byte represent the state of buttons of the 1st joypad (bit0 = A, bit1 = B, bit2 = Select, bit3 = Start, bit4 = Up, bit5 = Down, bit6 = Left, bit7 = Right); bits of the 2nd byte represent the state of buttons of the 2nd joypad, and so on.
Taseditor Data
4 bytes |
unsigned int32 |
FM3 version |
4 bytes |
unsigned int32 |
Saved modules |
4 bytes |
unsigned int32 |
Number of offsets (N = 6) |
4 * 6 bytes |
pointers |
Offsets |
??? |
stream |
MARKERS DATA |
??? |
stream |
BOOKMARKS DATA |
??? |
stream |
GREENZONE DATA |
??? |
stream |
HISTORY DATA |
??? |
stream |
PIANO ROLL DATA |
??? |
stream |
SELECTION DATA |
The data starts right after the last record of the Input Log. If there's EOF after the last record, TAS Editor will interpret the file as an FM2 file.
First 4 bytes of Taseditor Data contain the version of the project file format. The first release version of TAS Editor 1.0 saves projects with version = 3.
Next 4 bytes contain bit field that can be used for determining which modules of Taseditor were saved to the FM3 file:
- bit 0 – Markers were saved
- bit 1 – Bookmarks were saved
- bit 2 – entire Greenzone was saved
- bit 3 – History Log was saved
- bit 4 – Piano Roll position was saved
- bit 5 – Selection History was saved
Next 4 bytes contain the total number of modules, in the version 3 this number must be 6.
Then there are six offsets (4 bytes each) pointing at the data of each module. The offsets are counted from the beginning of the file.
When Taseditor saves the project, it calls all 6 modules that need saving. Each of them saves current writing offset and then serializes its own data into the file stream and moves current write position forward. The order of calling modules is always the same (Markers, Bookmarks, Greenzone, History, Piano Roll, Selection). When loading a project Taseditor calls those modules in the same order and they seek to the given offset and load / deserialize the data from the file.
To check the integrity of the data loaded, every module writes its own ID (string) into the file stream before writing the data. When loading the data it expects the ID to match, if it doesn't match then the module refuses to load following data, creates default state and reports "loading error" to Taseditor.
When using Save Compact settings, modules either save all their data as usual or write dummy ID which indicates that this module didn't save its data into the file. When loading the file a module that detects dummy ID refuses to load following data, creates default state but then reports "loading success" to Taseditor.
Module |
ID when saved |
ID when not saved |
Markers |
MARKERS |
MARKERX |
Bookmarks |
BOOKMARKS |
BOOKMARKX |
Greenzone |
GREENZONE |
GREENZONX |
History |
HISTORY |
HISTORX |
Piano Roll |
PIANO_ROLL |
PIANO_ROLX |
Selection |
SELECTION |
SELECTIOX |
Created with the Personal Edition of HelpNDoc: Free PDF documentation generator