Skip to content

fix(kls): match real Dexed ScaleLevel/ScaleCurve — sign, exp scale, breakpoint#14

Merged
hakaru merged 2 commits into
mainfrom
fix/kls-fidelity
Jun 29, 2026
Merged

fix(kls): match real Dexed ScaleLevel/ScaleCurve — sign, exp scale, breakpoint#14
hakaru merged 2 commits into
mainfrom
fix/kls-fidelity

Conversation

@hakaru

@hakaru hakaru commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Summary

scaleKeyboardLevel (DX7 Keyboard Level Scaling) and its dx7ref / dx7refmki C reference twins were byte-identical to each other but all three diverged from real Dexed/MSFA dx7note.cc on three parity-invisible, shared Swift+C counts. ReferenceTests.scaleLevelMatchesDEXED compared M2DX against the (equally-wrong) hand-ported C twin, so it stayed green while hiding the bugs — the same circular-reference trap flagged for the detune and pitch-EG dimensions in the DX7 fidelity audit.

Verified verbatim against asb2m10/dexed Source/msfa/dx7note.cc (ScaleLevel, ScaleCurve, exp_scale_data, and the Dx7Note::init outlevel composition).

Fixes (all shared Swift+C — ported verbatim into the Swift engine + both C twins)

Severity Bug Before → After
HIGH Sign inverted — KLS ran backwards isNegative ? capped : -capped → Dexed if (curve<2) scale = -scale (−curves attenuate, +curves boost)
HIGH Exp curve ~8–15× too weak kNlsTable·depth+1024 >> 11 (max ~16) → exp_scale_data[33]·depth·329 >> 15 (reaches 127)
MEDIUM Breakpoint +4 semitones off breakPoint + 21note − breakPoint − 17
LOW Linear +2048 rounding + internal min(127) cap dropped; clamp at the outlevel sum like Dexed

Tests

  • Added scaleKeyboardLevelMatchesRealDexedGoldens — hardcoded real-Dexed golden values spanning left/right, linear/exp, both signs, the hinge, depth 0, and an uncapped >127 case. Breaks the circular M2DX-vs-twin reference.
  • Re-baselined klsAtBreakPoint to the +17 hinge (note 56).
  • MarkICalibrationTests.darkerSustainwithKnownIssue. The corrected KLS removes ROM1A BASS 1's over-bright modulator scaling (Modern sustain centroid 685 → 180 Hz, toward the Dexed-faithful value — a likely contributor to the long-standing "≈2× brighter than Dexed" reports). That drop means the ÷0.6 "Mark I markedly darker than Modern" threshold no longer holds; documented as a known issue to revisit together with the Mark I ÷8 modulation-darkness calibration (a separately-flagged fidelity finding).

swift test: 240 tests pass (1 known issue).

Audit

Completes the keyboard-scaling dimension of the DX7 fidelity audit (docs/dx7-fidelity-audit-2026-06-30.md, app repo).

🤖 Generated with Claude Code

Hakaru Hirose and others added 2 commits June 30, 2026 08:33
…reakpoint

M2DX scaleKeyboardLevel and the dx7ref/dx7refmki C twins diverged from real Dexed dx7note.cc on three parity-invisible, shared Swift+C counts; the circular scaleLevelMatchesDEXED test (M2DX vs the equally-wrong twin) hid them. Port Dexed ScaleLevel/ScaleCurve verbatim into all three:

- sign: -curves (0/1) now attenuate, +curves (2/3) boost (was inverted, KLS ran backwards)
- exp: exp_scale_data[33]*depth*329>>15 (was kNlsTable*depth+1024>>11, ~8-15x too weak)
- breakpoint: note - break_pt - 17 (was +21; whole curve was shifted +4 semitones)
- linear: drop the +2048 rounding term; no internal 127 cap (clamp at the outlevel sum)

Tests: add scaleKeyboardLevelMatchesRealDexedGoldens (hardcoded real-Dexed values, breaks the circular reference); re-baseline klsAtBreakPoint to the +17 hinge (note 56). MarkICalibrationTests.darkerSustain -> withKnownIssue: the correct KLS drops BASS 1's over-bright Modern centroid 685->180 Hz so the x0.6 'Mark I markedly darker' threshold no longer holds (the disputed di8 darkness is markI-ops-dac finding 2). 240 tests pass (1 known issue).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hakaru
hakaru merged commit fa607ba into main Jun 29, 2026
1 check passed
@hakaru
hakaru deleted the fix/kls-fidelity branch June 29, 2026 23:41
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