Fix spline-drag rollback, bake contour leak, held-note live miss, amp clamp

Editor close mid-drag now rolls back published contours like capture-loss does; bake detaches liveContours so a printed capture can't observe a live drag; a held note now receives a live publish that lands in the same block as a note-on; amp spline read clamped to [0,1].
This commit is contained in:
2026-09-25 13:59:37 -04:00
parent f7505d0e53
commit 4567744b8f
10 changed files with 109 additions and 18 deletions
+31
View File
@@ -11,6 +11,7 @@
#include "../src/core/instrument/bake/bake_render.h"
#include "../src/core/instrument/engine/limiter.h"
#include "../src/core/instrument/engine/live_contours.h"
#include "../src/core/instrument/engine/live_params.h"
#include <cmath>
@@ -338,6 +339,36 @@ int main() {
CHECK(sameSamples(audio, reference));
}
// --- The bake detaches liveContours too, not just live -------------------------------
// A contour drag in flight publishes into liveContours (see reasampler_processor.h); a
// render that observed it would print whatever the user happens to be dragging instead
// of the dialed shape already sitting in play.ampSpline.contour.
{
instrument::engine::LiveContourBlock block;
SampleData s = makeSample(/*stereo=*/false, /*frames=*/1000);
s.play.playMode = PlayMode::Trigger;
s.play.ampSpline.mode = EnvMode::Spline;
s.play.ampSpline.contour = instrument::engine::VelocityCurve::flat(); // dialed: unity
// Publish a very different contour — ramping down to silence — into the block.
s.liveContours = &block;
{
PlayParams dragged = s.play;
dragged.ampSpline.contour = instrument::engine::VelocityCurve::rampDown();
block.publish(instrument::engine::foldContours(dragged));
}
const BakePlan plan = planOf(/*total=*/1000, /*noteOn=*/0, /*noteOff=*/1000);
const BakeAudio audio = renderBake(s, plan, kUnity, kNoLimiter);
CHECK(s.liveContours == &block); // the caller's own snapshot was not detached
SampleData detached = s;
detached.liveContours = nullptr;
const BakeAudio reference = renderBake(detached, plan, kUnity, kNoLimiter);
CHECK(sameSamples(audio, reference));
}
// --- Regression baseline: the neutral render is the source, sample for sample --------
// A Trigger voice at its own root under Varispeed reads at ratio exactly 1 and hits no
// filter, so every printed frame equals its source frame PROVIDED the amp curve's gain at