feedpak Hand-Editing Guide¶
A .feedpak is just a zip of plain files: some YAML, some JSON, some audio (OGG/WAV by default,
optionally MP3/FLAC/Opus), maybe a JPEG.
That means you can open one up and change it. Want to record your own rhythm guitar take and use
that instead of the mix? Fix an artist typo? Swap the cover art? Replace an automated stem split
that bled drums into the "other" stem? You don't need to rebuild the whole pack from its source —
just edit the file.
This guide walks through the most common edits, aimed at musicians who are comfortable with a text editor and an audio editor like Audacity but don't live on the command line.
For the format schema (what every field means, how the wire format works, how to extend the format with new data types), see the feedpak specification. This document is the how-do-I-actually-edit-mine companion. It describes the format, not any particular application; where an app's behaviour matters, it's flagged as application-specific.
1. The two forms — directory and zip¶
A feedpak exists in two interchangeable forms (spec §2):
| Form | What it is | When to use it |
|---|---|---|
| Directory | A folder named something.feedpak/ with the files loose inside |
Authoring — easy to edit, no zip/unzip cycle |
| Zip | A something.feedpak file (zip with the same files inside) |
Distributing — single file to share |
A conformant reader accepts both, so you can use whichever is convenient.
Unzipping for editing¶
Distribution packs usually ship in zip form. To edit one, unzip it:
- Windows: rename
mysong.feedpak→mysong.zip, right-click → Extract All. Then rename the resulting folder back tomysong.feedpak/(the directory form). Or use 7-Zip and extract without renaming. - macOS: rename
.feedpak→.zip, double-click. Or use The Unarchiver. - Linux:
unzip mysong.feedpak -d mysong.feedpak/.
Once you have the directory form, edit any file inside and your application will pick it up — no re-zipping required for your own use.
When edits to a zip don't appear (caching)¶
Some applications unpack a zip-form pack into a working cache the first time they open it, rather than reading the zip on every load. If you edit the original zip and your changes don't show up, the usual fixes are:
- Re-save the zip so its modification time / size changes — well-behaved readers re-extract when the archive changes.
- Consult your application's docs for how to clear its pack cache.
- Or sidestep caching entirely by using the directory form — most readers use it in place, so there's nothing to invalidate.
This caching is an application implementation detail; it is not part of the format.
2. Record and add your own rhythm stem¶
The use case: an automated stem split (e.g. produced by a tool like Demucs) sounds muddy on the rhythm guitar, and you'd rather play and record your own take.
Step 1 — Set up your reference¶
- Unzip the pack (see §1).
- Look in
stems/and open the reference audio in your audio editor. Two cases: stems/full.oggis present — that's the original mixed audio. Open it directly.- No
full.ogg, only per-instrument stems (guitar.ogg,bass.ogg,drums.ogg, …). This is common after an automated split. Select all the per-instrument stems and open them together — most editors load each as its own track aligned att=0, and playing them all at once reconstructs the full mix. - Note the sample rate (typically
44100 Hz). Your recording must match it.
Step 2 — Record your take aligned to the mix¶
- With the reference track(s) open, add a new audio track.
- Set the editor to play the reference through your headphones while recording your own input.
- Record your part along with the reference from
t=0. Critical: start recording at the very beginning of the song. If you punch in late, alignment will be off when you drop it in. - Stop when the song ends. Trim any silence/click at the very start of your recorded track so its
first sample lines up with
t=0of the reference (zoom in tight and check visually against the kick or first guitar hit).
Step 3 — Export the audio¶
- Solo your recorded track (mute every reference track).
- Export as OGG Vorbis — the recommended baseline format. (WAV, FLAC, MP3, or Opus also work; see the spec's audio-format rules. Keep at least one OGG/WAV stem so the pack stays portable.)
- Quality slider around 5 is a good size/quality balance for OGG (the spec's media
conventions). Save as
rhythm_custom.ogg. - Exporting a different format? The quality-slider guidance is OGG-specific (it doesn't
apply to WAV/FLAC/MP3/Opus). Use the matching file extension (e.g.
rhythm_custom.flac) and use that exact name in the manifestfile:path in Step 4. - Confirm the export sample rate matches the rate you noted in Step 1.
Step 4 — Drop it in and update the manifest¶
- Copy your exported file into the pack's
stems/folder (this guide usesrhythm_custom.ogg; if you exported a different format in Step 3, substitute that filename — e.g.rhythm_custom.flac— everywhere below, and keep at least one OGG/WAV stem for portability). - Open
manifest.yamlin any plain-text editor (VS Code, Notepad++, BBEdit, gedit — all fine; just don't use a word processor). - Find the
stems:block (spec §5.3). Mark the stem you want enabled on open withdefault: true(thefile:value must match the extension you exported):
stems:
- id: rhythm_custom
file: stems/rhythm_custom.ogg
default: true
- id: guitar
file: stems/guitar.ogg
default: false
- id: bass
file: stems/bass.ogg
default: true
- id: drums
file: stems/drums.ogg
default: true
# … other stems unchanged …
Application note. The spec defines
defaultas "enabled when the song opens." Beyond that, some players treat the first-listed stem as the primary mixdown (what you hear without a stem mixer). If your player does, list the stem you want as the main one first as well as marking itdefault: true.
- Save the file. Mind the indentation — two spaces, no tabs. YAML is fussy about this.
Step 5 — Reload and verify¶
Reload the song. A stem-mixer feature, if your application has one, will show a fader for
rhythm_custom next to the others. If you don't see it, check the caching notes in §1.
Common gotchas¶
- Sample-rate mismatch → choppy / pitched-wrong playback. Re-export at exactly the rate the other stems use.
- Mono vs stereo mismatch is fine for playback but levels can feel different — match the other stems if you want consistent mixer behaviour.
- Silence padding at the start of your recording → your stem plays late. Trim it tight before exporting.
- Tabs in
manifest.yaml→ most readers will refuse to load the song. Use two spaces.
3. Replace a bad automated stem¶
Automated separation is good but not perfect — it will occasionally bleed snare into other.ogg
or leave drum overtones in the bass track. Fixing it works the same way as adding a custom stem;
you're just overwriting an existing one.
Option A: overwrite in place¶
- Source or record a clean replacement and export it as OGG at the same sample rate.
- Save it directly over the bad file (e.g.
stems/other.ogg). - Reload — no manifest change needed.
Option B: keep the original, add a replacement¶
Useful if you want to A/B them:
- Save your new file as
stems/other_v2.ogg. - In
manifest.yaml, change thefile:path on that stem's entry:
- The old
other.oggstays in the folder but is no longer referenced. Delete it later if you want.
Removing a stem entirely¶
If you want to drop a stem (e.g. piano.ogg is empty for this song):
- Delete the file from
stems/. - Also remove its entry from
manifest.yamlstems[]. The manifest is the index (spec §2.2) — an orphan entry pointing at a missing file is a broken reference. (Note:stemsmust stay non-empty.)
A word on full.ogg¶
A freshly built pack often starts with just stems/full.ogg. After an automated split, the
builder typically rewrites the manifest to list per-instrument stems and removes full.ogg. If
you're hand-editing and want to keep full.ogg as a fallback (mixed audio in case all the
individual stems are muted), that's fine — leave the file in place and add a manifest entry with
default: false. Don't delete full.ogg unless the per-instrument stems sum cleanly to a full
mix.
4. Edit metadata, cover art, lyrics, tuning¶
All of these are tweaks to either manifest.yaml or files it points at. Open manifest.yaml in a
text editor for the next sections.
Title, artist, album, year¶
Top-level keys in manifest.yaml (spec §5.1). Edit the strings:
Keep the quotes if the value already has them (especially with an apostrophe or colon). Reload the song — the library entry updates next time the library refreshes.
While you're in here, an authored pack may also declare its format version:
feedpak_version: "1.0.0"(spec §4.1). It's optional — an absent value is treated as1.0.0— so you don't need to add it, but it's harmless to.
Cover art¶
Drop a square JPEG or PNG (500–1500 px on a side is the sweet spot) into the pack root and point the manifest at it:
If the manifest has no cover: line, add one.
Lyrics¶
lyrics.json is a flat JSON list of syllable objects (spec §7.1):
[
{"t": 12.34, "d": 0.18, "w": "Hel"},
{"t": 12.52, "d": 0.22, "w": "lo-"},
{"t": 13.10, "d": 0.30, "w": "world"}
]
| Field | Meaning |
|---|---|
t |
Time the syllable starts, in seconds (float) |
d |
Duration in seconds |
w |
The syllable text. A trailing - joins it to the next syllable as one word. A trailing + marks the last syllable of a line. Both are suffixes on a real syllable — not standalone entries |
Common hand-edits:
- Karaoke timing is off — bump t values up or down a few hundredths of a second.
- Wrong word — edit w.
- Missing line break — append + to the last syllable of the line that should end there (e.g.
change "w": "world" to "w": "world+"). Don't insert a standalone "+" entry — that creates
an empty syllable that still consumes word-spacing.
It's plain JSON — edit in any text editor.
Adding a translation or transliteration¶
To ship lyrics in more than one form — the original plus a romanization (romaji, pinyin, …) or a
translation — add a lyric_tracks list to manifest.yaml (spec §5.5).
Each entry points at its own lyrics.json-shaped file, so write the extra track the same way as
above and reference it:
language: ja # the song's primary sung language (BCP 47)
lyrics: lyrics.json # keep this — it's the fallback for older readers
lyric_tracks:
- id: ja
file: lyrics.json
language: ja
kind: original
- id: romaji
file: lyrics_romaji.json
language: ja-Latn
kind: transliteration
- id: en
file: lyrics_en.json
language: en
kind: translation
kind is original, transliteration, or translation. A transliteration usually copies the
original's t/d timings 1:1 (same syllables, re-spelled); a translation carries its own timing.
Leave the plain lyrics: line in place so a reader that predates this feature still shows lyrics.
Tuning¶
Per-arrangement, in manifest.yaml (spec §5.2):
arrangements:
- id: lead
name: Lead
file: arrangements/lead.json
tuning: [0, 0, 0, 0, 0, 0] # E standard
capo: 0
Each number is semitones from E A D G B E, lowest string first. Common tunings:
| Tuning | Offsets |
|---|---|
| E Standard | [0, 0, 0, 0, 0, 0] |
| Eb Standard | [-1, -1, -1, -1, -1, -1] |
| D Standard | [-2, -2, -2, -2, -2, -2] |
| Drop D | [-2, 0, 0, 0, 0, 0] |
| Drop C | [-4, -2, -2, -2, -2, -2] |
| DADGAD | [-2, 0, 0, 0, -2, -2] |
The manifest tuning overrides whatever's stored inside arrangements/lead.json, so fixing it here
is enough — you don't need to touch the arrangement JSON. For 4-string bass, only indices 0–3 are
meaningful; leave the rest at 0.
What not to put in manifest.yaml¶
Don't add per-machine settings (audio device picks, MIDI port IDs), UI state, or your own play counts. A feedpak holds the song's authored data — anything that varies by user or machine belongs in your application's own config, not the pack. See spec §9.5 for the full list.
5. Re-zipping for distribution¶
To share your modified pack, re-zip it:
- Open the
mysong.feedpak/directory. - Select everything inside —
manifest.yaml,arrangements/,stems/, and anylyrics.json/cover.jpg/ side-files. - Zip the contents, not the parent folder. (If you zip the folder, the archive gets a
top-level
mysong.feedpak/directory inside it, andmanifest.yamlwon't be at the zip root where readers expect it.) - Rename
mysong.zip→mysong.feedpak.
For your own use you can skip this entirely — readers accept the directory form.
Tips for hand-editing JSON data files¶
Most data files in a feedpak use JSON, which does not allow comments. If you find yourself making
repeated manual edits to a data file and want to leave yourself notes, rename the file from
.json to .jsonc. The .jsonc extension tells Readers that the file MAY contain // line
comments and /* */ block comments (see spec §8). Readers
strip comments before parsing and good Writers preserve them when re-saving, so your notes survive
round-trips.
For example, to annotate a song_timeline.jsonc with section markers:
{
"version": 1,
"tempos": [
{ "time": 0.0, "bpm": 120.0 } // verse tempo
],
"sections": [
{ "name": "intro", "number": 1, "time": 0.0 },
{ "name": "verse", "number": 1, "time": 16.0 },
{ "name": "chorus", "number": 1, "time": 32.0 }
]
}
Then update the manifest pointer from song_timeline: song_timeline.json to
song_timeline: song_timeline.jsonc. Everything else stays the same.
Two things to keep in mind:
- Comments are the only thing JSONC adds. Trailing commas, single-quoted strings, and other JSON5-style shortcuts are not allowed — once the comments are stripped, the file still has to be valid JSON. (A trailing comma is the easy mistake to make if you're used to editing JSONC elsewhere.)
- Comments mean the file needs a JSONC-aware reader. A
.jsoncfile that actually contains comments can only be opened by a reader that understands the extension; a strict-JSON-only reader will choke on//and/* */. So treat comments as notes for your own working copy — if you plan to share or distribute the pack, keep its data files as comment-free.json. (A comment-free.jsoncfile is just JSON with a different name, so it's always safe.)
Out of scope (for now)¶
- Authoring a pack from scratch (no source file to convert) — more of a developer task. Start at spec §8 (Reading and writing).
- Editing notes / chords in
arrangements/*.json— technically possible but extremely tedious by hand: hundreds of objects with short field names per song. The fields are documented in spec §6 (Arrangement JSON), but for any real chart edit you want a dedicated arrangement editor. (If you do attempt it, consider renaming the file to.jsoncso your edits can carry comments.) - Loudness normalization / advanced stem processing — out of scope here; standard audio-editor
or
ffmpegworkflows apply to any OGG file before you drop it intostems/.