Skip to content

feat: read, play and emit named wavetables - #9

Merged
spacedevin merged 2 commits into
mainfrom
feat/wave-tables
Aug 27, 2026
Merged

feat: read, play and emit named wavetables#9
spacedevin merged 2 commits into
mainfrom
feat/wave-tables

Conversation

@spacedevin

Copy link
Copy Markdown
Owner

Draft — needs the @spacedevin/deck release from spacedevin/deck#16, which is where wave becomes core grammar.

Deckard could not read a wave line. The statement originated in tish-gba, and deck-player later added its own copy, but the reference host never had one — so a .deck carrying a named table failed to load with unexpected top-level: wave, and the DMG wave channel offered three hardcoded shapes and nothing else. There was no way to author a wavetable here at all.

wave is core grammar now, which resolves both spellings to 32 levels before Deckard sees them:

wave organ 8beffecbbbbaa9888776554444310014
wave organ harmonics 1 0.5 0.33 0.2

What this adds

  • Project model holds the tables by name, keeping mode / harmonics / hex alongside levels.
  • Apply collects them and points each channel at the table its wave_shape names. A UI knob turn arrives as a one-track .deck fragment through this same path, so the binding stays correct when the shape is changed by hand rather than only on load.
  • GameBoyDmg plays a named table in preference to the built-in shapes — the same named_waves.get(wave_shape).unwrap_or_else(built_in) order the GBA bake uses. Levels are already on the 16-level grid wave RAM holds, so unlike the built-ins they need no quantization step.
  • The Wave selector lists the song's tables instead of only Saw/Square/Sine. A shape the song names but has no table for stays selectable, so turning the knob can't silently rewrite it.
  • Emit writes the tables back — and writes a harmonics line as harmonics rather than flattening it to 32 digits. That is the whole point of the parser keeping the source spelling: a save should not throw away what the author wrote. Only tables a channel actually names are emitted, or a project would accumulate a dead wave line every time it loaded a file.

Verification

New test/wavetables.tish (wired into test:js), 12 assertions covering: both spellings collected, harmonics resolving to the same levels as its hex literal, channel binding, harmonics surviving emit unflattened, hex emitting as hex, unused tables not emitted, a full round trip preserving levels and mode, and a built-in shape name binding no table.

Existing suites unchanged: PASS=516, 279, 278, 52, 13, 12, 11, 7, all with FAIL=0.

Note this repo's origin is an HTTPS URL, so the branch was pushed over SSH.

Deckard could not read a `wave` line. The statement originated in tish-gba and
deck-player added its own copy, but the reference host never had one — so a
`.deck` with a named table loaded with "unexpected top-level: wave", and the DMG
wave channel offered three hardcoded shapes and nothing else.

`wave` is core grammar now (spacedevin/deck#16), which resolves both the hex and
`harmonics` spellings to 32 levels before Deckard sees them. What was missing
here is the rest of the path:

- the project model holds the tables, keyed by name
- Apply collects them and points each channel at the table its `wave_shape`
  names; a UI knob turn arrives as a one-track `.deck` fragment through the same
  path, so the binding stays current when the shape is changed by hand
- the DMG wave channel plays a named table in preference to a built-in shape,
  which is the order the GBA bake uses
- the Wave selector lists the song's tables instead of only Saw/Square/Sine

Emit writes the tables back, and writes a `harmonics` line AS harmonics rather
than flattening it to 32 digits. That is the whole reason the parser keeps the
source spelling: a save should not throw away what the author wrote. Only tables
a channel actually names are emitted, or a project would grow a dead `wave` line
every time it loaded a file.
The released language package, where `wave` is core grammar — which is what
makes this branch work against a real install rather than a linked build.

All 12 wavetable tests pass against the published package, and the existing
suites are unchanged.
@spacedevin
spacedevin marked this pull request as ready for review August 27, 2026 23:47
@spacedevin

Copy link
Copy Markdown
Owner Author

Unblocked and out of draft — on the released @spacedevin/deck 1.5.3 (up from ^1.3.0).

Everything now verifies against a real install rather than a linked local build:

  • test/wavetables.tish — all 12 pass
  • existing suites unchanged: PASS=516, 279, 278, 52, 13, 12, 11, 7, all FAIL=0

@spacedevin
spacedevin merged commit e8214aa into main Aug 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant