fix: TempoTrackLane bar spacing drift with floating-point BPM

- Replace t += beatDuration loop (floating accumulation drifts)
- Iterate by integer beat number: t = bn * beatDuration
- Each bar position computed independently, no cumulative error
- Same fix for snapInterval loop
- Fixes unequal bar widths for BPM like 77, 81
This commit is contained in:
2026-07-27 08:25:47 +07:00
parent 6a409b954d
commit f59cc304d4
2 changed files with 11 additions and 7 deletions
+9 -5
View File
@@ -1325,9 +1325,11 @@ const TempoTrackLane = ({
const PADDING_LEFT = 0;
const tStart = (scrollLeftVal - leadIn * zoom) / zoom - PADDING_LEFT;
const tEnd = (scrollLeftVal + drawWidth - leadIn * zoom) / zoom + CLIP_BUFFER / zoom;
const firstBeat = Math.floor(tStart / beatDuration) * beatDuration;
for (let t = firstBeat; t <= tEnd; t += beatDuration) {
const beatNum = Math.floor(t / beatDuration) + 1;
const firstBeatNum = Math.floor(tStart / beatDuration);
const lastBeatNum = Math.ceil(tEnd / beatDuration);
for (let bn = firstBeatNum; bn <= lastBeatNum; bn++) {
const t = bn * beatDuration;
const beatNum = bn + 1;
const isBar = beatNum % 4 === 1;
const localX = (t - tStart) * zoom;
if (localX < -CLIP_BUFFER || localX > drawWidth + CLIP_BUFFER) continue;
@@ -1365,8 +1367,10 @@ const TempoTrackLane = ({
if (snapValue === '4') divisor = 4; else if (snapValue === '1') divisor = 1; else if (snapValue === '1/2') divisor = 0.5; else if (snapValue === '1/4') divisor = 0.25; else if (snapValue === '1/8') divisor = 0.125; else if (snapValue === '1/16') divisor = 0.0625; else if (snapValue === '1/32') divisor = 0.03125;
const snapInterval = beatDuration * divisor;
if (snapInterval * zoom >= 4) {
const firstSnap = Math.floor(tStart / snapInterval) * snapInterval;
for (let t = firstSnap; t <= tEnd; t += snapInterval) {
const firstSnapNum = Math.floor(tStart / snapInterval);
const lastSnapNum = Math.ceil(tEnd / snapInterval);
for (let sn = firstSnapNum; sn <= lastSnapNum; sn++) {
const t = sn * snapInterval;
const onBeat = Math.abs(t / beatDuration - Math.round(t / beatDuration)) < 0.001;
if (!onBeat) {
const localX = (t - tStart) * zoom;