instrument: one staged-envelope system — per-segment curves, the sustain-less AHD, and a shared overlay for all three envelopes
Trigger's fade pair folds into the AHD (and goes live); the release anchors right; Preserve rings its synthetic tail out instead of cutting it. Payload v10.
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
#include "core/instrument/ui/deck_groups.h" // DeckParam / DeckGroupId / sampleDeckGroups
|
||||
#include "core/instrument/ui/editor_geometry.h" // Rect (shared sub-rect type)
|
||||
#include "core/instrument/ui/envelope_edit.h" // EnvClampBounds / NodeHit (envelope node hit-test/edit)
|
||||
#include "core/instrument/ui/envelope_overlay.h" // AmpEnvelope / EnvNode (envelope overlay draw seam)
|
||||
#include "core/instrument/ui/envelope_overlay.h" // StageEnvelope / EnvNode (envelope overlay draw seam)
|
||||
#include "core/instrument/ui/knob_deck.h" // DeckGroupDesc / DeckLayout (the deck band)
|
||||
#include "core/instrument/ui/sample_bands.h" // SampleBands (the band-stack allocator)
|
||||
#include "core/instrument/ui/sample_chrome.h" // ChromeRects (chrome-band interior)
|
||||
@@ -41,7 +41,6 @@ using instrument::map::PlaySeconds;
|
||||
using instrument::map::SampleChoice;
|
||||
using instrument::map::SampleRefEntry;
|
||||
using instrument::map::SampleRefs;
|
||||
using instrument::ui::AmpEnvelope;
|
||||
using instrument::ui::ChromeRects;
|
||||
using instrument::ui::DeckGroupDesc;
|
||||
using instrument::ui::EnvClampBounds;
|
||||
@@ -49,6 +48,7 @@ using instrument::ui::EnvNode;
|
||||
using instrument::ui::OverlayArea;
|
||||
using instrument::ui::Rect;
|
||||
using instrument::ui::SampleBands;
|
||||
using instrument::ui::StageEnvelope;
|
||||
|
||||
class ReaSamplerProcessor;
|
||||
|
||||
@@ -81,6 +81,11 @@ private:
|
||||
enum class DragKind { kNone, kRootMarker, kWaveMarker, kScrollThumb, kEnvNode,
|
||||
kCurveNode, kDeckKnob };
|
||||
|
||||
// Which envelope the waveform overlay is drawing and editing. Exclusive, and kNone is a
|
||||
// valid resting state — the editor opens there. Transient view state: never persisted,
|
||||
// never a parameter.
|
||||
enum class OverlayEnv { kNone, kAmp, kPitch, kFilter };
|
||||
|
||||
// Controls on the setup surface. The int value is the opaque control id the pure
|
||||
// knob_deck hit-test returns; the shell maps it to the one parameter set or a
|
||||
// processor-side per-instance setter. The id space and the deck's group composition are
|
||||
@@ -107,6 +112,8 @@ private:
|
||||
kChanStereo, // the stereo channel-mode segment
|
||||
kPreview, // the preview-trigger button
|
||||
kControl, // a knob-deck element (index = control id)
|
||||
kInnerDial, // a knob cell's inner curve dial (index = the OUTER control id)
|
||||
kEnvRadio, // an envelope deck's overlay-select radio (index = radio control id)
|
||||
kCurveNode, // a velocity-curve control point (index = point index)
|
||||
kVelKnob, // the chrome preview-velocity radial knob
|
||||
kStripKey, // a piano-strip key (index = MIDI note); carries the name tooltip
|
||||
@@ -302,8 +309,8 @@ private:
|
||||
// pitch envelope) — wall-clock seconds, rate-free; the build resolves to frames.
|
||||
|
||||
// The normalized [0,1] display value for control `id` given `play` (seconds -> 0..1 over
|
||||
// a fixed ceiling, sustain 0..1 as-is, %-length/fade frames -> 0..1, semitone depth
|
||||
// centered at 0.5).
|
||||
// a fixed ceiling, levels and fractions as-is, semitone depth centered at 0.5, curve
|
||||
// exponents over their logarithmic travel).
|
||||
double controlValue(int id, const PlaySeconds& play) const;
|
||||
|
||||
// Applies a committed control interaction to `play`: a knob's normalized `value` or a
|
||||
@@ -315,22 +322,22 @@ private:
|
||||
// over the knob's 0..1).
|
||||
void applyParamControl(int id, double value, int segment);
|
||||
|
||||
// The Trigger fade-in/out knob full-scale, in source frames: kFadeMaxSeconds resolved
|
||||
// against the live rate — never a baked-in rate. Returns 0 when the rate is unknown.
|
||||
double fadeMaxFrames() const;
|
||||
// The overlay speaks one StageEnvelope whichever envelope is active; pack/unpack are the
|
||||
// only place that knows which stored struct each `which` maps onto, so the drawn shape and
|
||||
// a committed node drag can never disagree about it. AHDSR seconds are rate-free and copy
|
||||
// 1-to-1; an AHD additionally needs the wall-clock span its Hold fraction is taken against,
|
||||
// which is where `frames`/`startFrame` and the live rate come in.
|
||||
|
||||
// envelope_overlay's AmpEnvelope stores Trigger fades as fractions of the played span,
|
||||
// while the parameter set stores source frames — pack/unpack own that conversion (see
|
||||
// envelope_overlay.h's trigger-seam note). `frames` is total source frames; AHDSR
|
||||
// seconds are rate-free and copy 1-to-1.
|
||||
// PACK (draw): play params -> StageEnvelope. `startFrame` is the effective start point.
|
||||
StageEnvelope packEnvelope(OverlayEnv which, const PlaySeconds& play, std::int64_t frames,
|
||||
std::int64_t startFrame) const;
|
||||
|
||||
// PACK (draw): play params -> AmpEnvelope. `startFrame` is the effective start point.
|
||||
AmpEnvelope packEnvelope(const PlaySeconds& play, std::int64_t frames,
|
||||
std::int64_t startFrame) const;
|
||||
// UNPACK (commit): an edited StageEnvelope -> the play params, in place.
|
||||
void unpackEnvelope(OverlayEnv which, const StageEnvelope& env, PlaySeconds& play) const;
|
||||
|
||||
// UNPACK (commit): an edited AmpEnvelope -> the play params, in place.
|
||||
void unpackEnvelope(const AmpEnvelope& env, std::int64_t frames, std::int64_t startFrame,
|
||||
PlaySeconds& play) const;
|
||||
// The radio control id that selects `which`, and its inverse. One table, so the deck's
|
||||
// radio and the overlay can never drift apart.
|
||||
static OverlayEnv overlayEnvForRadio(int radioId);
|
||||
|
||||
// Clamp bounds envelope_edit uses, matching the sliders' own domains so a node drag can
|
||||
// never produce a param a slider couldn't.
|
||||
@@ -417,16 +424,21 @@ private:
|
||||
WaveMarker waveMarker_ = WaveMarker::kStart;
|
||||
SetupMarkers dragStartMarkers_;
|
||||
std::int64_t dragSampleFrames_ = 0; // decoded length of the sample under the drag
|
||||
std::int64_t dragStartFrame_ = 0; // effective start point at grab time; for env-node drag
|
||||
|
||||
// Scrollbar-thumb drag: the offset at grab time. kDeckKnob drag: which control id.
|
||||
int dragStartScrollOffset_ = 0;
|
||||
int dragParamId_ = -1; // control id under a kDeckKnob drag; -2 = preview-vel knob
|
||||
// The cell whose INNER dial is under a kDeckKnob drag (dragParamId_ then holds the curve
|
||||
// control), so the paint side can light the right ring. -1 when the grab was the outer knob.
|
||||
int dragInnerCellId_ = -1;
|
||||
|
||||
// Envelope-node drag: which node + the AmpEnvelope snapshotted at grab (absolute-delta
|
||||
// Which envelope the overlay draws and edits (kNone = none, the opening state).
|
||||
OverlayEnv overlayEnv_ = OverlayEnv::kNone;
|
||||
|
||||
// Envelope-node drag: which node + the StageEnvelope snapshotted at grab (absolute-delta
|
||||
// contract, per envelope_edit's grabEnv).
|
||||
EnvNode envNode_ = EnvNode::Origin;
|
||||
AmpEnvelope dragStartEnv_{};
|
||||
StageEnvelope dragStartEnv_{};
|
||||
|
||||
// Velocity-curve node drag: which point, the curve snapshotted at grab
|
||||
// (resolvePointDrag's absolute-delta contract), and the grab-time box rect.
|
||||
|
||||
Reference in New Issue
Block a user