14 KiB
Project Research Summary
Project: YellowJacket v1.2.1 Format Parity Domain: Audio metadata tag writing — OGG Vorbis and WAV format support Researched: 2026-03-18 Confidence: HIGH
Executive Summary
YellowJacket v1.2.1 adds OGG Vorbis and WAV tag writing to achieve full format parity across all four supported audio formats. The existing tagwriter pipeline was designed for format extension — a switch-case in pipeline.go dispatches to format-specific writer functions, and everything downstream (DB sync, events, UI) is format-agnostic. Adding OGG and WAV requires two new writer functions, zero new dependencies, and no frontend changes.
The recommended approach is custom implementations for both formats: a custom OGG page rewriter (~350 LOC) for OGG Vorbis, and a custom RIFF chunk parser (~200 LOC) wrapping the existing bogem/id3v2 library for WAV. No pure-Go library exists for OGG Vorbis tag writing, and the Go WAV ecosystem recently lost its most popular library (go-audio/wav archived Feb 2026). The OGG container format and RIFF chunk format are both well-documented and simple enough to implement directly. Vorbis Comments (used by OGG) are the exact same metadata format already used in FLAC — field names, encoding, and comment structure are identical, enabling significant code reuse.
The primary risk is the OGG page infrastructure: CRC32 checksums use a non-standard bit ordering (MSB-first, not the Go standard library's reflected CRC32), page sequence numbers must be strictly sequential, and granule positions must be preserved exactly. These are well-understood constraints with clear specifications, but incorrect implementation produces silently corrupted files. Round-trip testing (write → read back via dhowden/tag) is the primary mitigation, following the pattern established by the existing MP3 and FLAC writers.
Key Findings
Recommended Stack
Zero new dependencies. Both formats are implemented using Go standard library primitives (encoding/binary, encoding/base64, bytes, io) plus existing dependencies for shared functionality.
Core technologies:
- Custom OGG page rewriter: Parse/write OGG pages with CRC32 and segmentation — no pure-Go OGG writing library exists;
mccoyst/ogg(37 stars, no semver) saves ~80 LOC but adds dependency risk - Custom RIFF chunk parser/writer: Read/write WAV RIFF structure —
go-audio/wavandgo-audio/riffwere archived Feb 2026; RIFF is simple enough for custom code bogem/id3v2(existing): Generate ID3v2 tags for WAVid3chunks — same library already used for MP3 writing, all 8 fields + cover art work identicallygo-flac/flacpicture(existing): Build METADATA_BLOCK_PICTURE binary blocks for OGG cover art — same binary format, just base64-wrapped for OGGfileutil.AtomicWrite(existing): Crash-safe file writes for both formats — proven pattern from MP3/FLAC writers
Expected Features
Must have (table stakes):
- Write all 8 text fields for OGG Vorbis (same Vorbis Comment field names as FLAC)
- Write all 8 text fields for WAV (via ID3v2 in RIFF chunk)
- Preserve existing non-edited metadata (ReplayGain, lyrics, etc.)
- Preserve audio data byte-for-byte (no re-encoding)
- Crash-safe writes via AtomicWrite
- Batch and single-track editing work for both formats
Should have (differentiators):
- OGG cover art via METADATA_BLOCK_PICTURE (base64-encoded FLAC picture block)
- WAV cover art via ID3v2 APIC frame (identical to MP3)
- Preserve existing RIFF INFO chunks when writing ID3v2 to WAV
- Round-trip test coverage (7 tests per format, following FLAC precedent)
Defer (v2+):
- RIFF INFO writing (lossy — can't represent album_artist, disc_number, or cover art)
- Dual-write ID3v2 + RIFF INFO in WAV
- Migrating deprecated OGG
COVERARTfield toMETADATA_BLOCK_PICTURE - RF64 (>4GB WAV) support
- OGG Opus tag writing (different header structure from Vorbis)
Architecture Approach
Both writers integrate into the existing pipeline with minimal modification: add two format constants, extend the DetectFormat() switch, and add two cases to the WriteTrackTags() format dispatch. No new interfaces, no refactoring. The frontend is completely format-agnostic and requires zero changes.
Major components:
ogg.go(~350 LOC) — OGG page parser/writer, Vorbis Comment serializer, CRC32, METADATA_BLOCK_PICTURE encoding,writeOggTags()orchestratorwav.go(~200 LOC) — RIFF chunk parser/writer, ID3v2 tag inid3chunk viabogem/id3v2,writeWavTags()orchestratortagwriter.go+pipeline.go(~15 LOC changes) — Format constants, detection, dispatchogg_test.go+wav_test.go(~600 LOC) — 7 round-trip tests each, following FLAC pattern
Key code reuse:
- Vorbis Comment field mapping: identical to FLAC (extract shared helpers from
flac.go) - ID3v2 tag building for WAV: identical to MP3 (
applyTextChanges(),applyCoverArtChanges()) - AtomicWrite: used as-is by both writers
dhowden/tagfor read-back verification in tests
Critical Pitfalls
-
OGG CRC32 non-standard bit ordering (P1) — OGG uses MSB-first CRC32 with polynomial 0x04c11db7. Go's
hash/crc32uses reflected (LSB-first) ordering and produces wrong checksums. Must implement custom CRC or port fromjfreymuth/oggvorbis/crc.go. -
OGG page sequence number continuity (P2) — Rewriting comment header may change the number of header pages, requiring all subsequent page sequence numbers to be renumbered. Use full-stream rewrite approach (correct by construction).
-
OGG granule position preservation (P3) — Header pages must have granule position 0; audio pages must preserve original granule positions exactly. Corruption here breaks seeking and duration reporting.
-
WAV RIFF chunk size updates (P6) — Adding or resizing the
id3chunk requires updating the outer RIFF header size field. Wrong size makes the file appear truncated to some players. -
WAV chunk word alignment (P10) — RIFF chunks must start at even byte offsets. Odd-length chunks need a padding byte that's NOT included in the chunk's size field but IS part of the physical file.
WAV Metadata Approach Decision
Research revealed a tension between two approaches:
- RIFF INFO: Native WAV format, simple, but can't represent album_artist, disc_number, or cover art
- ID3v2-in-WAV: Reuses existing
bogem/id3v2, full field + cover art support, read bydhowden/tag
Decision: ID3v2-in-WAV. This gives full field parity with MP3, enables cover art, reuses existing code, and round-trips through dhowden/tag (our reader). RIFF INFO is preserved when present but not written to.
Implications for Roadmap
Based on research, suggested phase structure:
Phase 1: WAV Tag Writer
Rationale: Lower risk, faster to implement. Reuses existing bogem/id3v2 library and applyTextChanges()/applyCoverArtChanges() from MP3 writer. RIFF container is simpler than OGG (no checksums, no page segmentation). Building this first proves the pipeline extension pattern works before tackling the harder OGG format.
Delivers: WAV text tag writing (all 8 fields) + cover art + round-trip tests
Addresses: WAV table stakes + WAV cover art (differentiator, but trivial since it reuses MP3 APIC code)
Avoids: P5 (use ID3v2, not RIFF INFO), P6 (careful RIFF size bookkeeping), P10 (chunk alignment padding)
New code: ~200 LOC wav.go + ~250 LOC wav_test.go + ~15 LOC pipeline changes
Estimated effort: Small — RIFF parsing is straightforward binary parsing
Phase 2: OGG Vorbis Text Tag Writer
Rationale: OGG requires the most new infrastructure (page parser, CRC32, segmentation). Text-only tag writing exercises all the hard parts (page rewrite, CRC, sequence numbers) without the added complexity of multi-page comment packets from large cover art. This is the riskiest phase and benefits from Phase 1 having proven the pipeline extension works.
Delivers: OGG Vorbis text tag writing (all 8 fields) + round-trip tests
Addresses: OGG text field table stakes, audio data preservation, existing comment preservation
Avoids: P1 (CRC32), P2 (sequence numbers), P3 (granule positions), P4 (three-header structure), P7 (framing bit), P8 (packet prefix)
New code: ~300 LOC ogg.go (page infra + text writer) + ~300 LOC ogg_test.go
Estimated effort: Medium — OGG page infrastructure is the hardest new code in this milestone
Phase 3: OGG Vorbis Cover Art
Rationale: Separated from Phase 2 because it adds multi-page packet complexity (large base64-encoded images can exceed the ~64KB OGG page limit). Text fields exercise the page infrastructure with small comment packets; cover art stress-tests it with large ones. Can be deferred if Phase 2 runs long without blocking the milestone.
Delivers: OGG Vorbis cover art embed/remove via METADATA_BLOCK_PICTURE
Addresses: OGG cover art differentiator
Avoids: P9 (METADATA_BLOCK_PICTURE format), P15 (multi-page segmentation for large payloads)
New code: ~50 LOC additions to ogg.go + ~50 LOC additions to ogg_test.go
Estimated effort: Small if Phase 2's page infrastructure is solid; medium if multi-page edge cases surface
Phase 4: Edge Cases and Cleanup
Rationale: Validation and hardening after core functionality works. Adds detection/rejection of unsupported edge cases, size warnings, and documentation updates. Delivers: RF64 detection, multi-stream OGG detection, large file warnings, PROJECT.md updates Addresses: P13 (multi-stream OGG), P16 (RF64 WAV), P12 (disk space for large files) New code: ~30 LOC validation checks + documentation updates Estimated effort: Small
Phase Ordering Rationale
- WAV before OGG: WAV is lower risk (reuses existing ID3v2 library, simpler container) and proves the pipeline extension pattern. OGG requires all-new page infrastructure with correctness-critical CRC and sequencing.
- OGG text before OGG cover art: Text fields exercise the page rewrite with small comment packets. Cover art adds multi-page complexity that should only be attempted once the core page infrastructure is validated by round-trip tests.
- Edge cases last: Detection/rejection of unusual files (RF64, multi-stream) is low risk and low effort — just validation guards at file-open time.
Research Flags
Phases likely needing deeper research during planning:
- Phase 2 (OGG text writer): The OGG page re-segmentation and CRC implementation is the most complex new code. The spec is clear, but implementation details (lacing values, continuation flags, packet splitting across pages) benefit from studying
jfreymuth/oggvorbissource as reference. Phase-level research recommended.
Phases with standard patterns (skip research-phase):
- Phase 1 (WAV writer): RIFF parsing is trivial; ID3v2 tag generation reuses existing code. Well-documented, no unknowns.
- Phase 3 (OGG cover art): METADATA_BLOCK_PICTURE format is well-specified; base64 encoding is trivial. Only depends on Phase 2's page infrastructure being correct.
- Phase 4 (edge cases): Simple validation checks with clear specifications.
Confidence Assessment
| Area | Confidence | Notes |
|---|---|---|
| Stack | HIGH | Zero new dependencies; all recommendations based on official specs and existing codebase analysis |
| Features | HIGH | Feature set derived from official format specs (Xiph.org, RIFF) and existing codebase field model |
| Architecture | HIGH | Full codebase analysis confirms pipeline was designed for format extension; minimal changes needed |
| Pitfalls | HIGH | Pitfalls sourced from official OGG/RIFF specs, cross-referenced with existing library implementations |
Overall confidence: HIGH
Gaps to Address
bogem/id3v2WAV compatibility: The library'sOpen()/Save()API expects MP3 file structure. For WAV, we'll need to useParseReader()to read existing ID3v2 tags from a byte slice, andWriteTo()to serialize the tag to bytes for embedding in the RIFF chunk. This needs validation during Phase 1 implementation — ifParseReaderdoesn't work for standalone tag parsing, we may need to create tags from scratch (losing existing ID3v2 data in the WAV).- OGG test fixture creation: Cannot programmatically generate a valid OGG Vorbis file (requires Vorbis codebook data in setup header). Need to embed a minimal OGG fixture via
//go:embed. Can be created once with ffmpeg during Phase 2 setup. - Multi-stream OGG prevalence: Research confirms multi-stream OGG music files are extremely rare, but we should detect and reject them rather than silently corrupting. Validation during Phase 2.
Sources
Primary (HIGH confidence)
- OGG framing specification: https://xiph.org/ogg/doc/framing.html
- OGG RFC 3533: https://xiph.org/ogg/doc/rfc3533.txt
- Vorbis I Specification (comment field): https://xiph.org/vorbis/doc/Vorbis_I_spec.html
- Vorbis Comment specification: https://xiph.org/vorbis/doc/v-comment.html
- METADATA_BLOCK_PICTURE: https://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE
- FLAC Picture block format: https://xiph.org/flac/format.html#metadata_block_picture
- RIFF/WAV format: https://www.mmsp.ece.mcgill.ca/documents/AudioFormats/WAVE/WAVE.html
Secondary (MEDIUM confidence)
- WAV metadata overview: https://en.wikipedia.org/wiki/WAV#Metadata
- RIFF tag reference: https://exiftool.org/TagNames/RIFF.html
Libraries (HIGH confidence — direct code review)
jfreymuth/oggvorbisv1.0.5: OGG page reader reference, CRC32 lookup tabledhowden/tag: Reads OGG + WAV tags; validates round-trip correctnessbogem/id3v2v2.1.4: ID3v2 tag generation for WAVid3chunksgo-flac/flacpicturev2.0.2: FLAC picture block builder, reused for OGG METADATA_BLOCK_PICTUREgo-audio/wav(ARCHIVED 2026-02-21): Evaluated and rejectedmccoyst/ogg(37 stars, no semver): Evaluated and rejected — marginal benefit vs dependency risk
Codebase (HIGH confidence — validated in v1.2)
backend/tagwriter/flac.go— Vorbis Comment manipulation patterns to reusebackend/tagwriter/mp3.go— ID3v2 + AtomicWrite patterns to reuse for WAVbackend/tagwriter/pipeline.go— Format dispatch switch to extendbackend/tagwriter/tagwriter.go— TagChanges model, format detection, helpersbackend/fileutil/atomicwrite.go— Crash-safe file write utility
Research completed: 2026-03-18 Ready for roadmap: yes