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:
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "core/instrument/engine/play_params.h" // PlayMode (the AMP group's Gate/Trigger face)
|
||||
#include "core/instrument/engine/play_params.h" // PlayMode (the mode-dependent group faces)
|
||||
#include "core/instrument/ui/knob_deck.h" // DeckGroupDesc
|
||||
|
||||
namespace reasampler::instrument::ui {
|
||||
@@ -17,18 +17,20 @@ namespace reasampler::instrument::ui {
|
||||
enum class DeckParam {
|
||||
kPlayMode = 0, // Gate | Trigger toggle
|
||||
kPitchEngine, // Varispeed | Preserve toggle
|
||||
kAttack, // AHDSR attack (Gate) / —
|
||||
kHold, // AHDSR hold (Gate)
|
||||
kDecay, // AHDSR decay (Gate)
|
||||
kSustain, // AHDSR sustain (Gate)
|
||||
kRelease, // AHDSR release (Gate)
|
||||
kTrigLength, // Trigger %-length
|
||||
kTrigFadeIn, // Trigger fade-in
|
||||
kTrigFadeOut, // Trigger fade-out
|
||||
kPitchEnvEnable, // AD pitch envelope on|off
|
||||
kPitchEnvAttack, // AD pitch attack
|
||||
kPitchEnvDecay, // AD pitch decay
|
||||
kPitchEnvDepth, // AD pitch depth in +/- semitones
|
||||
kAttack, // amp AHDSR attack (Gate)
|
||||
kHold, // amp AHDSR hold (Gate)
|
||||
kDecay, // amp AHDSR decay (Gate)
|
||||
kSustain, // amp AHDSR sustain (Gate)
|
||||
kRelease, // amp AHDSR release (Gate)
|
||||
kTrigLength, // Trigger play span, % of the post-start length
|
||||
kTrigAttack, // amp AHD attack (Trigger)
|
||||
kTrigHold, // amp AHD hold, % of the span left after attack + decay
|
||||
kTrigDecay, // amp AHD decay (Trigger)
|
||||
kPitchEnvEnable, // AHD pitch envelope on|off
|
||||
kPitchEnvAttack,
|
||||
kPitchEnvHold, // % of the span left after attack + decay
|
||||
kPitchEnvDecay,
|
||||
kPitchEnvDepth, // AHD pitch depth in +/- semitones
|
||||
kKeyTrack, // key-tracking 0..200% (lives on InstrumentParams, not PlaySeconds)
|
||||
// Filter. The four control positions map through filter_params' own laws; the three
|
||||
// depths are bipolar and centred at zero.
|
||||
@@ -41,11 +43,32 @@ enum class DeckParam {
|
||||
kFilterVel, // velocity -> cutoff, +/-100%
|
||||
kFilterKeyTrack, // note -> cutoff, 0..200%
|
||||
kFilterLaw, // morph law row toggle: HP-BP-LP | HP-notch-LP
|
||||
kFilterEnvAttack,
|
||||
kFilterEnvAttack, // filter AHDSR (Gate)
|
||||
kFilterEnvHold,
|
||||
kFilterEnvDecay,
|
||||
kFilterEnvSustain,
|
||||
kFilterEnvRelease,
|
||||
kFilterTrigAttack, // filter AHD (Trigger)
|
||||
kFilterTrigHold,
|
||||
kFilterTrigDecay,
|
||||
// Curve exponents. These never get a cell of their own — each is the INNER DIAL of the
|
||||
// stage knob it shapes (see curveParamFor), which is why only sloped stages have one.
|
||||
kAttackCurve,
|
||||
kDecayCurve,
|
||||
kReleaseCurve,
|
||||
kTrigAttackCurve,
|
||||
kTrigDecayCurve,
|
||||
kPitchEnvAttackCurve,
|
||||
kPitchEnvDecayCurve,
|
||||
kFilterEnvAttackCurve,
|
||||
kFilterEnvDecayCurve,
|
||||
kFilterEnvReleaseCurve,
|
||||
kFilterTrigAttackCurve,
|
||||
kFilterTrigDecayCurve,
|
||||
// Overlay selection radios — transient view state, not parameters.
|
||||
kAmpEnvSelect,
|
||||
kPitchEnvSelect,
|
||||
kFilterEnvSelect,
|
||||
// Deck-only controls: processor-side per-instance params — routed to the processor
|
||||
// setters, never through the parameter set.
|
||||
kVoiceCount, // polyphony bound (1..32) — a stepped knob in the VOICE group
|
||||
@@ -68,17 +91,24 @@ enum DeckGroupId {
|
||||
};
|
||||
|
||||
// The deck's groups, left to right, in SIGNAL-FLOW order: pitch -> filter -> amp, then the
|
||||
// two instance-wide groups. `playMode` picks the AMP group's face, via knob_deck's blank-cell
|
||||
// reservation (knob_deck.h) so a mode flip never reflows the neighbouring groups.
|
||||
// two instance-wide groups. `playMode` picks the AMP and FILTER ENV groups' faces — AHDSR in
|
||||
// Gate, AHD in Trigger — via knob_deck's blank-cell reservation (knob_deck.h) so a mode flip
|
||||
// never reflows the neighbouring groups.
|
||||
std::vector<DeckGroupDesc> sampleDeckGroups(PlayMode playMode);
|
||||
|
||||
// The curve-exponent control a stage knob's INNER DIAL edits, or kCount when the knob shapes
|
||||
// no curve. THE one place the "every stage except Hold and Sustain is sloped" rule is written
|
||||
// down: a knob with no entry here draws no inner dial and its inner region resolves as an
|
||||
// ordinary knob grab.
|
||||
DeckParam curveParamFor(DeckParam knob);
|
||||
|
||||
// Whether control `id` is delivered LIVE — straight to the voices that are already sounding —
|
||||
// rather than through an instrument reload. The line is drawn at continuously-valued playback
|
||||
// controls, so this is a routing decision at the editor's commit site rather than a property
|
||||
// of any one knob; moving a control across the line is a change here and nowhere else.
|
||||
//
|
||||
// THE home for why each excluded control is excluded. Five continuous controls are outside the
|
||||
// live set, plus every discrete toggle:
|
||||
// THE home for why each excluded control is excluded. Three continuous controls are outside
|
||||
// the live set, plus every discrete toggle and the overlay radios:
|
||||
// - the discrete toggles (play mode, pitch engine, filter enable/law, pitch-envelope enable)
|
||||
// name a different sound rather than a different setting of one;
|
||||
// - the three capture-anchored overrides (root, loop span, start frame) name positions in
|
||||
@@ -86,13 +116,10 @@ std::vector<DeckGroupDesc> sampleDeckGroups(PlayMode playMode);
|
||||
// - kKeyTrack and kFilterVel feed values a voice latches at note-on by design (the pitch
|
||||
// ratio and the velocity-curve result), so live delivery would retune or re-gain a note
|
||||
// already struck;
|
||||
// - kTrigLength resolves playEnd_, a fact about the note. kTrigFadeIn/kTrigFadeOut are pure
|
||||
// amplitude shape and would be live-able in principle, but they live in `sample.play` and
|
||||
// are baked into SampleData at build time — the engine rebuild copies that verbatim, so
|
||||
// only a reload can deliver them without widening LiveValues. They fold into the AHD
|
||||
// alongside Gate's, at which point they inherit its routing; until then they reload.
|
||||
// Consequence, stated plainly: a Trigger-mode instance gets NO live delivery on its amplitude
|
||||
// controls. Only the filter and pitch-envelope knobs move a sounding Trigger one-shot.
|
||||
// - kTrigLength resolves playEnd_, a fact about the note, not a setting of it;
|
||||
// - the overlay radios select what the editor DRAWS and reach no parameter at all.
|
||||
// Both amp shapes are live: the Trigger fade pair that used to reload folded into the AHD and
|
||||
// inherited its routing, so a Trigger-mode instance now tracks its amplitude knobs too.
|
||||
bool isLiveDeckParam(DeckParam id);
|
||||
|
||||
// The editor drag kinds that can commit live, in this pure module's own vocabulary (the
|
||||
@@ -102,9 +129,9 @@ enum class LiveDragKind { kOther, kDeckKnob, kEnvNode };
|
||||
|
||||
// Whether a drag of `kind` commits live. A deck knob is live per isLiveDeckParam (negative ids
|
||||
// are the shell's processor-side sentinels and out-of-range ids are not controls, so neither
|
||||
// reaches the enum); an envelope-node drag is live only in Gate, where it edits the AHDSR —
|
||||
// in Trigger the same drag rewrites the play span, which is not a live control.
|
||||
bool liveCommitFor(LiveDragKind kind, int paramId, PlayMode playMode);
|
||||
// reaches the enum); an envelope-node drag is live in either mode, since every stage value it
|
||||
// can reach — AHDSR or AHD, on any of the three envelopes — is itself live.
|
||||
bool liveCommitFor(LiveDragKind kind, int paramId);
|
||||
|
||||
// The deck's BIPOLAR knob law: 0.5 of the knob's travel is zero depth, the ends are -1 and
|
||||
// +1. Exact inverses, and exact at the centre detent (0.5 -> 0 -> 0.5), so a knob parked at
|
||||
|
||||
Reference in New Issue
Block a user