I build Pianory, a browser-based piano practice app. AI helped draft this article; I checked the implementation claims against the current source.
A 2/4 score has two quarter-note beats per complete bar. If the player displays 2/4 but schedules four count-in clicks, the entrance cue contradicts the score. The meter needs to reach the click scheduler, not just a label.
In Pianory's score adapter, each measure contributes its active time signature. If the source has none, the adapter falls back to [4, 4]. The timeline converts a signature into a beat count and the length of each beat in quarter-note units. For [2, 4], the conversion is { beats: 2, beatQuarters: 1 }. Each measure span stores that result.
The click grid steps through a measure by beatQuarters and marks the first beat of a complete bar as accented. Pickups are handled separately: a short opening measure aligns its clicks from the end of that measure rather than pretending it is full length. The player looks up the span at its playback start, schedules beatsInBar count-in clicks, and delays the first note by beatsInBar × countInBeatSeconds. For a complete 2/4 span, that means two count-in clicks before music begins.
I ran pnpm exec vitest run src/lib/sheet/timeline.spec.ts src/lib/sheet/player.spec.ts: 2 files and 39 tests passed. The existing specs cover neighboring meter and count-in cases, but they do not explicitly assert [2, 4]. A focused regression test should construct a complete 2/4 measure, assert two count-in clicks, and check that music begins after two beat intervals. The passing suite is evidence for the tested behavior, not proof of that missing 2/4 case or of real-device audio timing.
Source files: src/lib/sheet/osmd-source.ts, src/lib/sheet/timeline.ts, and src/lib/sheet/player.ts. The useful contract is simple: carry the score's meter all the way to the audible cue.
