Skip to content

feat(editor): chord-at-cursor readout at the playhead - #130

Merged
byrongamatos merged 3 commits into
mainfrom
feat/editor-chord-at-cursor
Jul 8, 2026
Merged

feat(editor): chord-at-cursor readout at the playhead#130
byrongamatos merged 3 commits into
mainfrom
feat/editor-chord-at-cursor

Conversation

@ChrisBeWithYou

@ChrisBeWithYou ChrisBeWithYou commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

DAW roadmap 4.17 — the chord-at-cursor third of the item. (Passive key hints + fill-blanks deferred to a follow-up so this stays atomic.) Editor-only.

What

A small, read-only chord name appears next to the measure display, naming whatever sounds at the playhead — C, Am, Gmaj7, D#6, Csus4, E5, …

  • Exact-match vocabulary (@pure:chord-id): common triads, sevenths, sus, and the power-chord dyad, matched exactly against the sounding pitch-class set — so a name shows only when it's certain. when notes sound but form no named chord; blank when nothing sounds.
  • Bass breaks the genuine ties. m7 and 6 are the same four pitch classes (a Cm7 voiced over E♭ is D#6); augmented and dim7 are symmetric. The lowest sounding pitch class picks the spelling. (Sharp spelling throughout — enharmonic-correct labels are the separate 4.16a item.)
  • Pitch-correct per part. Fretted parts resolve to sounding pitch (capo- and tuning-aware, via _rollMidiForNote + _rollPitchCtx); keys parts use their packed pitch; octave doublings collapse. _notesSoundingAtPure gathers notes ringing at the time (onset-inclusive, sustain-aware, zero-sustain notes linger a min-dur so a struck chord registers).
  • Wired into updateTimeDisplay; new #editor-chord-display span. Drum/tempo modes show nothing. Never edits.

Tests — tests/chord_at_cursor.test.js (11, all fail on main)

pc-set dedupe/rounding; triads, sevenths, sus, dim, aug, power chords; the m7-vs-6 and sus2-vs-sus4 bass disambiguation; unmatched clusters → null; the sounding-window predicate (onset-inclusive, sustain, gaps, NaN, non-array); and an end-to-end 6-string E-major voicing naming as E. Full JS suite green.

Scope / fresh region

New @pure:chord-id block after @pure:measure-readout, a updateChordDisplay beside updateMeasureDisplay, one call in updateTimeDisplay, and one HTML span. No core, no spec; no overlap with the open PRs (#112/#125/#126/#127/#128/#129).

Summary by CodeRabbit

  • New Features

    • Added a read-only “chord at the playhead” label in the editor toolbar, shown beside the time/measure display.
    • The label updates live with playback, using exact chord vocabulary matching and a clear output behavior for sounding vs silent/unclear cases.
  • Tests

    • Added tests validating chord identification, sounding-note timing rules, memoization/cache hit behavior, and an end-to-end chord readout scenario.

DAW roadmap 4.17 (the chord-at-cursor third; passive key hints + fill-blanks
deferred to a follow-up). A small, read-only chord name next to the measure
display, naming whatever sounds at S.cursorTime.

- @pure:chord-id: a common triad/seventh/sus/power-chord vocabulary matched
  EXACTLY against the sounding pitch-class set, so a name shows only when it's
  certain. `_pcSetFromMidisPure` collapses octave doublings; `_identifyChordPure`
  tries every root and uses the bass pitch class to break the genuine ties
  (m7-vs-6 share one pc-set — Cm7 over Eb = D#6; symmetric aug/dim7). Sharp
  spelling (enharmonic-correct labels are a separate 4.16a item).
  `_notesSoundingAtPure` gathers notes ringing at the time (onset-inclusive,
  sustain-aware, zero-sustain notes linger a min-dur so a struck chord registers).
- updateChordDisplay: resolves fretted parts to sounding pitch (capo/tuning via
  _rollMidiForNote + _rollPitchCtx), keys parts to their packed pitch; shows the
  name, "—" when notes form no named chord, blank when silent. Wired into
  updateTimeDisplay; new #editor-chord-display span. Drum/tempo modes show
  nothing. Never edits.

Tests: tests/chord_at_cursor.test.js (11) — pc-set dedupe, triads/7ths/sus/dim/
aug/power, the m7-vs-6 and sus2-vs-sus4 bass disambiguation, unmatched→null,
the sounding window (onset-inclusive, sustain, gaps, NaN), and an end-to-end
6-string E voicing. All fail on main. Full JS suite green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HzMBtxWnLGHYkMMXtK38Bg
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@byrongamatos, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 30 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9fef58b6-f5d5-462f-b035-344dfda40723

📥 Commits

Reviewing files that changed from the base of the PR and between c68018c and 836c035.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • screen.html
  • screen.js
📝 Walkthrough

Walkthrough

Adds a read-only chord-at-cursor readout with a new toolbar display, pure chord-identification logic in screen.js, integration into the time-display refresh path, tests for the pure helpers, and a changelog entry.

Changes

Chord-at-cursor readout

Layer / File(s) Summary
Pure chord identification helpers
screen.js
Adds CHORD_FORMULAS and pure helpers to derive pitch-class sets, identify chords with bass tie-breaking, determine sounding notes at a time, and validate cached readout intervals.
UI wiring and display element
screen.html, screen.js
Adds the editor-chord-display placeholder, updates it from the time display refresh path, and renders the chord readout text and title.
Tests and changelog
tests/chord_at_cursor.test.js, CHANGELOG.md
Adds a Node test harness for the pure chord helpers, covers chord naming and sounding-window behavior, and documents the feature in the changelog.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: an editor chord readout at the playhead.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/editor-chord-at-cursor

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

Memoize the playhead chord readout so it stops rescanning all notes on
every playback rAF: cache the readout plus the [lo,hi) sounding-set
stability interval (_soundingIntervalPure) and reuse it while the cursor
stays inside it. Cache validity (_chordCacheHitPure) invalidates on edit,
arrangement swap, a fresh notes-array identity (song load/replace), or
any active drag (move retime OR sustain resize). DOM writes guarded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@byrongamatos

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@byrongamatos
byrongamatos merged commit c385825 into main Jul 8, 2026
@byrongamatos
byrongamatos deleted the feat/editor-chord-at-cursor branch July 8, 2026 07:22
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.

2 participants