You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: PLANS.md
+11-6Lines changed: 11 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -29,8 +29,11 @@ M1 should include:
29
29
30
30
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.
31
31
32
-
1.#41 Arrangement clip placement and playback -> `docs/features/16-arrangement-clip-placement-and-playback.md`
33
-
2.#43 Mixer audio routing and track controls -> `docs/features/17-mixer-audio-routing-and-track-controls.md`
32
+
1.#43 Mixer audio routing and track controls -> `docs/features/17-mixer-audio-routing-and-track-controls.md`
Copy file name to clipboardExpand all lines: docs/architecture.md
+9-2Lines changed: 9 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,7 +15,9 @@ The main rule is separation of concerns: UI rendering, persistence, and audio sc
15
15
- Display audio state such as stopped, playing, paused, and playhead position.
16
16
- Render song-level UI shells such as arrangement and mixer panels.
17
17
- Let users place, move, select, and delete arrangement clip instances.
18
+
- Let users adjust clip and arrangement lengths through model-backed controls.
18
19
- Dispatch mixer control edits such as volume, mute, solo, and master volume.
20
+
- Trigger save, restore, import, and export workflows through persistence/audio APIs.
19
21
- Use `requestAnimationFrame` for visual playheads where needed.
20
22
- Avoid owning exact audio timing.
21
23
@@ -24,6 +26,7 @@ The main rule is separation of concerns: UI rendering, persistence, and audio sc
24
26
- Define serializable project data types.
25
27
- Store musical time in ticks.
26
28
- Provide pure transformations for creating, editing, duplicating, and deleting clips and events.
29
+
- Store clip length and arrangement length as serializable musical values.
27
30
- Provide pure transformations for creating, moving, and deleting arrangement clip instances.
28
31
- Store serializable mixer settings such as track volume, mute, solo, and master volume when mixer routing exists.
29
32
- Avoid references to Web Audio runtime objects.
@@ -36,6 +39,7 @@ The main rule is separation of concerns: UI rendering, persistence, and audio sc
36
39
- Schedule audio against `AudioContext.currentTime`.
37
40
- Schedule arrangement playback from placed clip instances when `SONG` mode is active.
38
41
- Own mixer routing, track gain nodes, master gain, runtime meters, and effect nodes when those features exist.
42
+
- Provide an offline rendering path for arrangement WAV export when that feature exists.
39
43
- Expose a small typed API to the UI and feature code.
40
44
- Never depend on React components.
41
45
@@ -46,7 +50,8 @@ The main rule is separation of concerns: UI rendering, persistence, and audio sc
46
50
- Store sample references by stable IDs or metadata, not decoded buffers.
47
51
- Handle browser file import boundaries for user-provided audio files.
48
52
- Keep `File`, `Blob`, object URL, IndexedDB handles, and decoded audio buffers out of model data.
49
-
- Later, support local storage or IndexedDB.
53
+
- Persist the active browser project and imported sample blobs through IndexedDB.
54
+
- Export rendered arrangement audio as WAV without storing runtime audio objects in project JSON.
50
55
51
56
### Utilities
52
57
@@ -79,12 +84,14 @@ src/
79
84
80
85
## Runtime vs Serializable Data
81
86
82
-
Serializable data includes projects, tracks, clips, clip instances, drum events, note events, sample metadata, tempo, and time signature.
87
+
Serializable data includes projects, tracks, clips, clip instances, drum events, note events, sample metadata, tempo, time signature, clip length, arrangement length, arrangement loop ranges, and mixer settings.
83
88
84
89
Runtime data includes `AudioContext`, `AudioBuffer`, audio nodes, scheduler timers, decoded sample caches, and currently playing source nodes. Runtime data must not be written into project JSON.
85
90
86
91
Imported browser files are also runtime or persistence-layer data. Project JSON may reference imported audio by stable sample IDs and metadata such as file name, MIME type, and duration, but it must not embed `File`, `Blob`, object URL, or decoded PCM data.
87
92
93
+
IndexedDB may store imported sample blobs or bytes outside the project JSON document. The model should reference those blobs by stable sample IDs so the audio engine can rebuild decoded runtime caches after restore.
94
+
88
95
Mixer settings such as volume, mute, solo, and master volume are serializable project or app-model data once real mixer routing exists. Mixer runtime data, including `GainNode`, `AnalyserNode`, effect nodes, meter buffers, and active routing graphs, belongs to the audio engine runtime and must not be stored in project JSON.
89
96
90
97
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.
Copy file name to clipboardExpand all lines: docs/audio-engine.md
+18-2Lines changed: 18 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,7 +34,7 @@ In the browser implementation, decoded buffers should live in the audio engine r
34
34
35
35
Imported WAV files should follow the same runtime rule. The file picker may provide a `File` or `Blob`, but the audio engine should only keep decoded buffers in a runtime cache keyed by a stable imported sample ID. Project JSON stores metadata such as file name, MIME type, and duration, not the `File`, `Blob`, object URL, or `AudioBuffer`.
36
36
37
-
Until IndexedDB or another persistence layer stores imported file bytes, imported audio clips may be session-only. The audio engine should fail clearly if project metadata references an imported sample whose runtime file data is no longer available.
37
+
IndexedDB persistence may store imported file bytes outside project JSON. After restore, the audio engine should rebuild decoded buffers from those persistent blobs on demand. If project metadata references an imported sample whose bytes are unavailable, the engine should fail clearly instead of silently skipping playback.
38
38
39
39
## Imported Audio Clip Playback
40
40
@@ -65,7 +65,7 @@ Arrangement playback should:
65
65
- Respect `clipInstance.lengthTicks` as the visible and playable duration boundary.
66
66
- Keep play, pause, resume, and stop behavior separate from React render timing.
67
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.
68
+
Arrangement playback should derive its outer bounds from arrangement state, such as `arrangement.lengthBars`, when that state exists. Before adjustable arrangement length exists, a fixed or inferred arrangement range is acceptable if it is documented in the feature PR.
69
69
70
70
The current first pass reuses the existing lookahead loop scheduler for `SONG` mode by setting a loop range that covers the visible arrangement. This keeps scheduling independent from React and enables pause/resume with the existing transport API, but it is not yet a true one-shot linear song transport. A later transport task should add non-looping arrangement playback that stops at the arrangement end.
71
71
@@ -75,6 +75,22 @@ Imported audio clips should play at original speed unless a later time-stretchin
75
75
76
76
Arrangement playback still uses the lookahead scheduler. UI drag state, arrangement DOM geometry, visual playheads, decoded buffers, and active source nodes remain runtime-only.
77
77
78
+
## Offline WAV Export
79
+
80
+
Arrangement WAV export should use an offline audio rendering path, not the live React UI or visual playhead.
81
+
82
+
The first export target should be WAV because the browser can produce it from PCM data without a compressed-audio encoder dependency. A predictable first format is stereo 44.1 kHz 16-bit PCM WAV unless implementation constraints justify another choice in the PR.
83
+
84
+
Export rendering should:
85
+
86
+
- Render from arrangement tick 0 through the configured arrangement length.
87
+
- Use the same tick-to-audio-time conversion rules as live playback.
88
+
- Include the clip types, instruments, and mixer routing available at the time of implementation.
89
+
- Block with a clear error when required sample data is missing.
90
+
- Avoid mutating live transport state, active source nodes, or React component state during rendering.
91
+
92
+
WAV encoding can be a small utility that converts rendered PCM into a Blob. MP3, FLAC, stem export, cloud export, and mastering processors are separate features.
93
+
78
94
## Mixer Routing
79
95
80
96
The first functional mixer should apply to `SONG` arrangement playback. It depends on scheduled sources knowing their arrangement `trackId`.
Copy file name to clipboardExpand all lines: docs/data-model.md
+30-3Lines changed: 30 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,6 +8,8 @@ For 4/4:
8
8
9
9
- 1 beat = 480 ticks.
10
10
- 1 bar = 1920 ticks.
11
+
- 2 bars = 3840 ticks.
12
+
- 4 bars = 7680 ticks.
11
13
- 16-step grid step = 120 ticks.
12
14
13
15
Seconds are derived at playback time from ticks and tempo. Do not store seconds as the primary event position.
@@ -36,10 +38,12 @@ The initial transport UI range is 60 to 180 BPM. Implementations should validate
36
38
37
39
## Hybrid Clips
38
40
39
-
Early clips may contain both drum events and note events. This keeps the M1 editor focused: one 1-bar clip can hold a drum pattern and a piano roll phrase.
41
+
Early clips may contain both drum events and note events. This keeps the M1 editor focused: one clip can hold a drum pattern and a piano roll phrase.
40
42
41
43
Later, the model can evolve toward separate drum, MIDI, and audio clip types if arrangement and editing workflows need stronger separation.
42
44
45
+
The initial clip length is 1 bar, represented as `lengthTicks: 1920`. Later clip editing should support 1, 2, and 4 bar hybrid clips by changing `lengthTicks` to 1920, 3840, or 7680 ticks. Event positions and note durations remain tick-based and must stay inside the clip length.
46
+
43
47
Imported WAV files should use a separate audio clip shape rather than forcing audio file state into the M1 hybrid clip fields.
44
48
45
49
## Mixer State
@@ -80,7 +84,7 @@ Effect slots may remain UI placeholders until a basic effects feature introduces
80
84
81
85
## M1 Clip Collection and Sidebar Membership
82
86
83
-
The M1 browser app should maintain an ordered collection of reusable 1-bar hybrid clips. This may live in app-level project state before full export/import exists, but the data itself should be serializable and compatible with the future `Project.clips` field.
87
+
The M1 browser app should maintain an ordered collection of reusable hybrid clips. This may live in app-level project state before full export/import exists, but the data itself should be serializable and compatible with the future `Project.clips` field.
84
88
85
89
Runtime UI selection, such as `selectedClipId` and the selected sidebar item, may remain app state. The clip list, clip names, drum lane settings, pitched instrument membership, drum events, and note events should be serializable.
86
90
@@ -121,7 +125,7 @@ The model should keep these concepts separate:
121
125
- Runtime media data: `File`, `Blob`, object URL, decoded `AudioBuffer`, and active source nodes.
122
126
- Future arrangement placement: where a clip instance appears in song time and how long that instance lasts.
123
127
124
-
Imported file bytes and decoded sample data are not project JSON. Until IndexedDB or another persistence feature stores imported blobs, imported audio clips may be session-only and should be documented in the UI.
128
+
Imported file bytes and decoded sample data are not project JSON. IndexedDB persistence may store imported blobs outside the project document and connect them back through stable sample IDs. Until that persistence feature exists, imported audio clips may be session-only and should be documented in the UI.
125
129
126
130
Illustrative shape:
127
131
@@ -158,6 +162,13 @@ The arrangement view places reusable clips on tracks using `ClipInstance` object
158
162
- How long the placed instance lasts in arrangement ticks.
159
163
- Optional source offset for audio clips.
160
164
165
+
`ArrangementState` owns arrangement-level song settings such as:
166
+
167
+
- Total arrangement length in bars.
168
+
- Current loop range.
169
+
170
+
The first adjustable arrangement length feature should default to 16 bars, keep a minimum of 1 bar, and use a practical maximum such as 128 bars. The arrangement ruler, grid, scroll width, loop bounds, playback bounds, and export duration should derive from this state.
171
+
161
172
`ArrangementLoopRange` owns the current song playback loop boundaries:
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.
Persist the user's current project in the browser so a refresh or reopened tab can restore clips, arrangement data, mixer settings, imported sample metadata, and imported sample audio bytes.
9
+
10
+
## Context
11
+
12
+
The app is browser-first and project data must remain serializable. Runtime audio objects such as `AudioContext`, `AudioBuffer`, node graphs, object URLs, and decoded sample caches must not be stored in project JSON.
13
+
14
+
Imported audio files need separate durable storage because object URLs and decoded buffers are session-only. IndexedDB is the first local persistence target.
15
+
16
+
## Scope
17
+
18
+
Included:
19
+
20
+
- Add an IndexedDB persistence layer under `src/persistence/`.
21
+
- Store a versioned project document for the active project.
22
+
- Store imported sample metadata in serializable project state.
23
+
- Store imported sample file bytes or blobs in IndexedDB using stable sample IDs.
24
+
- Restore the last active project on app startup.
25
+
- Rebuild runtime audio caches from stored blobs only when needed.
26
+
- Add debounced autosave for project edits.
27
+
- Show minimal save status, such as saved, saving, or save failed.
28
+
- Add a baseline migration/version field for stored project documents.
29
+
- Handle unavailable storage or quota errors with visible user feedback.
30
+
31
+
Excluded:
32
+
33
+
- Cloud sync.
34
+
- User accounts.
35
+
- Multi-device collaboration.
36
+
- A full project browser or multi-project dashboard.
37
+
- File-system project export/import.
38
+
- Final audio rendering/export.
39
+
- Storing `AudioBuffer`, `AudioNode`, `File`, or object URL values in project JSON.
40
+
41
+
## Constraints
42
+
43
+
- Keep project JSON serializable.
44
+
- Use stable IDs to connect project sample metadata to IndexedDB blobs.
45
+
- Keep persistence separate from React rendering and audio scheduling.
46
+
- Do not make the audio engine depend on IndexedDB.
47
+
- Do not introduce a runtime dependency unless the implementation clearly needs it and the PR explains why.
48
+
- Tests may use lightweight mocks or adapters for IndexedDB behavior.
49
+
50
+
## Done when
51
+
52
+
- Refreshing the browser restores the active project state.
53
+
- Imported WAV clips can still be played after refresh if their blobs were saved successfully.
54
+
- Autosave does not block UI interactions.
55
+
- Save failures are visible and do not corrupt in-memory state.
56
+
- Stored project records include a schema version.
57
+
- Runtime audio caches are rebuilt from persistent data rather than serialized directly.
58
+
59
+
## Verification
60
+
61
+
Run:
62
+
63
+
-`npm run typecheck --if-present`
64
+
-`npm run lint --if-present`
65
+
-`npm run test --if-present`
66
+
-`npm run build --if-present`
67
+
68
+
Manual check:
69
+
70
+
- Create or modify a clip.
71
+
- Import a WAV file.
72
+
- Place clips in the arrangement.
73
+
- Refresh the page.
74
+
- Confirm the project, clips, placement, and imported audio references are restored.
75
+
- Confirm the console has no IndexedDB or decoding errors.
76
+
77
+
## PR notes
78
+
79
+
- Summarize the IndexedDB stores and schema version.
80
+
- Explain what is persisted and what remains runtime-only.
81
+
- Mention any browser storage limitations or quota behavior.
0 commit comments