Bake window: derived note lengths carry exact durations, not ladder rungs — a long take is no longer cut at 384 beats
Hold keeps its picker. Also: one home for the %-fold, duration-ordered Hold travel, and a corrupt tail degrades to absent rather than fabricating one.
This commit is contained in:
@@ -1,32 +1,23 @@
|
||||
// trigger_seam — the shared Trigger play-span formula: how the stored %-length becomes the
|
||||
// source-frame span the voice plays, the overlay draws over, and the bake's window holds.
|
||||
// One home so those three cannot disagree about where a Trigger note ends.
|
||||
// trigger_seam — the shared Trigger play-span formula: how a %-length becomes the source-frame
|
||||
// span the voice plays, the overlay draws over, and the bake's window holds. One home so those
|
||||
// cannot disagree about where a Trigger note ends.
|
||||
//
|
||||
// playLengthFrames = round(effectiveLengthFraction * (frameCount - startFrame))
|
||||
// playLengthFrames = round(clamp01(lengthFraction) * (frameCount - startFrame))
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "core/instrument/engine/play_params.h" // splineActive (the %-knob's inert rule)
|
||||
|
||||
namespace reasampler::instrument::map {
|
||||
|
||||
// The %-length the voice ACTUALLY plays. A drawn contour is a pure time function over the
|
||||
// full sample length, so any active spline EG folds the fraction to 1.0 and the stored knob
|
||||
// goes inert (splineActive, play_params.h) — but the stored value survives, so a pre-spline
|
||||
// setting is still there to be read. Every consumer of the span must fold it here or it
|
||||
// silently plays/draws/bakes a fraction of the take.
|
||||
// `startFrame` is the effective start point (0 when absent), `lengthFraction` the EFFECTIVE one
|
||||
// — fold it through effectiveLengthFraction (play_params.h) first, or a stored-but-inert %-knob
|
||||
// shortens the span. Returns 0 for an empty post-start span and for any fraction that is not
|
||||
// above zero, NaN included; the fraction is clamped to 1.0 and the result to the span, so a
|
||||
// corrupt stored value cannot reach past the source.
|
||||
//
|
||||
// Templated over the two parameter representations for the same reason splineActive is.
|
||||
template <class Play>
|
||||
double effectiveLengthFraction(const Play& p) {
|
||||
return splineActive(p) ? 1.0 : p.trigger.lengthFraction;
|
||||
}
|
||||
|
||||
// postStart = max(0, frameCount - startFrame); playLength = round(lengthFraction * postStart).
|
||||
// `startFrame` is the effective start point (0 when absent), `lengthFraction` the EFFECTIVE
|
||||
// one above. Returns 0 when postStart == 0 or lengthFraction <= 0.
|
||||
// Voice::start evaluates this same clamped formula inline rather than calling it: the engine
|
||||
// does not depend on `map/`, in either direction.
|
||||
std::int64_t triggerPlayLength(double lengthFraction,
|
||||
std::int64_t frameCount,
|
||||
std::int64_t startFrame);
|
||||
|
||||
Reference in New Issue
Block a user