Skip to content

fix(count-in): follow the song's meter and its pickup measure - #1029

Merged
byrongamatos merged 1 commit into
mainfrom
fix/count-in-timesig-pickup
Jul 23, 2026
Merged

fix(count-in): follow the song's meter and its pickup measure#1029
byrongamatos merged 1 commit into
mainfrom
fix/count-in-timesig-pickup

Conversation

@gionnibgud

Copy link
Copy Markdown
Contributor

Problem

A user reported the metronome fighting the barlines on a 4/4 piano score
opening with a pickup measure (two eighth notes). Chasing it surfaced the
count-in as an independent bug, in core rather than any plugin.

The count-in clicked exactly four beats, always. Two consequences:

  • A 3/4 song was counted in 4/4.
  • A song opening with a pickup (anacrusis) had the pickup enter where the
    downbeat belonged, so the player came in a beat ahead — for the whole song,
    since nothing later corrects the impression.

Fix

Bar length now comes from the song_timeline beats already on the highway.
Beats carry measure >= 0 on downbeats, so the gap between consecutive
downbeats is the bar length — no new plumbing, which matters because the
frontend never consumes the time_signatures WS message at all (it is streamed
to plugins only, so making count-in time-signature-aware that way would have
meant new state to load, reset, and keep in sync).

A first bar shorter than that meter is a pickup, and the count is shortened by
its length: a 1-beat pickup in 4/4 counts “1 2 3” and the music enters on 4.

Three details that are load-bearing rather than incidental:

  • Bar length is the mode of the downbeat gaps, not the first gap — the
    first gap in a pickup song is the pickup, which would then be read as the
    meter.
  • The beats trailing the last downbeat count as a candidate gap — otherwise
    a song of pickup + one bar offers only the pickup’s gap and the count
    collapses to it.
  • Pickup shortening is scoped to the song’s first bar. A short bar anywhere
    else is a meter change (or a truncated final bar); treating one as a pickup
    would leave nearly no count-in. Those are counted by their own length, which
    is also what a mid-song meter change wants.

Songs with no beats — pre-chart, minigames, synthetic highways — still get
four. Both count-in paths use it: loop wrap / section practice, and the
start-of-song “Countdown before song” setting.

Testing

  • tests/js/count_in_beats.test.js — 15 new cases: meter (3/4, 4/4, 6/8),
    pickups of 1 and 2 beats in 4/4 and 3/4, the pickup-plus-one-bar tie, a
    mid-song meter change counted as its own bar rather than a pickup, mid-bar
    and mid-song-downbeat resumes, seek slop, and every no-beats fallback.
  • tests/js/loop_restart.test.js gains a countInBeats stub — it sandboxes
    startCountIn and beginCount now calls one more helper. Assertions
    unchanged.
  • Full JS suite: 1343 passing.
  • Verified in the running app on the reported song: three clicks, pickup enters
    on four, accents land on the barlines.

Related

The same report also needed two plugin-side fixes, both merged/open separately
— the MusicXML converter was dropping the first full measure’s downbeat label
(got-feedBack/feedBack-plugin-musicxml-import#10) and staffview was accenting
the pickup (got-feedBack/feedBack-plugin-staffview#23). This PR stands on its
own: it affects every instrument, not just notation.

🤖 Generated with Claude Code

The count-in always clicked exactly four beats, so a 3/4 song was counted
in 4/4, and a song opening with a pickup (anacrusis) had the pickup enter
where the downbeat belonged — putting the player a beat ahead all song.

Bar length now comes from the song_timeline beats already on the highway
(measure >= 0 marks downbeats), so no new plumbing: the time_signatures
map is streamed to plugins rather than stored in the frontend. A first bar
shorter than that meter shortens the count by its length — a 1-beat pickup
in 4/4 counts "1 2 3" and the music enters on 4.

Bar length is the mode of the downbeat gaps, not the first gap, so a
pickup's own short gap can't be read as the meter; the beats trailing the
last downbeat count as a candidate too, or a song of pickup + one bar
offers only the pickup's gap. Pickup shortening is scoped to the song's
first bar — a short bar elsewhere is a meter change, and is counted by its
own length instead. Songs without beats (pre-chart, minigames, synthetic
highways) still get four.

Applies to both count-in paths: loop wrap / section practice, and the
start-of-song 'Countdown before song' setting.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: gionnibgud <gionnibgud@gmail.com>
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

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

Next review available in: 27 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: 3b347852-96e4-42be-babc-daad36634c29

📥 Commits

Reviewing files that changed from the base of the PR and between 0e3522c and 6ece31b.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • static/js/count-in.js
  • tests/js/count_in_beats.test.js
  • tests/js/loop_restart.test.js
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/count-in-timesig-pickup

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.

@byrongamatos
byrongamatos merged commit 32c00cd into main Jul 23, 2026
6 checks passed
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