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:
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
// live_contours.h — the three drawn EG contours as one fixed-capacity plain value, and the block
|
||||
// that publishes them to the audio thread so a sounding voice follows a contour edit. Separate
|
||||
// from LiveValues on purpose: at kMaxCurvePoints x 3 this is ~9 KB, and riding the live block
|
||||
// would put it on every knob publish, automation merge and field compare.
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
#include "core/instrument/engine/seqlock.h"
|
||||
#include "core/instrument/engine/velocity_curve.h"
|
||||
|
||||
namespace reasampler::instrument::engine {
|
||||
|
||||
// One contour's points, copied out of its VelocityCurve so the audio thread can hold it without
|
||||
// a vector. `count` never exceeds kMaxCurvePoints — the curve's own ceiling — and the points
|
||||
// past it are ignored.
|
||||
struct ContourPoints {
|
||||
std::uint32_t count = 0;
|
||||
VelocityPoint points[kMaxCurvePoints];
|
||||
};
|
||||
|
||||
// All three are carried whatever each envelope's mode: Staged|Spline is a note-on fact that
|
||||
// travels by reload, so the voice decides which cursors to rebind and the block stays one shape.
|
||||
struct LiveContours {
|
||||
ContourPoints amp;
|
||||
ContourPoints pitch;
|
||||
ContourPoints filter;
|
||||
};
|
||||
|
||||
static_assert(std::is_trivially_copyable_v<LiveContours>,
|
||||
"the contour block is copied under a seqlock — it must stay a plain value");
|
||||
|
||||
ContourPoints contourPoints(const VelocityCurve& curve);
|
||||
|
||||
// Templated over the frames and seconds parameter representations for the same reason
|
||||
// splineActive is (play_params.h): both spell the three fields identically. Off the audio thread.
|
||||
template <class Play>
|
||||
LiveContours foldContours(const Play& p) {
|
||||
LiveContours c{};
|
||||
c.amp = contourPoints(p.ampSpline.contour);
|
||||
c.pitch = contourPoints(p.pitchSpline.contour);
|
||||
c.filter = contourPoints(p.filterSpline.contour);
|
||||
return c;
|
||||
}
|
||||
|
||||
// A class rather than an alias so play_params.h can forward-declare it.
|
||||
class LiveContourBlock : public Seqlock<LiveContours> {};
|
||||
|
||||
} // namespace reasampler::instrument::engine
|
||||
Reference in New Issue
Block a user