docs(envelope): add Trigger frames<->fraction seam note + zero-delta guard on fade nodes
This commit is contained in:
@@ -93,7 +93,16 @@ AmpEnvelope resolveNodeDrag(const AmpEnvelope& grabEnv, EnvNode node, const Rect
|
|||||||
// --- Trigger: fades + length are FRACTIONS. X pixels convert to a fraction of the PLAYED
|
// --- Trigger: fades + length are FRACTIONS. X pixels convert to a fraction of the PLAYED
|
||||||
// span (fades) or the whole sample (length). Monotonic: fadeIn + fadeOut <= 1 so the
|
// span (fades) or the whole sample (length). Monotonic: fadeIn + fadeOut <= 1 so the
|
||||||
// two fade nodes never cross (each clamps against the other), and length in [0, max].
|
// two fade nodes never cross (each clamps against the other), and length in [0, max].
|
||||||
|
//
|
||||||
|
// TRIGGER SEAM — CONVERSION REQUIRED ON BOTH PATHS (Wave 2 shell author, read this):
|
||||||
|
// fadeInFraction/fadeOutFraction in AmpEnvelope are fractions of the played span.
|
||||||
|
// TriggerParams (sampler_core.h) stores the corresponding values as SOURCE FRAMES
|
||||||
|
// (fadeInFrames/fadeOutFrames, int64_t). The shell owes a converter on BOTH directions:
|
||||||
|
// pack (draw): fadeInFrames/fadeOutFrames -> fraction (needs frameCount + rate)
|
||||||
|
// unpack (commit): fraction -> fadeInFrames/fadeOutFrames (same inputs)
|
||||||
|
// See the TRIGGER SEAM note on AmpEnvelope in envelope_overlay.h for the formula.
|
||||||
case EnvNode::FadeInEnd: {
|
case EnvNode::FadeInEnd: {
|
||||||
|
if (dxPixels == 0) break; // zero-motion grab: no param change, no division
|
||||||
const double playSeconds = std::max(0.0, grabEnv.lengthFraction) * totalSeconds;
|
const double playSeconds = std::max(0.0, grabEnv.lengthFraction) * totalSeconds;
|
||||||
const double dFrac = playSeconds > 0.0 ? dSec / playSeconds : 0.0;
|
const double dFrac = playSeconds > 0.0 ? dSec / playSeconds : 0.0;
|
||||||
const double hi = std::min(bounds.maxFadeInFraction,
|
const double hi = std::min(bounds.maxFadeInFraction,
|
||||||
@@ -102,6 +111,7 @@ AmpEnvelope resolveNodeDrag(const AmpEnvelope& grabEnv, EnvNode node, const Rect
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EnvNode::FadeOutStart: {
|
case EnvNode::FadeOutStart: {
|
||||||
|
if (dxPixels == 0) break; // zero-motion grab: no param change, no division
|
||||||
// FadeOutStart sits at (1 - fadeOut) of the played span; dragging it LEFT (negative dx)
|
// FadeOutStart sits at (1 - fadeOut) of the played span; dragging it LEFT (negative dx)
|
||||||
// lengthens the fade-out. So the fade-out fraction moves OPPOSITE the pixel delta.
|
// lengthens the fade-out. So the fade-out fraction moves OPPOSITE the pixel delta.
|
||||||
const double playSeconds = std::max(0.0, grabEnv.lengthFraction) * totalSeconds;
|
const double playSeconds = std::max(0.0, grabEnv.lengthFraction) * totalSeconds;
|
||||||
|
|||||||
@@ -67,9 +67,26 @@ enum class EnvNode {
|
|||||||
// zone's stored AdsrSeconds / TriggerParams. Engine-free by design (no sampler_core include).
|
// zone's stored AdsrSeconds / TriggerParams. Engine-free by design (no sampler_core include).
|
||||||
//
|
//
|
||||||
// Gate fields (SECONDS, wall-clock): attack / hold / decay / release; sustain is a LEVEL 0..1.
|
// Gate fields (SECONDS, wall-clock): attack / hold / decay / release; sustain is a LEVEL 0..1.
|
||||||
|
// These map 1-to-1 with the stored AdsrSeconds fields — no conversion required.
|
||||||
|
//
|
||||||
// Trigger fields (FRACTIONS of play): fadeIn / fadeOut as a fraction of the played span;
|
// Trigger fields (FRACTIONS of play): fadeIn / fadeOut as a fraction of the played span;
|
||||||
// lengthFraction is the played span as a fraction of the
|
// lengthFraction is the played span as a fraction of the
|
||||||
// post-start sample length (matching TriggerParams).
|
// post-start sample length (matching TriggerParams).
|
||||||
|
//
|
||||||
|
// TRIGGER SEAM — CONVERSION REQUIRED ON BOTH PATHS (Wave 2 shell author, read this):
|
||||||
|
// TriggerParams (sampler_core.h) stores Trigger fades as SOURCE FRAMES:
|
||||||
|
// fadeInFrames (int64_t) — 0->1 ramp length in source frames
|
||||||
|
// fadeOutFrames (int64_t) — 1->0 ramp length in source frames
|
||||||
|
// AmpEnvelope stores them as FRACTIONS of the played span:
|
||||||
|
// fadeInFraction = fadeInFrames / playLengthFrames
|
||||||
|
// fadeOutFraction = fadeOutFrames / playLengthFrames
|
||||||
|
// where playLengthFrames = round(lengthFraction * (frameCount - startFrame)).
|
||||||
|
// This is a NON-TRIVIAL derived view — NOT a direct field copy. The shell owes a
|
||||||
|
// converter on BOTH directions:
|
||||||
|
// PACK (draw): frames -> fraction (TriggerParams -> AmpEnvelope, needs frameCount + rate)
|
||||||
|
// UNPACK (commit): fraction -> frames (AmpEnvelope -> TriggerParams, same inputs)
|
||||||
|
// lengthFraction maps 1-to-1 with TriggerParams::lengthFraction and needs no conversion.
|
||||||
|
//
|
||||||
// Unused fields for the active mode are ignored.
|
// Unused fields for the active mode are ignored.
|
||||||
struct AmpEnvelope {
|
struct AmpEnvelope {
|
||||||
EnvMode mode = EnvMode::Gate;
|
EnvMode mode = EnvMode::Gate;
|
||||||
@@ -82,9 +99,12 @@ struct AmpEnvelope {
|
|||||||
double releaseSeconds = 0.060;
|
double releaseSeconds = 0.060;
|
||||||
|
|
||||||
// Trigger, fractions of the play span (fadeIn/fadeOut) and of the post-start length.
|
// Trigger, fractions of the play span (fadeIn/fadeOut) and of the post-start length.
|
||||||
double lengthFraction = 1.0; // (0,1] of the post-start span that plays
|
// NOTE: fadeInFraction/fadeOutFraction are DERIVED from TriggerParams::fadeInFrames/
|
||||||
double fadeInFraction = 0.0; // 0->1 ramp as a fraction of the played span
|
// fadeOutFrames — see the TRIGGER SEAM note above. A converter is owed on both the
|
||||||
double fadeOutFraction = 0.0; // 1->0 ramp as a fraction of the played span
|
// pack (draw) and unpack (commit) paths; these fields are NOT a direct TriggerParams copy.
|
||||||
|
double lengthFraction = 1.0; // (0,1] of the post-start span that plays (1-to-1 with TriggerParams)
|
||||||
|
double fadeInFraction = 0.0; // 0->1 ramp as a fraction of the played span (DERIVED — see above)
|
||||||
|
double fadeOutFraction = 0.0; // 1->0 ramp as a fraction of the played span (DERIVED — see above)
|
||||||
};
|
};
|
||||||
|
|
||||||
// One polyline vertex: a pixel point plus which node it is. The shell draws a line through the
|
// One polyline vertex: a pixel point plus which node it is. The shell draws a line through the
|
||||||
|
|||||||
Reference in New Issue
Block a user