WavAmpster Station Package Format
packaging tool, the runtime player, or a cart that ships its own stations.
Status: v1 (GWP-599 / GWP-676). Concretizes the approved
WavAmpster design (deleted 2026-07-29; recover from git history).
What a station is
Section titled “What a station is”A station is a background music playlist for the deck: an ordered set of
tracks the operator tunes in the WavAmpster player, which then play in the
background while they use the rest of the deck. WavAmpster plays real PCM
audio (the deck’s PCM lineage), never PSG chiptune — see
music.md for the separate PSG ambient-music system.
A station is a directory, not a binary container:
<station-id>/ station.knst ; the playlist manifest (this format) 01-neon-rain.pcm ; one raw-PCM file per track, playback order 02-cold-transit.pcm 03-static-bloom.pcmThis is deliberately the design’s “one playlist manifest + its rendered PCM
files.” The same directory layout is the single format shared by all three
station sources (below), so nothing needs a bespoke packer to read a station —
the runtime open()s the manifest and streams the .pcm files directly, the
way the deck already treats raw PCM assets.
Audio format
Section titled “Audio format”Every track .pcm file is raw, headerless PCM:
| Property | Value |
|---|---|
| Encoding | signed 16-bit little-endian (S16LE) |
| Channels | mono (1) |
| Sample rate | 44 100 Hz |
| Container | none — raw samples, no WAV/RIFF header |
| Extension | .pcm |
Sample count is filesize / 2. This matches the emulator’s SDL output device
exactly (S16 / 44 100 / mono), so the runtime mixes station samples straight
into the audio buffer with no resampling — all decode and resampling happen
once, at build time, in the sdk/ tool. It also matches the deck’s canonical
“44.1 kHz mono PCM” audio (see the Canonical Hardware Specification in the
umbrella CLAUDE.md; do not restate rates here).
Note on “bark-matched.” The design calls the format “bark-matched.” The
.pcmfiles underruntime/assets/barks/are actually 8 kHz / 8-bit and currently dormant (no runtime PCM path consumed them). Stations are the first live PCM path on the deck; they target the 16-bit / 44.1 kHz output format, not the legacy bark rate. Do not conflate the two.
The manifest — station.knst
Section titled “The manifest — station.knst”station.knst is a small, line-oriented UTF-8 text file. It is trivial to emit
(the Rust tool) and trivial to parse (a ~40-line C reader in the runtime) —
neither side needs a TOML/JSON dependency.
# KN-86 WavAmpster station manifestversion: 1id: idleware-nightshiftname: NIGHTSHIFTformat: pcm-s16le-44100-monotrack: 01-neon-rain.pcm | Neon Rain | 213402track: 02-cold-transit.pcm | Cold Transit | 187015track: 03-static-bloom.pcm | Static Bloom | 240900Grammar
Section titled “Grammar”- One directive per line. Leading/trailing whitespace is ignored.
- A line whose first non-space character is
#is a comment. Blank lines are ignored. - A directive is
key: value. The key is lowercase; whitespace around the:is trimmed.
Header keys
Section titled “Header keys”| Key | Req | Meaning |
|---|---|---|
version | yes | Manifest schema version. 1 today. A reader MUST reject a version it does not understand. |
id | yes | Stable station identifier, [a-z0-9-]+. The selector for (station-tune id). Unique among discovered stations. |
name | yes | Operator-facing display name (short; UPPERCASE by house convention for the amber grid). |
format | yes | Audio format token. v1 supports exactly pcm-s16le-44100-mono. A reader MUST reject an unknown token (forward-safety). |
Unknown header keys are ignored (forward-compatibility). Unknown format
values are a hard error — the file is claiming an audio layout the reader can’t
stream.
Track rows
Section titled “Track rows”Each track: line is one track. Manifest order is playback order (not
filename order — the NN- filename prefix is a convenience, not authoritative).
The value is three pipe-delimited fields, each trimmed:
track: <pcm-file> | <title> | <duration-ms>| Field | Meaning |
|---|---|
<pcm-file> | Track filename, relative to the station directory. No path separators; must exist. |
<title> | Operator-facing track title (from the source file’s ID3 tag, else its filename stem). |
<duration-ms> | Integer track length in ms (samples * 1000 / 44100). Informational — the player derives exact length from the file size; a reader may treat it as a hint. |
At least one track: row is required. A station with zero tracks is invalid.
Station sources
Section titled “Station sources”All three use the identical directory + manifest format:
- Built-in stations ship in the system image under
runtime/assets/stations/<station-id>/. The host scans that directory at boot; every subdirectory containing a validstation.knstis one station. - Cart-contributed stations — a cart may carry a
stations/<id>/subtree. Discovered by the same scan when the cart is mounted; the format is identical, so a cart station is a first-class station with no special-casing. - Future broadcast / signal sources tie in as just another station source — no format change.
Producing a station
Section titled “Producing a station”The knamp tool in sdk/knamp/ (GWP-677) is the reference producer: a folder of
.mp3 / .wav → decode → downmix to mono → resample to 44 100 Hz → quantize to
S16LE → NN-<slug>.pcm per track + an emitted station.knst. Titles come from
ID3 tags, falling back to the filename stem; tracks are ordered by source
filename. Hand-authoring a station (drop raw .pcm files + write the manifest)
is equally valid.
knamp build ~/Music/kn86-stations/idleware-vol1 runtime/assets/stations/idleware-vol1All decode happens here, on a workstation. The deck ships no decoder and streams
the rendered PCM only. To install stations on a real device, use the stations
Ansible role (hosts/device/tools/sd-provision/converge/stations.yml), which
runs this tool on the control node and pushes the result.
Streaming, literally. The runtime reads a track through a fixed 256 KB ring
rather than loading it whole, so a track costs the same memory whether it runs
one minute or ten (ADR-0060). Two consequences for authoring: track length is
unbounded by device RAM, and the .pcm file must stay readable for the whole
time it plays, because a station directory is opened lazily rather than slurped
at tune time.
Versioning
Section titled “Versioning”version: 1 is the initial schema. Additive header keys are backward-compatible
(readers ignore unknown keys). A breaking change (new required key, new
format token, changed track-row shape) bumps version and readers gate on it.
Related
Section titled “Related”WavAmpster design(deleted 2026-07-29; recover from git history) — the approved brief.music.md— the separate PSG-only ambient music system (chiptune, not PCM).clip-system.md— the other pre-rendered asset primitive (terminal animation).- Canonical Hardware Specification (umbrella
canonical-spec.md) — the deck’s audio + display source of truth.
Inspirations
Section titled “Inspirations”Assigned by Josh in the kn86-inspo workbench. Full map: cart-inspiration-map.md.
| Source | Category |
|---|---|
| 4TRK | music app |
| AetherTune | music app |
| PulseDeck | music app |
| asak | music app |
| audium | music app |
| cliamp | music app |
| valveFM | music app |
| waves | music app |
| cmus | terminal app |