Skip to content

fix(capo): read capo charts' fretted notes from the nut - #74

Closed
mattromano wants to merge 1 commit into
got-feedBack:mainfrom
mattromano:fix/73-capo-expected-pitch
Closed

mattromano wants to merge 1 commit into
got-feedBack:mainfrom
mattromano:fix/73-capo-expected-pitch

Conversation

@mattromano

Copy link
Copy Markdown

What

Closes #73

Capo charts follow the Rocksmith convention: a fretted note's fret counts from the nut, and fret 0 means open, which sounds at the capo. A capo-4 E chord is A7 D6 G0 B5. Note detection added the capo to every fret, so each fretted note was expected capo semitones sharp and capo charts barely scored.

  • _ndMidiFromStringFret now uses open + fret for fretted notes and open + capo for open ones, through a new helper _ndAbsoluteFret. Every expected-pitch, band-range and chord-member calculation already goes through this function, so this one change covers them all.
  • _ndMidiToStringFret is the display fallback for noodling between chart notes. It now reports the fret counted from the nut, so it matches how the chart writes it.
  • Desktop engine: the native verifier computes open + capo + fret itself, and there's no option to change that. Both bridge funnels (_ndBridgeSetChart, _ndBridgeScoreChord) now pass the engine capo: 0 and move open notes to the capo fret (_ndEngineCapoPayload), so the engine expects the same pitches as the JS path. This also covers the contained chart and setVerifyTarget scoring. A verify context that passes tuning + capo now uses the chart convention, which _ndSanitizeVerifyCtx already called "the chart convention". The openMidis path still forces capo 0, so it's unchanged.
  • README: a short note on how capo charts are read.

Version bumped 1.32.0 → 1.33.0 in plugin.json, package.json and _ND_VERSION. This collides with #72, which bumps to the same version. Whichever merges second needs a one-line re-bump.

Related: #72 (effective tuning / getCapo()). That PR changes where capo comes from, and this one changes how it's applied, so they don't depend on each other. If both land, a chart-transform capo goes through the same mapping. Both PRs edit the two bridge funnels on adjacent lines, so expect a small textual conflict there.

Not in this PR: core has the same base + offset + capo + fret formula in lib/song.py (pitch_from_base / note_pitch_midi). The highway's scale-degree fill in lib/routers/ws_highway.py uses it. That's a core change and worth its own issue.

Tests

  • New test/capo_expected_pitch.test.js (6 tests):
    • capo 4: A7 D6 G0 B5 maps to E3 G#3 B3 E4, and the open low E maps to G#2
    • no capo: unchanged
    • capo + tuning offset (drop D, capo 3)
    • the display fallback reports nut-relative frets and round-trips
    • _ndEngineCapoPayload rewrites only open notes, keeps technique flags, and returns a capo-0 payload unchanged
    • end to end: the desktop engine setChart receives capo: 0 and G0 → G4
    • Before the fix, 5 of the 6 tests fail. The no-capo test passes both ways.
  • test/verify-target-context.test.js: the IPC assertion now expects the capo folded into the frets (capo: 0, a fretted target keeps its fret) instead of capo: 2 being passed through.
  • npm test: 359/359 pass. node --check screen.js is OK, and feedBack-plugin-spec/tools/validate.py reports ok.
  • One baseline note: on Windows, queue_set_summary.test.js › "last-song Exit retires the log…" fails intermittently in the full run on unmodified main and passes on its own. It passed in this branch's final run.

Checklist

  • Tests added/updated for new behaviour
  • Version bumped in all three places (version_sync.test.js green)
  • Commits are DCO signed off (git commit -s)

🤖 Generated with Claude Code

Rocksmith capo charts write fretted notes at their absolute fret and
only fret 0 means open (sounding at the capo): a capo-4 E chord is
A7 D6 G0 B5. Expected pitch added the capo to every fret, so each
fretted note was expected `capo` semitones sharp and capo charts
barely scored.

Expected pitch is now open + fret for fretted notes and open + capo
for open ones. The display fallback reports frets from the nut too.
The desktop engine applies open + capo + fret itself, so both bridge
funnels hand it capo 0 with open notes moved to the capo fret.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: mattromano <42412983+mattromano@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 46 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 8533c69d-f516-48ed-af1c-29b3a1754168

📥 Commits

Reviewing files that changed from the base of the PR and between 412433d and 3031c90.


📒 Files selected for processing (6)
  • README.md
  • package.json
  • plugin.json
  • screen.js
  • test/capo_expected_pitch.test.js
  • test/verify-target-context.test.js


  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mattromano

Copy link
Copy Markdown
Author

Consolidated into #84 (commits kept, rebased onto main, plus the review fixes).

@mattromano mattromano closed this Oct 15, 2026
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.

Capo charts: every fretted note is expected capo semitones sharp

1 participant