Skip to content

Commit b4c40d3

Browse files
authored
Merge pull request #42 from boostcampwm-snu-2026-1/docs/41-arrangement-clip-placement-playback
docs: plan arrangement clip placement playback
2 parents deb935b + 4531220 commit b4c40d3

9 files changed

Lines changed: 273 additions & 7 deletions

File tree

PLANS.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ M1 should include:
3030
Use this section as the current execution order for agent work. Feature document numbering describes the planned product sequence, but actual issue order may change as dependencies, review feedback, or implementation risks become clearer.
3131

3232
1. #39 WAV file import as audio clip -> `docs/features/15-wav-file-import-as-audio-clip.md`
33+
2. #41 Arrangement clip placement and playback -> `docs/features/16-arrangement-clip-placement-and-playback.md`
3334

3435
## Planned Milestones
3536

@@ -48,10 +49,10 @@ Use this section as the current execution order for agent work. Feature document
4849
13. Arrangement mixer panel UI shell.
4950
14. Hybrid clip loop playback.
5051
15. WAV file import as audio clip.
51-
16. Project export/import.
52-
17. IndexedDB autosave.
53-
18. Arrangement data model.
54-
19. Arrangement editing and playback.
52+
16. Arrangement clip placement and playback.
53+
17. Project export/import.
54+
18. IndexedDB autosave.
55+
19. Arrangement data model refinements.
5556
20. Mixer audio routing.
5657
21. Basic effects.
5758

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Build a practical clip-based music creation tool that can grow beyond a demo whi
2121

2222
## Current Status
2323

24-
The project has an initial Vite + React + TypeScript scaffold. DAW features such as audio playback, sequencing, piano roll editing, and arrangement editing have not been implemented yet.
24+
The project has an initial Vite + React + TypeScript scaffold and early DAW UI/audio features under active development. Arrangement placement, arrangement playback, persistence, and broader song-building workflows are still planned work.
2525

2626
## Getting Started
2727

@@ -67,6 +67,7 @@ Feature task specs:
6767
- [13 Drum Step Subdivisions](docs/features/13-drum-step-subdivisions.md)
6868
- [14 Arrangement Mixer Panel UI Shell](docs/features/14-arrangement-mixer-panel-ui-shell.md)
6969
- [15 WAV File Import as Audio Clip](docs/features/15-wav-file-import-as-audio-clip.md)
70+
- [16 Arrangement Clip Placement and Playback](docs/features/16-arrangement-clip-placement-and-playback.md)
7071

7172
## Initial Roadmap
7273

@@ -76,7 +77,9 @@ Feature task specs:
7677
4. Build a 16-step drum sequencer.
7778
5. Build a basic 1-bar piano roll.
7879
6. Combine drum and note events into hybrid clip loop playback.
79-
7. Add project export/import and persistence features.
80+
7. Import local WAV files as audio clips.
81+
8. Place clips on the arrangement timeline and play the arranged song.
82+
9. Add project export/import and persistence features.
8083

8184
## Notes
8285

docs/architecture.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ The main rule is separation of concerns: UI rendering, persistence, and audio sc
1414
- Dispatch user actions to state/model logic.
1515
- Display audio state such as stopped, playing, paused, and playhead position.
1616
- Render song-level UI shells such as arrangement and mixer panels.
17+
- Let users place, move, select, and delete arrangement clip instances.
1718
- Use `requestAnimationFrame` for visual playheads where needed.
1819
- Avoid owning exact audio timing.
1920

@@ -22,6 +23,7 @@ The main rule is separation of concerns: UI rendering, persistence, and audio sc
2223
- Define serializable project data types.
2324
- Store musical time in ticks.
2425
- Provide pure transformations for creating, editing, duplicating, and deleting clips and events.
26+
- Provide pure transformations for creating, moving, and deleting arrangement clip instances.
2527
- Avoid references to Web Audio runtime objects.
2628

