Make spline EG drags audible live: held and new notes follow a dragged knot

Contours ride their own seqlock block into a double-buffered engine copy, and the swap step is smoothed. Each drag move publishes contours without a model write; release still commits and reloads.
This commit is contained in:
2026-09-25 13:42:25 -04:00
parent 9ff34b0a9e
commit f7505d0e53
21 changed files with 788 additions and 97 deletions
+7 -3
View File
@@ -15,7 +15,8 @@
namespace reasampler {
namespace instrument::engine { class LiveParams; } // live_params.h; SampleData holds a pointer
// SampleData holds a pointer to each (live_params.h, live_contours.h).
namespace instrument::engine { class LiveParams; class LiveContourBlock; }
using audio::AudioSample;
using instrument::engine::VelocityCurve;
@@ -181,8 +182,8 @@ struct PlayParams {
// The three drawn contours: the alternative to adsr/trigAhd, to pitchEnv.shape, and to
// filter.env/trigEnv respectively. They sit HERE rather than inside the three envelope
// structs because those are copied whole into the live block, which must stay trivially
// copyable (live_params.h) — and a contour is not a live control anyway: like the velocity
// curves it travels by reload.
// copyable (live_params.h). A contour reaches a sounding voice through its own block
// instead (live_contours.h); only its Staged|Spline mode travels by reload.
SplineEnv ampSpline;
SplineEnv pitchSpline;
SplineEnv filterSpline;
@@ -295,6 +296,9 @@ struct SampleData {
// same knob as a live one. That is the desired behaviour — it is the note the user is
// hearing. Do not "fix" it by moving ownership into the snapshot.
const instrument::engine::LiveParams* live = nullptr;
// The drawn-contour peer of `live`, under the same ownership and null contract: null plays
// the contours in `play` for the note's whole life.
const instrument::engine::LiveContourBlock* liveContours = nullptr;
// A framesR of a different length than frames is treated as absent — a malformed pair
// never half-plays.