Reconstructions
A reconstruction is one converted audio sample: the per-channel instruction streams that
produce the NES approximation of an original recording. It is
stored as a .stn file. Reconstruction algorithms explains
how one is produced. This page documents the file.
The file has what is played, not what it sounds like. The audio is rendered from the instructions whenever it is needed. That keeps the file small and keeps what the application shows in step with what an export plays.
▍Contents
A .stn file is one MessagePack map:
| Field | Contents |
|---|---|
metadata |
the application name and version, and the reconstruction data version checked on load (see Versioning) |
id |
a unique identifier for the reconstruction |
config |
a frozen snapshot of the generation configuration it was made with: sample rate, NES frequency, spectrum method, gamma, and the rest |
coefficient |
the working level, the single scale factor applied to the input to fit the NES channels' range. It lets the reconstruction and the original be shown and played on a common scale |
instructions_data |
one entry per channel (below) |
stems_data |
the stems setup, the recordings behind it, and which stem holds each frame (below) |
instructions_data
One entry per channel:
| Field | Contents |
|---|---|
channel_name |
pulse1, pulse2, triangle or noise |
instructions |
the stream the channel plays, one instruction per frame. A FamiTracker export is built from this |
initial_pitch |
the note the channel's arpeggio offsets are measured against, chosen when the reconstruction is built. An export reads the offsets against this pitch, so editing an arpeggio moves the frames around a fixed base (see FamiTracker export) |
held_features |
the dimensions left to the channel. An export writes them as disabled slots, and every note sounds them at the value a song starts on |
A channel whose every frame rests is standing by, and its stream is stored as no frames at all. A file that has streams only for the channels it plays reads as all four channels, and the rest come back standing by.
stems_data
| Field | Contents |
|---|---|
config |
the stems setup the conversion ran under: one entry per recording, and the hierarchy of levels |
sources |
one per entry: the stem_id it was converted as, the name it is known by, and the path it was read from, absent once detached |
assignments |
per channel, the stem_ids holding each frame, parallel to that channel's stream |
scale |
the recording scale: the factor the conversion divided every recording it read by, measured on the whole set before any recording left. Reading the recordings at it keeps each one at the level it held in the conversion. Absent in a file upgraded from data version 2.1, which holds one recording that reads at its own peak |
Every reconstruction has this record. A conversion from a single file records one stem covering every
channel it plays. Every entry holds a frame on some channel, unless no entry does: a recording left holding
none leaves the record, with its source and its place in the hierarchy. The recordings that stay keep their
ids. Two ids name no recording. -1 is a resting frame. -2 is a frame the reader wrote by
hand: it answers to no recording and survives every removal. A frame rests where its channel is silent:
where no source took it, where a source's channel count or the hierarchy left it free, or where decoding
settled on a silent instruction.
A recording's name belongs to the document and its path to this machine. A detached reconstruction therefore keeps every name and has no location.
The stems setup as JSON
sampletones convert --stems reads the same setup, written as JSON with the same fields. It has one
entry per recording, in the order the recordings are given. Each entry names the channels it may occupy,
the ones it bends, the drives it pushes each of them at and the channel_cap channels it may sound at
once. A hierarchy lists the stem ids by precedence level. A drive settles which instruction each frame
records while the conversion runs, so a reconstruction plays the instructions it names. An entry without
drives is read at unit drive on every channel it holds, and an entry without channel_cap may sound
all four. In this example, the first recording is on the pulses, with its second pulse pushed harder and
held to one channel a frame. The second recording is on the rest as it stands:
{
"entries": [
{
"id": 0,
"settings": {
"channels": ["pulse1", "pulse2"],
"bends": ["pulse1", "pulse2"],
"drives": {"pulse1": 1.0, "pulse2": 2.5},
"channel_cap": 1
}
},
{"id": 1, "settings": {"channels": ["triangle", "noise"], "bends": ["triangle"]}}
],
"hierarchy": {"levels": [[0], [1]]}
}
▍Detached reconstructions
A reconstruction normally remembers the file each of its recordings was read from. Embedding one in a project makes it part of a shareable artifact, where an absolute path on the author's machine means nothing to anyone else. Detaching lets those locations go and keeps the instructions, the stems assignment and every recording's name. The reconstruction stays self-contained, a saved project stays portable, and the document still says which recordings it was built from.
▍Versioning
Each file records the reconstruction data version it was written with, and the application version beside it for reference. A file at the supported version loads as it stands. A file at an older version the upgrade chain reaches is migrated in memory to the current shape first. Any other file is declined. Data compatibility describes the chain.
The current data version is 2.2. A file at data version 2.1 carries no stems record. Its upgrade records one recording covering the channels the run handed out, and leaves the recording scale unmeasured.
▍Storage and export
.stn files live in the documents folder. A file is a deflated MessagePack
payload and is self-contained: the instructions, the stems assignment and the frozen configuration are
everything needed to play it. The payload names every field of every frame, and a reconstruction has one
frame per channel per frame of audio. The names repeat for every frame, so they deflate to a small
fraction of the file. A payload stored plainly opens as it stands, so a file written by an earlier build
still opens.
The instruction streams can be exported to a tracker, as one instrument per channel or as a whole module. See FamiTracker export and Bitphase export.