2729
### Audio engine
@@ -30,6 +32,7 @@ The main rule is separation of concerns: UI rendering, persistence, and audio sc
3032
- Load and decode sample assets.
3133
- Store runtime-only decoded sample data.
3234
- Schedule audio against `AudioContext.currentTime`.
35+
- Schedule arrangement playback from placed clip instances when `SONG` mode is active.
3336
- Later, own mixer routing, track gain nodes, meters, and effect nodes when those features exist.
3437
- Expose a small typed API to the UI and feature code.
3538
- Never depend on React components.
@@ -82,6 +85,8 @@ Imported browser files are also runtime or persistence-layer data. Project JSON
8285

8386
Future mixer runtime data, including `GainNode`, `AnalyserNode`, effect nodes, meter buffers, and active routing graphs, also belongs to the audio engine runtime and must not be stored in project JSON.
8487

88+
Arrangement placement data is serializable. A placed clip should be represented by a `ClipInstance` with stable IDs, `startTick`, `lengthTicks`, and track membership. Drag state, pointer coordinates, DOM measurements, scheduler timers, decoded buffers, and active audio nodes are runtime-only and must not be persisted.
89+
8590
## Future Desktop Packaging Considerations
8691

8792
Keep the app browser-first, but avoid assumptions that block future Electron or Tauri packaging:

docs/audio-engine.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,26 @@ The first imported WAV implementation may support a simple preview or clip playb
5151

5252
Imported audio clip duration is source media duration in seconds. Future arrangement placement should convert arrangement positions and visible instance lengths to ticks, while source offsets remain sample-local seconds. Without a time-stretching feature, resizing an audio clip instance should trim/crop playback or extend silence rather than stretch the audio to a new musical duration.
5353

54+
## Arrangement Playback
55+
56+
`PAT` mode playback targets the selected clip editor. `SONG` mode playback should target placed `ClipInstance` objects on the arrangement timeline.
57+
58+
Arrangement playback should:
59+
60+
- Read serializable clip instances from project or app model state.
61+
- Convert arrangement tick positions to `AudioContext.currentTime` scheduling times.
62+
- Expand hybrid clip drum events to `clipInstance.startTick + drumEvent.startTick`.
63+
- Expand hybrid clip note events to `clipInstance.startTick + noteEvent.startTick`.
64+
- Schedule audio clips at `clipInstance.startTick` when their runtime sample data is available.
65+
- Respect `clipInstance.lengthTicks` as the visible and playable duration boundary.
66+
- Keep play, pause, resume, and stop behavior separate from React render timing.
67+
68+
The first arrangement playback implementation may play linearly from tick 0 through the end of the last placed clip instance, then stop. Arrangement loop regions can be added later.
69+
70+
Imported audio clips should play at original speed unless a later time-stretching feature explicitly changes that behavior. If an audio clip instance is shorter than the source buffer, playback should be cropped. If the instance is longer than the source buffer, playback may end naturally and leave silence. If runtime file data is missing after refresh, the engine should report a clear missing-source error rather than silently failing.
71+
72+
Arrangement playback still uses the lookahead scheduler. UI drag state, arrangement DOM geometry, visual playheads, decoded buffers, and active source nodes remain runtime-only.
73+
5474
## One-shot Sample Playback
5575

5676
Use a new `AudioBufferSourceNode` for every one-shot playback. A source node cannot be restarted after it has played.

