Skip to content

feat(editor): clickable, audible keyboard gutter in the piano roll - #128

Merged
byrongamatos merged 3 commits into
mainfrom
feat/editor-keyboard-gutter
Jul 8, 2026
Merged

feat(editor): clickable, audible keyboard gutter in the piano roll#128
byrongamatos merged 3 commits into
mainfrom
feat/editor-keyboard-gutter

Conversation

@ChrisBeWithYou

@ChrisBeWithYou ChrisBeWithYou commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

DAW roadmap 4.1 (SONG-EDITOR-DAW-WORKSPACE-DESIGN.md §F4). Editor-only.

What

In keys/piano view the piano roll's left axis was a flat dark strip with sparse C/F labels. It's now drawn as an actual keyboard laid on its side, and clicking a key auditions its pitch.

  • Keyboard render (drawPianoLabels rewritten): white/black key shading per MIDI row — black keys inset from the front (right) edge so the white keys' tails read between them, the side-on keyboard look — C rows labelled with their octave (C4…), white-to-white separators only where a real keyboard has no black key between (E–F, B–C), and a front-edge divider so the gutter reads as a panel. String view is untouched.
  • Click to hear (_auditionPitch + midiToFreq): a gentle, hearing-safe voice — soft 6 ms attack, ~0.28 peak, ~0.32 s decay — routed through the existing master limiter, i.e. the edit-blip envelope, pitched and a touch longer so it reads as a note. midiToFreq is equal-tempered (A4 = 440). No-op until the audio context is running (autoplay-gated), and for inaudibly-high pitches.
  • Routing (onMouseDown): a left-click in the LABEL_W gutter (keys mode only) → _auditionPitch(yToMidi(y)) via the pure _inKeyboardGutterPure region test, then returns — no selection, no note edit. Right-click still opens the context menu.

Tests — tests/keyboard_gutter.test.js (10, all fail on main)

midiToFreq temperament (A4/A5/A3/middle-C/E4) + non-finite → 0 guard; the gutter hit region's half-open edges (never overlaps the note area or the waveform/beat strips); _auditionPitch autoplay guard (no ctx / suspended → nothing scheduled), one-voice-at-pitch scheduling on a running ctx, and the inaudible-pitch refusal. Full JS suite green.

Scope / fresh region

Touches the piano-roll left-axis render (drawPianoLabels), a new midiToFreq/_inKeyboardGutterPure pure block, _auditionPitch beside _editBlipAt, and one branch in onMouseDown — none of which the open PRs (#112/#125/#126/#127) touch (#126's roll work was in _drawPianoNote, the note render, not the gutter). No core, no spec.

Summary by CodeRabbit

  • New Features
    • Updated the piano roll’s left axis to look and behave like a keyboard gutter, including white/black key styling and octave-row labels.
    • Left-clicking a key in the gutter now plays a short equal-tempered pitch preview when audio is active.
  • Bug Fixes
    • Prevented gutter interactions from triggering the normal note editing/add flow, including double-click behavior.
  • Tests
    • Added automated tests covering gutter hit detection, pitch preview scheduling, and regression for double-click handling.

… keyboard

DAW roadmap 4.1. In keys/piano view the left note-label column is now rendered
as an actual keyboard laid on its side, and clicking a key auditions its pitch.

- drawPianoLabels rewritten: white/black key shading per row (black keys inset
  from the front edge so the white tails read between them, the side-on
  keyboard look), C rows labelled with their octave, white-white separators
  only at E–F / B–C, and a front-edge divider. String view is untouched (it
  keeps its string labels).
- midiToFreq (equal temperament, A4=440; 0 for non-finite) + _auditionPitch: a
  gentle, hearing-safe voice (soft attack, ~0.28 peak, ~0.32s decay) through
  the existing master limiter — the edit-blip envelope, pitched and a touch
  longer. No-op until the audio context is running (autoplay-gated) and for
  inaudibly-high pitches.
- onMouseDown routes a left-click in the LABEL_W gutter (keys mode only) to
  _auditionPitch(yToMidi(y)) via the pure _inKeyboardGutterPure region test,
  and returns — no selection, no edit. Right-click still opens the menu.

Tests: tests/keyboard_gutter.test.js (10) — midiToFreq temperament + non-finite
guard, the gutter hit region's half-open edges, and _auditionPitch's autoplay
guard + single-voice-at-pitch scheduling + inaudible-pitch refusal. 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: 31 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: 22f14d25-29a9-48fa-8981-6445d4f4276e

📥 Commits

Reviewing files that changed from the base of the PR and between fc87eb7 and 8897aa3.

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

Walkthrough

Adds a real keyboard gutter to the piano roll, with MIDI-to-frequency helpers, pitch audition on left-click, double-click suppression in the gutter, runtime tests, and a changelog update.

Changes

Keyboard gutter and pitch audition

Layer / File(s) Summary
MIDI-to-frequency and gutter hit-test helpers
screen.js
Adds midiToFreq with non-finite guarding and _inKeyboardGutterPure for half-open gutter hit-testing.
Keyboard gutter rendering
screen.js
Reworks drawPianoLabels to render shaded white/black key rows, white-key separators, C-row octave labels, and a front-edge divider.
Click routing and pitch audition playback
screen.js
Routes left-clicks inside the gutter from drawNotes to _auditionPitch, and prevents gutter double-clicks from reaching add/select behavior in keys mode. _auditionPitch gates on audio context state, creates a triangle oscillator with an envelope, and tracks guide voices.
Keyboard gutter and audition tests
tests/keyboard_gutter.test.js, tests/keyboard_gutter_dblclick.test.js, CHANGELOG.md
Adds runtime tests for frequency conversion, gutter containment, audition scheduling, and double-click suppression in the gutter, and documents the new keyboard behavior in the changelog.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant drawNotes
  participant _auditionPitch
  participant AudioContext

  User->>drawNotes: left-click inside keyboard gutter
  drawNotes->>_auditionPitch: audition pitch(midi)
  _auditionPitch->>AudioContext: check state running
  alt context not running or invalid frequency
    _auditionPitch-->>drawNotes: no-op
  else context running and audible range
    _auditionPitch->>_auditionPitch: midiToFreq(midi)
    _auditionPitch->>AudioContext: create triangle oscillator + gain envelope
    _auditionPitch->>_auditionPitch: track guide voice, prune if over limit
  end
Loading

Possibly related PRs

🚥 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 summarizes the main change: a clickable, audible keyboard gutter in the piano roll.
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-keyboard-gutter

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

Guard onDblClick against the keyboard gutter: a double-click on a gutter
key was falling through to showAddNote (hitNote miss -> add-note dialog at
time 0), silently authoring a note. The gutter is audition-only, so scope
a keys-mode gutter early-return via _inKeyboardGutterPure. Adds a
regression test that fails on pre-fix code.

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.

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