Add chart authoring + serialization API (writers + createEmptyChart) - #125
Open
elicwhite wants to merge 4 commits into
Open
Add chart authoring + serialization API (writers + createEmptyChart)#125elicwhite wants to merge 4 commits into
elicwhite wants to merge 4 commits into
Conversation
The inverse of parseChartAndIni: build a chart from scratch or round-trip
a parsed chart back to files.
- createEmptyChart(): a minimal valid ParsedChart with no source bytes
- writeChartFile() / writeMidiFile(): serialize a ParsedChart to .chart
text / Format-1 .mid bytes
- writeIniFile(): serialize metadata to a song.ini string
- writeChartFolder(): ChartDocument -> flat File[] (notes.{chart,mid} +
song.ini + passthrough assets), the counterpart to parseChartAndIni's
File[] input
- add defaultIniChartModifiers (the parsing-relevant subset of
defaultMetadata), used by createEmptyChart
- export the new writer API from index.ts, along with
eventTypes/EventType/RawChartData/VocalTrackData and Normalized* vocal
aliases for consumers that build/inspect ParsedChart data
Port the writer unit + same-format round-trip tests onto the new test/unit layout and src/ import convention. 120 tests covering createEmptyChart, .chart/.mid/.ini writers, writeChartFolder, and parse->write->reparse fidelity (incl. grouped unrecognized extras).
Addresses the code-quality review of the writer commits (no behavior change — validated by 435 unit tests + an 8k-chart parse->write->parse round-trip with zero fidelity drift). - Decompose the 1458-line midi-writer.ts into a midi-writer/ module: index (orchestrator), shared (event model + builders + note helpers), events, drums, frets, vocals — each under 500 lines. The public `./midi-writer` import path is unchanged (folder index.ts). - Add typed event builders (metaTextEvent / trackNameEvent / lyricsEvent / noteOnEvent / noteOffEvent) in shared.ts, removing ~27 repeated `... as MidiEvent` casts at call sites. - Extract chart/writer-shared.ts (codaTicksFromFreestyle, wrap/unwrap event brackets) and use it from both the .chart and .mid writers, deleting the duplicated coda-derivation and bracket-normalization logic. - Replace magic drumType integers (=== 1 / === 2) with the canonical drumTypes.fourLanePro / fiveLane constants and type the params DrumType. - Harden buildUnrecognizedTrack: stable-sort a passthrough track's events by absolute tick before delta-encoding, so a malformed (non-monotonic) source track no longer crashes the whole write.
test/corpus/roundtrip.mjs walks chart folders and checks parse -> writeChartFolder -> re-parse fidelity (per-track calculateTrackHash + vocal phrase/note/lyric counts) plus idempotence (P2 vs P3) to separate real writer bugs from benign first-pass normalization. Loads the built CJS dist so it runs under plain `node`. node test/corpus/roundtrip.mjs --input <dir> [--input <dir2>] [--limit N]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Chart authoring + serialization API (the inverse of
parseChartAndIni)Adds the ability to build a chart from scratch or round-trip a parsed chart back to files:
createEmptyChart()— a minimal validParsedChartwith no source bytes.writeChartFile()/writeMidiFile()— serialize aParsedChartto.charttext / Format-1.midbytes.writeIniFile()— serialize metadata to asong.inistring.writeChartFolder()—ChartDocument→ flatFile[](notes.{chart,mid}+song.ini+ passthrough assets), the counterpart toparseChartAndIni'sFile[]input.defaultIniChartModifiers— the parsing-relevant subset ofdefaultMetadata, used bycreateEmptyChart.The writers are the inverse of the parser, so they re-derive normalization the parser applies (natural-HOPO force markers, sustain-chain length overrides, disco-flip/tom sentinels, ENHANCED_OPENS vs forceOpen, vocal phrase 105/106 split, etc.) so that
parse → write → parseis faithful.Validation
parse → writeChartFolder → re-parseacross 78,453 real charts: every instrument-trackcalculateTrackHashand vocal phrase/note/lyric count preserved, writers idempotent — 0 fidelity drift. The lone failure in 78K was a corrupt sourceBEATtrack (non-monotonic ticks);buildUnrecognizedTracknow stable-sorts passthrough tracks so malformed input no longer fails the whole write.test/corpus/roundtrip.mjs.Structure
midi-writer.tsis organized as amidi-writer/module (indexorchestrator +shared/events/drums/frets/vocals), with typed event builders to avoid repeatedas MidiEventcasts and awriter-shared.tsfor coda/bracket logic shared with the.chartwriter.Note for review
A few
index.tsexports were added for downstream consumers that build/inspectParsedChartdata — theNormalized*vocal aliases andeventTypes/EventType/RawChartData/VocalTrackData. Happy to drop any you'd rather keep internal.