Skip to content

Commit 891c135

Browse files
authored
Merge pull request #29 from boostcampwm-snu-2026-1/feat/23-sampler-advanced-sustain
feat: add sampler sustain playback
2 parents 86b260e + e193d1a commit 891c135

26 files changed

Lines changed: 633 additions & 162 deletions

PLANS.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ M1 should include:
2929

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

32-
1. #26 Arrangement view UI shell -> `docs/features/11-arrangement-view-ui-shell.md` (PR in review)
33-
2. #23 Sampler for advanced sustain -> `docs/features/09-sampler-advanced-sustain.md`
32+
1. #23 Sampler for advanced sustain -> `docs/features/09-sampler-advanced-sustain.md` (PR in review)
3433

3534
## Planned Milestones
3635

docs/audio-engine.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,13 @@ Sample-based pitched playback should:
7474
- Use a gain envelope for attack and release.
7575
- Stop or release active voices when transport stops.
7676

77-
The first Iowa Piano implementation should avoid sustain looping. The bundled one-second piano samples are not reliable loop-ready sustain samples yet, and early loop points can make long notes sound like repeated strikes. Iowa Piano notes should currently play the sample once from the configured start offset, then stop or naturally decay.
77+
The current Iowa Piano implementation uses the shared sampler sustain path. Iowa Piano zones include explicit `sustain` metadata with forward-loop points and an envelope. If that metadata is valid for the decoded buffer and note duration, the source node uses `loop = true`, `loopStart`, and `loopEnd`. If the metadata is missing, unsupported, or invalid, playback falls back to one-shot sample behavior.
7878

79-
A future sampler sustain task may add explicit sustain metadata with `loopStartSeconds` and `loopEndSeconds`; if those values are present and valid, the source node may use `loop = true` with those loop points. Loop metadata is serializable instrument/sample metadata, but decoded buffers and active source nodes are runtime-only.
80-
81-
Do not attempt automatic loop point detection in the first pass. If loop points are added later, update the explicit metadata and document the decision.
79+
Do not attempt automatic loop point detection in this pass. Loop points are explicit serializable metadata and should be tuned by editing the zone metadata or replacing sample material.
8280

8381
Current Iowa Piano sample zones use explicit `sampleStartSeconds` offsets because the bundled one-second C4-C5 WAV files contain leading silence before the audible note attack. The engine should pass that value as the second argument to `AudioBufferSourceNode.start(when, offset)`.
8482

85-
Current Iowa Piano sample zones intentionally omit sustain metadata, so the audio engine does not enable `AudioBufferSourceNode.loop` for Iowa Piano.
83+
Current Iowa Piano loop metadata is a pragmatic first pass for the bundled 5-second samples. It uses a late tail loop region so short notes and most 1-bar notes play the natural sample decay without looping, while longer notes can loop the quieter tail instead of repeating the audible attack portion. Some samples may still have weak sustain quality depending on their source material. The engine must reject unsafe loop metadata rather than clamp invalid values into a loop.
8684

8785
The audio engine should load sample zones needed by selected note events before handing them to the lookahead scheduler. If a sample-based instrument has no zone for a note, the engine may fall back to `Default Synth` behavior for that note rather than storing any runtime fallback state in project data.
8886

@@ -101,6 +99,7 @@ Sampler sustain should:
10199
- Keep musical event positions and durations in ticks and convert them to seconds only at scheduling time.
102100
- Validate loop metadata before enabling looping.
103101
- Fall back to one-shot sample playback when loop metadata is missing or invalid.
102+
- For one-shot sample playback, complete the release fade before the earlier of note end and the usable sample region end so the buffer does not end abruptly at non-zero gain.
104103
- Apply release behavior at note end, transport pause, and transport stop so sustained voices do not remain stuck.
105104

106105
The first implementation should prefer explicit metadata over automatic analysis. Automatic loop point detection, visual loop point editing, velocity layers, round-robin selection, and full sampler preset management belong in later tasks.

docs/data-model.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ The `sustain` fields are serializable metadata. They describe how the runtime au
160160

161161
The `sampleStartSeconds` field skips leading silence before note attack. `sampleEndSeconds`, sustain loop points, crossfade length, and envelope values are sample-local seconds because they describe positions or durations inside a sample, not musical event time.
162162

163-
Current Iowa Piano sample zones intentionally omit `sustain` metadata. The samples play once from their configured start offsets and do not loop in the initial implementation. Advanced sampler sustain may add explicit loop metadata later if the loop points are tuned well enough to avoid repeated-strike artifacts.
163+
Current Iowa Piano sample zones include explicit `forward-loop` sustain metadata and basic envelope metadata for the bundled 5-second samples. The loop points use a late tail region so short notes can use the natural sample decay and longer notes avoid repeating the audible note attack. These fields are still serializable sample-zone data only. The runtime audio engine validates them against decoded buffer duration and note duration before enabling `AudioBufferSourceNode.loop`; invalid or unsupported metadata falls back to one-shot sample playback.
164164

165165
## Initial Piano Roll Implementation
166166

docs/features/09-sampler-advanced-sustain.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Feature: 09 Sampler Advanced Sustain
22

33
## Status
4-
Planned
4+
In Review
55

66
## Goal
77

docs/features/11-arrangement-view-ui-shell.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Feature: 11 Arrangement View UI Shell
22

33
## Status
4-
In Review
4+
Done
55

66
## Goal
77

@@ -20,7 +20,7 @@ A Google Stitch prototype provides a visual reference for the arrangement view.
2020
- Fixed left track headers.
2121
- Scrollable grid with track lanes.
2222
- Demo clip blocks placed on the timeline.
23-
- Bottom scrollbar and zoom area.
23+
- Native horizontal scrolling for the timeline.
2424

2525
The prototype uses Tailwind and includes layout issues, including track and clip alignment problems. Treat it as visual reference only.
2626

@@ -36,7 +36,7 @@ Included:
3636
- Add fixed-width track headers.
3737
- Add a scrollable timeline grid with horizontal track lanes and vertical bar/beat lines.
3838
- Add a few static/demo clip blocks to communicate intended layout.
39-
- Add a bottom horizontal scrollbar or scrollbar-like visual area and zoom placeholder.
39+
- Keep native horizontal scrolling available when the timeline is wider than the viewport.
4040
- Keep track headers, grid rows, and clip blocks vertically aligned through shared row-height constants.
4141
- Keep ruler, grid columns, and clip left/width values horizontally aligned through shared timeline geometry constants.
4242
- Use CSS Modules and semantic design tokens.
@@ -52,7 +52,7 @@ Excluded:
5252
- Clip duplication, clip splitting, or clip creation in the arrangement.
5353
- Real audio clips or generated waveforms.
5454
- Track mute, solo, arm, or routing behavior beyond nonfunctional visual controls.
55-
- Arrangement zoom implementation beyond a visual placeholder.
55+
- Arrangement zoom implementation.
5656
- Tailwind installation, Tailwind config, Tailwind CDN, or Tailwind utility-class-heavy React markup.
5757

5858
## Constraints

docs/testing.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Test files should use `*.test.ts` or `*.test.tsx`. Keep paths grouped by the pro
3838

3939
```text
4040
tests/unit/audio/lookahead-scheduler.test.ts
41+
tests/unit/audio/sampler-sustain.test.ts
4142
tests/unit/utils/tick-time.test.ts
4243
```
4344

9.07 MB
Binary file not shown.
9.65 MB
Binary file not shown.
9.56 MB
Binary file not shown.
7.92 MB
Binary file not shown.

0 commit comments

Comments
 (0)