gen3: maintain the channel slice in a stride - #83
Open
ptn wants to merge 1 commit into
Open
Conversation
Axis was not detecting the amp type correctly on most presets on FM3,
firmware 13.
The FM3's fn-0x1F body carries all four channels back to back — channel k's
paramId p lives at k*stride + p — and #channelSlice takes that stride from the
profile's rangeSections. A walk-built runtime profile reports a SHORT one there:
forgefx-midi's buildDeviceCache sets `stride: sec.size`, the count of records the
walk actually collected, not the section's width. The FM3 walk brings back 126 of
DISTORT's 144 (and 62 of CABINET's 106), and runtimeProfileFrom merged the
cache's section meta OVER the catalog's hardware-validated one, so 126 won.
Channel A (base 0) is unaffected, which is why this only surfaced on some
presets. For channels B-D, base = channel*126 lands inside an EARLIER channel's
slice, so every param read there — the amp model included — is a real,
valid-looking value from the wrong param:
• preset 068 "USA MKIIC++ lead", amp on channel B: 126*1+6 = channel A's
paramId 132 (VPLATEMON, 0) → "59 Bassguy Bright" instead of roster 248.
• preset 043 "Friedman BE metal" scene 4, amp on channel C: 126*2+6 = channel
B's paramId 114 (TRIODE1RATIO, raw 23330) → the type decode's `raw > max`
rescale launders it into 117, "CA3+ Clean", instead of roster 259. That
rescale is also why the wrong name SHIFTED (115 → 117) when the roster length
changed — the clue that misdirected the earlier channel-pick investigation.
The channel pick was right all along.
Two independent guards, either one sufficient for the cases above:
• runtimeProfileFrom takes the WIDER of catalog/cache stride. The cache value
is a lower bound, never a measurement; the catalog's is validated. Cache-only
sections are still adopted whole, and a genuinely wider cache stride still
wins if a firmware ever grows one.
• #channelSlice cross-checks the table stride against the wire: the body is
whole channel blocks (itemCount = channels * stride on every shipped
catalog), so a stride that does not divide the advertised itemCount cannot be
the real one → fall back to the width the body implies.
drivers/channel-slice.test.ts replays both presets field-exact over a mocked
transport; without the fix it fails with literally "59 Bassguy Bright".
No cache rebuild needed — the stale short stride is now ignored at read time.
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.
Axis was not detecting the amp type correctly on most presets on FM3,
firmware 13.
The FM3's fn-0x1F body carries all four channels back to back — channel k's
paramId p lives at k*stride + p — and #channelSlice takes that stride from the
profile's rangeSections. A walk-built runtime profile reports a SHORT one there:
forgefx-midi's buildDeviceCache sets
stride: sec.size, the count of records thewalk actually collected, not the section's width. The FM3 walk brings back 126 of
DISTORT's 144 (and 62 of CABINET's 106), and runtimeProfileFrom merged the
cache's section meta OVER the catalog's hardware-validated one, so 126 won.
Channel A (base 0) is unaffected, which is why this only surfaced on some
presets. For channels B-D, base = channel*126 lands inside an EARLIER channel's
slice, so every param read there — the amp model included — is a real,
valid-looking value from the wrong param:
• preset 068 "USA MKIIC++ lead", amp on channel B: 1261+6 = channel A's
paramId 132 (VPLATEMON, 0) → "59 Bassguy Bright" instead of roster 248.
• preset 043 "Friedman BE metal" scene 4, amp on channel C: 1262+6 = channel
B's paramId 114 (TRIODE1RATIO, raw 23330) → the type decode's
raw > maxrescale launders it into 117, "CA3+ Clean", instead of roster 259. That
rescale is also why the wrong name SHIFTED (115 → 117) when the roster length
changed — the clue that misdirected the earlier channel-pick investigation.
The channel pick was right all along.
Two independent guards, either one sufficient for the cases above:
• runtimeProfileFrom takes the WIDER of catalog/cache stride. The cache value
is a lower bound, never a measurement; the catalog's is validated. Cache-only
sections are still adopted whole, and a genuinely wider cache stride still
wins if a firmware ever grows one.
• #channelSlice cross-checks the table stride against the wire: the body is
whole channel blocks (itemCount = channels * stride on every shipped
catalog), so a stride that does not divide the advertised itemCount cannot be
the real one → fall back to the width the body implies.
drivers/channel-slice.test.ts replays both presets field-exact over a mocked
transport; without the fix it fails with literally "59 Bassguy Bright".
No cache rebuild needed — the stale short stride is now ignored at read time.