feat: read wave from the language, and accept the harmonics form - #20
Merged
Conversation
`wave <name> <32 hex nibbles>` originated here, as a fork of the parser, and survived as a registered dialect extension after the fork was undone. It was never GBA-specific though — deck-player registered its own copy too — so it has been adopted into the language proper (spacedevin/deck#16). That deletes the hex validation and nibble unpacking from this crate. The parser resolves both spellings to 32 levels, and all that is left here is packing two levels per byte for wave RAM. The additive sum lands at bake time, which is the only place it can: the device is no_std on ARM7TDMI with no FPU and no libm, so there is no sin() on the far side. Nothing about the ROM changes — still 16 bytes per table, copied verbatim into WAVE_RAM, so a harmonics table costs exactly what a hex one did. The corpus digest is unchanged across all 54 decks, and a new test pins the part that would be invisible otherwise: a harmonics table and the hex literal it resolves to pack to byte-identical wave RAM. Blocked on the deckfile 1.5.0 release; the pin is bumped ahead of it, so CI will not go green until that publishes.
The released crate, in place of the version pinned ahead of it. `wave` is core grammar there, so this is what actually makes the branch build. All 11 tests pass against the published crate, and the corpus digest across all 54 decks is byte-identical to the pre-change baseline.
spacedevin
marked this pull request as ready for review
August 27, 2026 23:44
Member
Author
|
Unblocked and out of draft — pinned to the released
|
CI runs `cargo fmt --check` on every crate and `cargo clippy --all-targets -D warnings` on this one; the wave changes passed neither. Formatting was mechanical. Clippy found two needless range loops and one real problem: `assert!(b >> 4 <= 15 && (b & 0x0f) <= 15)` is always true, because a nibble of a u8 cannot exceed 15. The assertion proved nothing. Replaced with the invariant actually worth pinning — that packing is lossless and high-nibble-first. Getting that order wrong still yields 16 plausible bytes, so nothing downstream would catch it; the ROM would just play a scrambled waveform. Tests still 11/11 and the corpus digest is unchanged across all 54 decks.
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.
wave <name> <32 hex nibbles>started life here, as a fork of the.deckparser. When the fork was undone it survived as a registered dialect extension — but it was never actually GBA-specific: deck-player registered its own independent copy, andconformance/profiles.jsonstill listed it undergba.extensions.topLevel. A statement every host implements is a language feature, so it has been adopted into the language proper.What changed here
The hex validation and nibble unpacking are gone from this crate. The parser hands over 32 resolved levels whichever spelling wrote them, so the bake only packs two levels per byte:
Songs can now write a table as harmonic amplitudes instead of digits:
Nothing about the ROM changes
The additive sum happens in the parser at bake time — the only place it can, since the device is
no_stdon ARM7TDMI with no FPU and no libm.DeckSong.waves: &'static [[u8; 16]]is unchanged,psg::wave_tablestill copies 16 bytes verbatim intoWAVE_RAM, and the size delta is zero. Aharmonicstable costs exactly what a hex one did.Verification
DECK_CORPUS_DIGEST=1 cargo test -- --nocapture corpusbefore and after diffs clean — not a single note moved.wave_harmonics_and_hex_pack_identicallypins the thing that would otherwise be invisible: aharmonicstable and its hex literal pack to byte-identical wave RAM. This is the hardware end of the language's equality guarantee.cargo test— 11 pass.profile_test::gba_profile_is_honestpasses against the new013-waveconformance case. Worth noting it earned its keep: it caught that my first draft of that case used twotype wavetracks, which the LR35902's single wave channel cannot do. The case was fixed upstream rather than the profile loosened.No
.deckfile in this repo currently uses a top-levelwavestatement — all 44 wave tracks use built-inwave_shape— so there is no existing content to regress.