feat: add a bounded WAV sampler with looping, relinking and saved presets

This commit is contained in:
Johannes Findeisen 2026-11-05 23:50:14 +01:00
commit 35bf6a00a1
24 changed files with 213 additions and 32 deletions

View file

@ -90,3 +90,34 @@ Format 14 adds instrument controls and automation. Readers still accept v1–v13
old fixed internal assignments use their original defaults. Older builds reject
v14. Tests cover legacy-default sound equality, v13 migration, parameter/preset
round trips, pitch-bend offsets, automated block partitions, undo and GUI edits.
## Phase 42 sample instrument
**File → Load sampler WAV** assigns a Sample Player to the selected track or
relinks its existing sample while retaining its controls. Use the instrument
controls editor for root MIDI key (0..127), whole-sample loop (0/1), attack,
release and gain (0..4). One root mapping covers every MIDI key using linear
rate conversion, including source/output sample-rate differences. Loop and root
are integer controls and require hold automation. Live bend spans ±2 semitones.
This initial sampler has no multisample zones, loop-point editor or time stretch.
Extreme transposition can alias; use appropriate source material.
The existing WAV reader supports PCM16/24/32 and float32, mono/stereo downmixed
to mono. Each sample is at most 16M mono frames; the combined instrument plan
budget is 64M frames (256 MiB). Files are at most 256 MiB, with 4096 chunks.
There are 32 preallocated voices per track. Loading and freeing happen only on
the control thread; playback interpolates cached samples without I/O.
Missing/invalid samples retain their references and play silence, reported in
backend asset-issue counts, GUI preparation warnings and `xtc-check --inspect`.
Relink with Load sampler WAV; it is one undoable prepared edit. Allocation and
capacity failures reject preparation. Format 15 adds a SAMPLE reference after
each instrument's controls/automation; in-project samples save relatively and
resolve relative to the project file. Other samples retain absolute paths.
Preset files include the reference but do not embed/copy audio.
`examples/projects/original-pluck.wav` is an original synthesized example with
license/provenance in SAMPLE_LICENSE.md. Both are installed with the examples.
Tests cover source-rate conversion, one-shot endpoint, looping, release,
partitioning, preset references, missing assets, GUI relinking/undo/reload and
preparation-allocation/callback guards.

View file

@ -1,4 +1,4 @@
# Project format v14 (reads v1–v13)
# Project format v15 (reads v1–v14)
Phases 5–31 use a bounded text format implemented in C99 without a parser library.
The extension is `.xtc`. File operations run exclusively on the control thread.
@ -104,7 +104,7 @@ node types 1..4, migrating their clips to empty asset paths. Version 2 accepts
node types 1..5 and ASSET records. Both migrate to MIDI=0 and no notes.
Version 3 accepts instrument nodes and MIDI/NOTES records. Versions 1–3 migrate
all tracks to unity gain, centered pan, mute/solo off and no automation.
Saving always writes v14. Unknown versions are rejected without replacing the destination; older
Saving always writes v15. Unknown versions are rejected without replacing the destination; older
applications without v12 support cannot read current saves. Migration and maximum-path roundtrips are tested.
## Ownership and failures
@ -274,7 +274,7 @@ must rebuild and initialize the appended `xtc_automation_point.step` field.
## Phase 28 compatibility and diagnostic contract
The current reader accepts versions 1–14 and the writer always emits version 14.
The current reader accepts versions 1–15 and the writer always emits version 15.
Phase 28 made no format change; Phase 31 adds plugin format identity in v11. Saving an older document upgrades it;
retain an original backup if an older application must still open it. APP is
informational; compatibility depends on the format version, not the producer's
@ -407,3 +407,14 @@ Earlier bindings have no controls/automation; v13 internal instruments retain
fixed default sounds. Modern external instruments still require zero controls.
Instrument tempo follows project tempo. Instrument preset files use this same
schema with exactly one instrument track and no clips; they are metadata only.
## Version 15 sample references
Each instrument parameter block ends with `SAMPLE hex_path_or_dash`. Only the
internal Sample Player (index 4) may carry a nonempty sample path. Paths within
the project directory are relative on disk and resolve against the project
file's directory; other paths are absolute. Metadata loading does not read WAVs.
Missing/invalid samples remain references and become reported silence during
preparation. Controls describe root key, whole-file loop, attack, release and
gain. Earlier projects have empty sample paths. Rebuild public API consumers
for the additional copied `sample_path` field in `xtc_plugin_spec`.

View file

@ -1195,14 +1195,19 @@ pitch-bend offset regressions. See BUILTIN_DEVICES.md and PROJECT_FORMAT.md.
Provide sample-based sounds beyond the current oscillator presets.
### Tasks and acceptance criteria
- [ ] Define supported sample formats, mapping, looping, envelopes, voice limits and memory budgets.
- [ ] Load/prepare samples outside callbacks and expose an instrument editor with undo.
- [ ] Persist sample references and mappings with missing-media reporting and relinking.
- [ ] Provide original or appropriately licensed example sounds and document their licenses.
- [ ] Test playback rate conversion, boundaries, voice release, missing assets and project reload.
- [x] Define supported sample formats, mapping, looping, envelopes, voice limits and memory budgets.
- [x] Load/prepare samples outside callbacks and expose an instrument editor with undo.
- [x] Persist sample references and mappings with missing-media reporting and relinking.
- [x] Provide original or appropriately licensed example sounds and document their licenses.
- [x] Test playback rate conversion, boundaries, voice release, missing assets and project reload.
### Implementation status
Planned. Phase 38 supplies no sample instrument or sample library.
Implemented: a 32-voice, single-root WAV sampler with whole-file looping,
envelopes, gain, cached linear rate conversion and an undoable editor/relink
workflow. Format 15 persists relocatable sample references and reads v1–v14.
Missing/invalid media becomes reported silence. Original licensed example and
core, GUI, persistence, release/loop and allocation/callback tests are included.
See BUILTIN_DEVICES.md for memory/format and transposition limits.
---