Skip to content

Investigate "all tunings half-step flat" — code is correct, add regression guard - #17

Merged
palvimaki merged 1 commit into
devfrom
case/tuner-semitone-flat-fix
May 19, 2026
Merged

palvimaki merged 1 commit into
devfrom
case/tuner-semitone-flat-fix

Conversation

@palvimaki

Copy link
Copy Markdown
Owner

Founder report

"all tunings are half step too low" — displayed note/target ~1 semitone flat vs. the actual pitch played, across every tuning.

Root-cause investigation

The hypothesis was a deterministic constant bug (wrong A4, off-by-one MIDI/octave, bin/sample-rate error, shifted note table). Every candidate was checked and ruled out. The codebase is mathematically correct end-to-end.

Verified accurate to <0.1 cents at A4=440 and all standard guitar frequencies (82.41 / 110 / 146.83 / 196 / 246.94 / 329.63 Hz):

Layer File Result
Reference pitch / MIDI formula src/audio/note-math.ts:39-49 440 * 2**((midi-69)/12), 1200*log2() — correct
MIDI↔note name src/audio/note-math.ts:22-37 round-trips E2↔40, A4↔69, E4↔64 — correct
Guitar presets src/domain/instruments/guitar/presets.ts E2=82.407, A4=440.000 exactly — correct
Nearest-string select src/app/state.ts:104 picks the same note, no shift — correct
TS DSP (YIN + MPM) src/audio/dsp/{yin,mpm}.ts <0.5c on synthetic plucks — correct
Production worklet pitch chain (YIN + target-aware) public/worklets/tuner-processor.js <0.1c on synthetic plucks — correct

There is no semitone-flat constant or formula error anywhere in the source. No prior semitone fix exists in history; production is current with dev.

What this PR does

Adds a permanent regression test (test/unit/semitone-flat-regression.test.ts) that feeds exact reference pitches through frequency → MIDI → note and the nearest-string / cents path, asserting 0-cent agreement. A genuine semitone bug would surface here as ≈ -100 cents. The test passes, codifying correctness and catching any future regression.

No production-code change is made because the reported defect does not exist in the code. Fabricating a "fix" would introduce a real bug.

Most likely actual cause (for Founder follow-up, no deploy)

  1. Stale PWA cache — an old cached service worker / tuner-processor.js from before the octave-gate fixes (21fbbf9). Hard-reload / clear site data and retest.
  2. Reference source not at 440 — if tested against another tuner/app/string set that itself isn't A440, every reading would look uniformly flat.
  3. Acoustic — strong low-string inharmonicity / room coupling at the mic; not a code constant.

Recommend the Founder hard-refresh tuner.fi (or bump the SW cache version) and retest before any further code work.

Tests

npm test → 80 files, 299 tests, all green (includes the new regression test).

🤖 Generated with Claude Code

Founder reported every tuning reads ~1 semitone flat. Investigation
found NO deterministic constant bug: note-math (A4=440, MIDI formula),
guitar presets, nearest-string selection, the TS YIN/MPM DSP, and the
production worklet pitch chain all resolve standard guitar frequencies
(82.41/110/146.83/196/246.94/329.63/440 Hz) to <0.1 cents.

This adds a permanent regression test feeding exact reference pitches
through frequency->MIDI->note and the nearest-string/cents path,
asserting 0-cent agreement (a semitone bug would surface as ~-100c).
The test passes, confirming the code is correct. The reported symptom
is therefore environmental (stale cached PWA service worker / worklet,
or a non-440 reference on the source), not a code constant.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@palvimaki
palvimaki merged commit 43940ee into dev May 19, 2026
1 check passed
palvimaki pushed a commit that referenced this pull request Jun 22, 2026
Brings main/production current with live dev: mic-fix PRs #17-19 + 2026-06-22
code-review patch PR #21 (deploy safety, a11y, PWA, DSP). Previously main/
production were stale at v0.1.15.
palvimaki pushed a commit that referenced this pull request Jun 22, 2026
Brings production current with live dev: mic-fix PRs #17-19 + 2026-06-22
code-review patch PR #21 (deploy safety, a11y, PWA, DSP). Previously production
was stale at v0.1.15.
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