docs/data-model.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,48 @@ export interface AudioClip {
130130

131131
Future arrangement resizing should be non-destructive. The arrangement should store resize/trim decisions on `ClipInstance`, for example `lengthTicks` and optional `sourceOffsetSeconds`, instead of modifying the source audio clip or embedded file. Without a dedicated time-stretching feature, resizing an imported audio clip instance should mean trimming/cropping playback or showing silence after the source ends; it should not imply tempo-matched stretching.
132132

133+
## Arrangement Clip Placement
134+
135+
The arrangement view places reusable clips on tracks using `ClipInstance` objects.
136+
137+
`Clip` owns reusable source content:
138+
139+
- Hybrid clip drum and note events.
140+
- Audio clip source metadata.
141+
- Clip name and source identity.
142+
143+
`ClipInstance` owns song placement:
144+
145+
- Which source clip is placed.
146+
- Which track contains it.
147+
- Where it starts in arrangement ticks.
148+
- How long the placed instance lasts in arrangement ticks.
149+
- Optional source offset for audio clips.
150+
151+
Illustrative shape:
152+
153+
```ts
154+
export interface ClipInstance {
155+
id: string;
156+
clipId: string;
157+
trackId: string;
158+
startTick: Tick;
159+
lengthTicks: Tick;
160+
sourceOffsetSeconds?: number;
161+
}
162+
```
163+
164+
The first arrangement placement feature should create, move, select, and delete `ClipInstance` objects without mutating the source `Clip`. Deleting a placed clip from the arrangement removes only that instance. It does not delete the sidebar clip.
165+
166+
Default instance lengths:
167+
168+
- Hybrid clip: use the source clip's `lengthTicks`, initially 1920 ticks for a 1-bar clip.
169+
- Audio clip: derive an initial `lengthTicks` from `durationSeconds` and current `tempoBpm` when placed, or use an equivalent helper that keeps arrangement placement tick-based.
170+
171+
Without time stretching, imported audio playback runs at original speed. If an audio clip instance is shorter than the source, playback is cropped. If it is longer than the source, playback may end naturally and leave silence. Changing project tempo can change the musical grid without changing the underlying audio source speed until a later time-stretching feature exists.
172+
173+
Snap and movement should update tick values, not pixel positions. UI geometry is derived from `startTick`, `lengthTicks`, track order, and timeline constants.
174+
133175
## Bundled Drum Sample Naming and Display
134176

135177
Bundled drum sample files live under `public/samples/drums/`.
@@ -366,6 +408,7 @@ export interface ClipInstance {
366408
trackId: string;
367409
startTick: Tick;
368410
lengthTicks: Tick;
411+
sourceOffsetSeconds?: number;
369412
}
370413

371414
export interface DrumEvent {
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# Feature: 16 Arrangement Clip Placement and Playback
2+
3+
## Status
4+
Planned
5+
6+
## Goal
7+
8+
Allow users to place reusable clips on the `SONG` arrangement timeline and play the arranged song from the transport.
9+
10+
This turns the arrangement view from a static shell into the first usable song-building surface.
11+
12+
## Context
13+
14+
The app already has:
15+
16+
- A `PAT` mode for focused clip editing.
17+
- A `SONG` mode arrangement UI shell.
18+
- A left sidebar that manages clips and clip child items.
19+
- Transport play, pause, resume, stop, playhead, and tempo behavior for clip playback.
20+
- Planned WAV import as audio clips in `docs/features/15-wav-file-import-as-audio-clip.md`.
21+
22+
Users now need to place clips horizontally in time and vertically across tracks. Playback in `SONG` mode should schedule the placed clip instances instead of looping only the selected `PAT` clip.
23+
24+
## Scope
25+
26+
Included:
27+
- Make sidebar clips draggable into the arrangement timeline where practical.
28+
- Create serializable `ClipInstance` entries when clips are placed.
29+
- Store arrangement placement with `clipId`, `trackId`, `startTick`, and `lengthTicks`.
30+
- Render arrangement clip blocks from project or app model state instead of static demo blocks.
31+
- Move existing clip instances horizontally and vertically by drag where practical.
32+
- Snap dropped and moved clip instances to the arrangement grid.
33+
- Select and delete placed clip instances.
34+
- Keep the existing arrangement track list and timeline layout aligned.
35+
- Add a visual arrangement playhead in `SONG` mode.
36+
- Make transport play, pause, resume, and stop operate on arrangement playback when `SONG` mode is active.
37+
- Schedule placed hybrid clips by expanding their drum and note events relative to each `ClipInstance.startTick`.
38+
- Schedule placed audio clips when imported audio runtime data is available.
39+
- Keep imported audio playback at original speed; no time stretching in this feature.
40+
- Add focused tests for clip instance creation, moving, deletion, snapping, and scheduler event expansion where practical.
41+
- Update relevant product, architecture, data model, audio, UI, and testing docs.
42+
43+
Excluded:
44+
- Time stretching or tempo matching imported audio.
45+
- Clip instance resize handles.
46+
- Clip splitting.
47+
- Arrangement recording.
48+
- Track creation, deletion, or reordering.
49+
- Multi-select, copy/paste, duplicate shortcuts, or marquee selection.
50+
- Arrangement loop region editing.
51+
- Persistent project export/import beyond serializable in-memory model changes.
52+
- IndexedDB persistence for imported audio bytes.
53+
- Full mixer audio routing, real level metering, or effects.
54+
55+
## Constraints
56+
57+
- React UI must not own exact audio timing.
58+
- Store arrangement positions and lengths in ticks.
59+
- Use PPQ 480, where one 4/4 bar is 1920 ticks.
60+
- Keep project data serializable.
61+
- Do not store `AudioBuffer`, `AudioNode`, `File`, `Blob`, object URLs, scheduler timers, or drag runtime objects in project JSON.
62+
- Playback must schedule audio against `AudioContext.currentTime`.
63+
- Audio clip source duration may be seconds because it describes media length, but arrangement placement still uses ticks.
64+
- Imported audio clips must fail clearly if their runtime file data is missing.
65+
- Use CSS Modules and semantic design tokens for UI changes.
66+
- Preserve existing `PAT` mode clip editing behavior.
67+
68+
## Data Model Notes
69+
70+
The arrangement should use serializable clip instances:
71+
72+
```ts
73+
export interface ClipInstance {
74+
id: string;
75+
clipId: string;
76+
trackId: string;
77+
startTick: Tick;
78+
lengthTicks: Tick;
79+
sourceOffsetSeconds?: number;
80+
}
81+
```
82+
83+
For hybrid clips, the first implementation should use the clip's `lengthTicks` as the default instance length. Hybrid clip events play once relative to the instance start. Repeating a pattern should be represented by multiple placed instances until a later feature adds looping or repeat handles.
84+
85+
For imported audio clips, `lengthTicks` controls the visible and scheduled clip-instance duration. Without time stretching, playback uses the decoded audio at original speed:
86+
87+
- If the instance is shorter than the source, playback is cropped.
88+
- If the instance is longer than the source, the remaining duration is silence.
89+
- If runtime imported file data is unavailable after refresh, the clip instance should remain visible but audio playback should report a clear missing-source limitation.
90+
91+
The first implementation may seed a small set of arrangement tracks in app state. Track creation, deletion, and reordering are separate tasks.
92+
93+
## UI Notes
94+
95+
Use the existing `SONG` arrangement layout:
96+
97+
- Sidebar clip rows are drag sources.
98+
- Arrangement track lanes are drop targets.
99+
- Placed clips render as timeline blocks.
100+
- Dragging a placed clip moves it to another snapped start time or track.
101+
- Selecting a placed clip shows a clear selected state.
102+
- Deleting a placed clip instance removes only that arrangement placement, not the source clip from the sidebar.
103+
104+
Snap should start simple. Prefer beat-level snapping, using 480 ticks, unless the existing arrangement snap control already supports a narrower value. Later features may add user-selectable snap resolution.
105+
106+
If browser drag-and-drop is awkward for track timeline geometry, pointer-based dragging is acceptable. The feature should still behave like drag placement from the user's perspective.
107+
108+
## Audio Notes
109+
110+
`SONG` playback should schedule arrangement events, not selected-clip loop events.
111+
112+
The audio engine or feature orchestration should expand clip instances into runtime scheduler events:
113+
114+
- Hybrid clip drum events: `instance.startTick + drumEvent.startTick`.
115+
- Hybrid clip note events: `instance.startTick + noteEvent.startTick`.
116+
- Audio clips: source starts at `instance.startTick`, optionally from `sourceOffsetSeconds`.
117+
118+
The arrangement transport may initially play linearly from tick 0 through the end of the last clip instance and then stop. Arrangement loop ranges can be added later.
119+
120+
Events already scheduled inside the lookahead window may still play briefly after edits, pause, or stop. Keep the scheduling window short enough for interactive editing.
121+
122+
## Done when
123+
124+
- Users can drag a sidebar clip into a `SONG` arrangement track.
125+
- A placed clip block appears at the snapped time and correct track.
126+
- Placed clip blocks are backed by serializable `ClipInstance` data.
127+
- Static demo arrangement clips are removed or replaced by seeded serializable model state.
128+
- Users can move a placed clip instance to another snapped time or track.
129+
- Users can select and delete a placed clip instance without deleting the source clip.
130+
- `SONG` transport playback schedules placed clip instances.
131+
- Pause, resume, and stop work in `SONG` mode.
132+
- A visual arrangement playhead follows playback and resets or hides appropriately when stopped.
133+
- Hybrid clip drum and note events play at their arrangement positions.
134+
- Audio clip instances play when runtime imported audio data is available.
135+
- Missing imported audio runtime data is reported clearly instead of silently failing.
136+
- `PAT` mode clip editing and clip playback still work.
137+
- Relevant tests and docs are updated.
138+
139+
## Verification
140+
141+
Run:
142+
- `npm run typecheck`
143+
- `npm run lint`
144+
- `npm run test`
145+
- `npm run build`
146+
147+
Manual check:
148+
- Switch to `SONG` mode.
149+
- Drag a sidebar clip into an arrangement track.
150+
- Confirm the placed clip aligns to the snapped grid.
151+
- Drag the placed clip to another time and track.
152+
- Select and delete the placed clip.
153+
- Place multiple clips across tracks and press play.
154+
- Confirm the arrangement playhead roughly matches audible playback.
155+
- Confirm pause, resume, and stop behavior in `SONG` mode.
156+
- Confirm `PAT` mode still edits and plays the selected clip.
157+
- If WAV import is implemented, place an imported audio clip and confirm it plays when runtime data is available.
158+
- Refresh the page and confirm missing imported audio data is handled clearly if persistence is not implemented.
159+
160+
## PR notes
161+
162+
- Reference issue #41.
163+
- Explain the `ClipInstance` model changes or model usage.
164+
- Explain how sidebar drag placement and arrangement move/delete work.
165+
- Explain how `SONG` playback differs from `PAT` clip loop playback.
166+
- State clearly that time stretching, resizing, arrangement loop regions, and persistent imported audio bytes are deferred.

docs/product.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ Build a browser-first mini DAW for creating electronic music with short clips. T
1616
2. Create or select a 1-bar clip.
1717
3. Build a clip with drum events and pitched notes, or import a local WAV file as an audio clip.
1818
4. Start loop playback and edit while listening.
19-
5. Later, arrange clips into a larger song.
19+
5. Place clips on the `SONG` arrangement timeline.
20+
6. Play the arranged timeline to build a larger song.
2021

2122
## MVP Definition
2223

@@ -44,6 +45,7 @@ The MVP is a browser-first 1-bar hybrid clip editor with:
4445

4546
- Users can create a short 1-bar loop with drums and pitched notes.
4647
- Playback timing is stable enough for simple electronic music loops.
48+
- Users can place clips on an arrangement timeline and hear the placed clips in song order.
4749
- Project data can be represented as JSON without runtime audio objects.
4850
- The codebase separates UI rendering, project state, persistence, and audio scheduling.
4951
- Future contributors can pick up feature specs and implement small, reviewable tasks.

0 commit comments

Comments
 (0)