Skip to content

fix(locallibrary): player capitals and the mixes-into panel's keys - #511

Open
botandbang wants to merge 2 commits into
bnb/tui-discoverfrom
bnb/loc-11-13-player-fixes
Open

botandbang wants to merge 2 commits into
bnb/tui-discoverfrom
bnb/loc-11-13-player-fixes

Conversation

@botandbang

Copy link
Copy Markdown
Contributor

What and why

Two fixes to the player, one commit each.

Q quit the player

Fixes LOC-11

#306 fixed this, in ca71e8981. In terminals that report keys by their codes (CSI u, xterm's modifyOtherKeys, tmux extended-keys), Q arrives as q with shift, and the keymap read it as quit. The player exited normally, so there was never a panic to capture. That commit added capital in apps/locallibrary/src/tui/app/input.rs and a test for Q, S and A.

This PR adds the regression test that would have caught it: a Hegel property, prop_a_shifted_letter_sent_as_its_code_is_its_capital, over the deck's and the library's capitals. Any run of them typed while a track plays leaves the same screen sent either way, and none quits.

On a release build of this branch in a pty at 120x40, with RUST_BACKTRACE=1, playing a track on the demo drive and sending Q, ESC [113;2u (CSI u) and ESC [27;2;113~ (modifyOtherKeys) between beat jumps, loops and hot cues, the player kept running, toggled quantize each time and quit with status 0 on q. stderr held only the test-volumes notice.

The "mixes into" panel showed one key

Fixes LOC-13

The keys shown were right: each row showed its own track's key. The ranking was the problem. The panel showed the first matches harmony::suggestions ranks, and it ranks every same-key track before any other, so with more same-key tracks than the panel's four to six rows, which is any real library, same-key tracks filled every row and the panel never showed a ±1 or relative match. An F minor track showed only 4A. On the 3,886-track rekordcrate/large fixture, a C major track listed 8B five times at 120x40, while track matches lists 7B and 9B right after.

Matches::find in apps/locallibrary/src/tui/app/loaded.rs now lets same key, ±1, relative and energy boost take turns, closest tempo first within each. The panel's first rows show the closest track of each kind there is, then the second of each, and so on. The library's details panel and the deck share it.

track matches and the sidecar's harmonic_matches keep listing best first, every same-key track before the rest. That difference is on purpose: a full list reads well best first, and a panel of a few rows needs every kind in it. docs/player.md says so.

Added

  • the_mixes_into_panel_shows_more_than_the_playing_key: a library with seven same-key matches, a neighbour and a relative; the deck at 120x40 shows all three kinds.
  • prop_the_ways_of_mixing_in_take_turns: for any made-up library, the matches found are as many as the suggestions allow up to the limit, start with one of each kind in the suggestions' order, and keep the suggestions' tempo order within each kind.
  • prop_a_shifted_letter_sent_as_its_code_is_its_capital, above.
  • playing_in in the TUI's test helpers: playing with a library of the test's own.
  • apps/locallibrary/changes/loc-11-13-player-fixes.md.

Changed

  • Matches::find orders the matches by turns, as above.
  • docs/player.md says how the matches are ordered.

Removed

Nothing.

How it was tested

Each new test was seen to fail with its fix broken, one at a time: with capital skipped in on_key, the property failed on ['Q'] with "Q quit" (as did the existing a_shifted_q_sent_as_its_code_quantizes_rather_than_quits); with the old order (kind first, then tempo) the panel test failed missing 7B 128.0 Neighbour and the take-turns property failed on its first-rows check.

cargo nextest run -p locallibrary-cli passed 1,376 of 1,376, and cargo nextest run --workspace 5,114 of 5,114 (1 skipped). cargo fmt --all --check and the three clippy forms (workspace, --no-default-features --features tui,account, --no-default-features, all with --all-targets -D warnings) pass. Coverage is left to CI.

The panel was checked on a release build in a real terminal engine, truecolor and dark, playing "Upstart" (C major, 128.88 BPM) on the rekordcrate/large fixture. Before, the deck at 120x40 listed 8B in all five rows. Now it lists 8B, 7B, 8A, 8B. At 80x24 the deck has no room for the panel, and the library's details pane shows 8B, 7B, 8A.

Matches::find now asks the suggestions for every match, then sorts and takes 40 (when a track starts) or 60 (the details pane), where it asked for 40 or 60. harmony::suggestions already built and cloned every match before cutting the list, so the time barely moves. Measured with a temporary test in an optimised build of the unit binary (release without LTO), with its counting allocator, per call over 79 playing tracks of the 3,886-track fixture and 150 of a 10,000-track library made as crates/locallibrary/benches/synthetic makes its tracks:

library limit median before median after p95 before p95 after bytes a call before after
3,886 tracks 40 0.197 ms 0.195 ms 0.260 ms 0.265 ms 199,562 301,468
3,886 tracks 60 0.229 ms 0.222 ms 0.288 ms 0.306 ms 199,562 301,468
10,000 tracks 40 1.326 ms 1.375 ms 1.477 ms 1.604 ms 2,638,272 4,148,459
10,000 tracks 60 1.453 ms 1.471 ms 1.822 ms 1.787 ms 2,638,272 4,148,459

Allocations a call went from 2,547 to 2,549 on the fixture and from 32,109 to 32,111 on 10,000 tracks. The extra bytes are one more list of every match, each with its turn, built for the sort. It runs on a background thread, not in a frame, so frame work doesn't change; no frame budget was touched.

Checklist

  • Tests cover the change
  • For locallibrary: apps/locallibrary/changes/loc-11-13-player-fixes.md has a changelog line
  • The READMEs, docs/ and --help still say what the code does (apps/locallibrary/docs/rpc/ too)

…eir lowercase keys

`Q` quit the player in terminals that report keys by their codes (CSI u, xterm's
modifyOtherKeys, tmux extended-keys): they send it as `q` with shift, and the keymap took that for
`q`. The player quit cleanly, which is why no panic text ever showed. #306 fixed it (ca71e89),
and on a release build `Q` sent each way now toggles quantize.

This adds the regression test that would have caught it: a property over the deck's and the
library's capitals, typed while a track plays, that any run of them leaves the same screen
whether each comes as the capital or as its code, and that none of them quits.

Fixes LOC-11
…anel

The player's "mixes into" panel took the first matches `harmony::suggestions` ranks, and it ranks
every same-key track before any other. The keys shown were each track's own, but in a library of
any size same-key tracks filled all four to six rows, so the panel never showed a ±1 or relative
match: playing an F minor track showed nothing but 4A.

`Matches::find` now takes each way of mixing in (same key, one step round the wheel, relative,
energy boost) in turn, closest tempo first within each, so the first rows show one of each there
is. `track matches` and the sidecar keep listing best first; docs/player.md says how the two
differ.

Fixes LOC-13
@botandbang
botandbang requested a review from bnb as a code owner November 7, 2026 19:12
@botandbang botandbang added the all-os Run the macOS and Windows checks on this pull request label Nov 7, 2026
@linear-code

linear-code Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

LOC-13

LOC-11

@github-actions github-actions Bot added documentation Improvements or additions to documentation locallibrary locallibrary and the loclib-* crates locallibrary: player The terminal player and its waveforms tests Tests, fixtures and test harnesses labels Nov 7, 2026
@bnb
bnb added this pull request to stack #515 November 7, 2026 19:55
@github-actions

github-actions Bot commented Nov 7, 2026

Copy link
Copy Markdown

Size

Compared with main. KiB are 1,024 bytes.

This pull request main Change
Client JavaScript 772.6 KiB 772.6 KiB 0 B (0%)
Client JavaScript, brotli 259.7 KiB 259.7 KiB 0 B (0%)
Client CSS 94.5 KiB 94.5 KiB 0 B (0%)
Client CSS, brotli 13.6 KiB 13.6 KiB 0 B (0%)

@github-actions

github-actions Bot commented Nov 7, 2026

Copy link
Copy Markdown

Rust coverage

From run 499. Both are held to the thresholds in .cargo/config.toml.

Tests Lines Functions Regions
All 98.06% (91081/92885) 97.58% (14906/15276) 96.74% (202248/209058)
Hegel property tests alone 96.53% (89662/92885) 96.04% (14671/15276) 95.05% (198716/209058)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

all-os Run the macOS and Windows checks on this pull request documentation Improvements or additions to documentation locallibrary: player The terminal player and its waveforms locallibrary locallibrary and the loclib-* crates tests Tests, fixtures and test harnesses

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants