Skip to content

Commit 23e7106

Browse files
authored
fix(player): run gen_block through the language's dialect dispatch (#22)
* fix(player): run gen_block through the language's dialect dispatch `Apply` stored the raw `gen_block` — `{ generatorId, lines }` — straight onto `ch.generatorSpec`, so a dialect registered through `registerGenBlockDialect` was never consulted. The language has the extension point (`parseGenBlock` dispatches to the registered handler and falls back to a raw shape when there is none); the player just wasn't calling it. The effect is silent: a voice that needs the parsed graph, like `matrixFm` or `patch`, finds `generatorSpec.graph` empty, falls back to a default tone, and plays something that is not the patch in the file. No error, no substitution recorded. Additive and non-breaking. `generatorId` and `lines` stay where they were; `kind`, `tplHeaderId` and `version` are now populated, and `graph` appears when a dialect provides one. Hosts registering no dialect see the same shape as before. Note this is necessary but not sufficient. deck-player and @spacedevin/deck-synths each inline their own copy of @spacedevin/deck — the player against the monorepo working copy, the synths against 1.5.3 from npm — so they hold two separate dialect registries and a dialect registered in one is invisible to the other. Deduplicating the language package is what makes this fix reach across hosts. * docs(player): the bake does not agree on `square` yet The comment added with the waveform fallback fix claimed `square` ignores `duty` "on both sides". It does not. deckpack.rs `pcm_table` has no `square` arm, so the bake falls through to pulse and honours `duty` — `gen waveform square duty 25` is 50% in the browser and 25% in the ROM. Say so rather than asserting a parity that isn't there.
1 parent 6171ef2 commit 23e7106

2 files changed

Lines changed: 22 additions & 3 deletions

File tree

packages/player/src/generators/GbaDirectSound.tish

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ fn getGbaBuffer(ctx, shape, duty) {
6868
} else if (shape === "triangle") {
6969
v = phase < 0.5 ? (phase * 4.0 - 1.0) : (3.0 - phase * 4.0)
7070
} else if (shape === "square") {
71-
// `square` names a 50% wave, so it ignores `duty` on purpose — on both sides.
71+
// `square` names a 50% wave, so it ignores `duty` on purpose.
72+
// NOTE: the GBA bake does not agree yet — deckpack.rs `pcm_table` has no `square` arm, so it
73+
// falls through to pulse, which does honour `duty`. `gen waveform square duty 25` is 50%
74+
// here and 25% in the ROM. Tracked on the engine side; do not assume parity for `square`.
7275
v = phase < 0.5 ? 1.0 : -1.0
7376
} else if (shape === "sine") {
7477
v = Math.sin(phase * Math.PI * 2)

packages/player/src/song/Apply.tish

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// against tish-gba's build-time bake (crates/tish-gba-scenepack/src/deckpack.rs), which is the
1010
// canonical list for the two chip synths.
1111

12-
import { parseProgram, parseTrackBody, barSelectorMatches, snakeToCamel } from '@spacedevin/deck'
12+
import { parseProgram, parseTrackBody, barSelectorMatches, snakeToCamel, parseGenBlock } from '@spacedevin/deck'
1313
import { defaultParamsForGeneratorId, isPortedGeneratorId, knownUnportedGeneratorIds } from '../generators/Registry.tish'
1414
import { bootDeckRegistries } from './DeckIds.tish'
1515

@@ -573,7 +573,23 @@ fn applyTrack(track, index, errors, substitutions, waveTables) {
573573
}
574574

575575
if (track.genBlocks && track.genBlocks.length > 0) {
576-
ch.generatorSpec = track.genBlocks[track.genBlocks.length - 1]
576+
let spec = track.genBlocks[track.genBlocks.length - 1]
577+
// Run the block through the language's dialect dispatch instead of storing it raw. A host that
578+
// registers a `gen_block` dialect (`registerGenBlockDialect`, e.g. matrix_fm or patch) gets the
579+
// parsed result here; a host that registers none gets the same shape it always did, plus the
580+
// `kind`/`version` the language reports. Storing the raw block meant a registered dialect was
581+
// never consulted, so a voice needing the parsed graph fell back to a default tone and played
582+
// something that was not the patch in the file.
583+
let parsed = parseGenBlock(spec.generatorId, spec.lines)
584+
if (parsed) {
585+
spec.kind = parsed.kind
586+
spec.tplHeaderId = parsed.tplHeaderId
587+
spec.version = parsed.version
588+
if (parsed.graph !== null && parsed.graph !== undefined) {
589+
spec.graph = parsed.graph
590+
}
591+
}
592+
ch.generatorSpec = spec
577593
}
578594

579595
return ch

0 commit comments

Comments
 (0)