f7505d0e53
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.
51 lines
2.0 KiB
C++
51 lines
2.0 KiB
C++
#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
|