Skip to content
Closed
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
060501f
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 15, 2026
aecfb52
test(desktop): lock GrooveMap timeline semantics
seonghobae Aug 15, 2026
7c9b2a6
docs(changelog): record GrooveMap timeline optimization
seonghobae Aug 15, 2026
e0bd382
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 15, 2026
4114032
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 15, 2026
b04e6a6
test(desktop): restore GrooveMap timeline regressions
seonghobae Aug 15, 2026
e55c072
docs(changelog): restore GrooveMap optimization note
seonghobae Aug 15, 2026
9e43f62
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 15, 2026
18d3c1d
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 15, 2026
a908920
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 15, 2026
715c4da
fix(groove-map): restore regression evidence and changelog
seonghobae Aug 15, 2026
d311e01
fix(changelog): preserve released history
seonghobae Aug 15, 2026
9751805
fix(workspace): preserve GrooveMap max semantics
seonghobae Aug 16, 2026
ace2744
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 16, 2026
294d995
test(groove): lock timeline maximum semantics
seonghobae Aug 16, 2026
6486618
fix(groove): preserve timeline maximum semantics
seonghobae Aug 16, 2026
38e1027
docs(changelog): record GrooveMap optimization contract
seonghobae Aug 16, 2026
d7e1369
Merge remote-tracking branch 'origin/develop' into HEAD
seonghobae Aug 25, 2026
888c925
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 26, 2026
055db2b
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 26, 2026
a45b2d1
Merge branch 'develop' into bolt-optimize-reduce-13473486884347986122
seonghobae Aug 26, 2026
a649e18
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 26, 2026
c9c4ad6
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 26, 2026
4107fa4
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 26, 2026
af87411
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 26, 2026
99e6a7d
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 26, 2026
7f5bf1c
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 26, 2026
5236ac2
perf(desktop): preserve GrooveMap timeline semantics
seonghobae Aug 28, 2026
ee0f383
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 28, 2026
abea1c4
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 28, 2026
9e58b22
perf(desktop): restore GrooveMap security baseline
seonghobae Aug 28, 2026
0de77e2
fix(changelog): merge GrooveMap change entry
seonghobae Aug 28, 2026
370bd5d
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 28, 2026
62fd665
fix(changelog): keep GrooveMap entry in one section
seonghobae Aug 28, 2026
7c6c52f
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 28, 2026
e0b1617
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 28, 2026
ba07701
perf(desktop): replace reduce with for...of in GrooveMap maxTime calc…
seonghobae Aug 28, 2026
fa1ced9
chore: downgrade jsdom and update pdfjs-dist and nanoid to fix depend…
seonghobae Aug 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
- Display the analyzed song tempo (BPM) as a badge in the rehearsal workspace.
- 각 합주 역할(Role)별 개인 연습 진행도를 0~100% 범위로 기록 및 시각화할 수 있는 연습 진척도(`practiceProgress`) 트래커 기능 추가. UI 컨트롤(슬라이더 및 +/- 버튼)과 한/영 다국어 지원 포함.

### Changed

- Preserve GrooveMap's ten-second timeline floor while computing larger transcription bounds with a single allocation-free loop.

## [0.1.3] - 2026-04-29

### Fixed
Expand Down
35 changes: 35 additions & 0 deletions apps/desktop/src/features/workspace/GrooveMap.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { render, screen } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import { GrooveMap } from "./GrooveMap";

describe("GrooveMap", () => {
it("uses the latest note offset as the timeline maximum when it exceeds the ten-second floor", () => {
render(
<GrooveMap
notes={[
{ pitch: "E2", onset: 10, offset: 20, velocity: 0.8 },
{ pitch: "G2", onset: 2, offset: 12, velocity: 0.7 }
]}
/>
);

const latestNote = screen.getByTitle("E2 (10.00s - 20.00s)");
const earlierNote = screen.getByTitle("G2 (2.00s - 12.00s)");

expect(latestNote.style.left).toBe("50%");
expect(latestNote.style.width).toBe("50%");
expect(earlierNote.style.left).toBe("10%");
expect(earlierNote.style.width).toBe("50%");
});

it("retains the ten-second timeline floor when every note ends earlier", () => {
render(
<GrooveMap notes={[{ pitch: "A2", onset: 2, offset: 5, velocity: 0.6 }]} />
);

const note = screen.getByTitle("A2 (2.00s - 5.00s)");

expect(note.style.left).toBe("20%");
expect(note.style.width).toBe("30%");
});
});
6 changes: 5 additions & 1 deletion apps/desktop/src/features/workspace/GrooveMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ function GrooveMapComponent({ notes, isLoading }: GrooveMapProps) {

// Find max offset to determine timeline width
const maxTime = useMemo(() => {
return renderedNotes.reduce((max, n) => Math.max(max, n.offset), 10);
let max = 10;
for (const n of renderedNotes) {
if (n.offset > max) max = n.offset;
}
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
return max;
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Comment on lines +20 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: GrooveMap maxTime no longer propagates NaN

The new loop uses if (n.offset > max), which skips a NaN offset, while the old reduce used Math.max and propagated NaN into maxTime. Behavior is identical for finite offsets. For a NaN offset the new code keeps a finite denominator instead of breaking the whole timeline, so it is more robust, but it contradicts the PR's own stated goal of preserving Math.max semantics.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

}, [renderedNotes]);
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Comment on lines 19 to 25

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: GrooveMap max loop silently changes NaN handling

The old reduce used Math.max, which returns NaN once any offset is NaN and poisons every note's position. The new loop's if (n.offset > max) skips NaN offsets, so maxTime stays finite. Behavior differs only for non-finite offsets; the description claims Math.max is used but the committed code uses the comparison form.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


// Unique pitches to determine vertical lanes (avoiding 88-key piano roll)
Expand Down
Loading