Bake window derives itself: %-knob fold, declick pad, Gate held to exhaustion, preview velocity; Hold is the one knob a loop needs
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "core/instrument/map/trigger_seam.h" // effectiveLengthFraction (the one %-length rule)
|
||||
|
||||
namespace reasampler {
|
||||
|
||||
void Voice::presizePreserveShifters(std::int64_t windowFrames) {
|
||||
@@ -101,13 +103,11 @@ void Voice::start(int note, int velocity, const SampleData& sample, bool declick
|
||||
env_.noteOn();
|
||||
playEnd_ = 0; // unused in Gate
|
||||
} else {
|
||||
// Trigger: play [start, playEnd) where
|
||||
// playEnd = start + round(lengthFraction*(frames-start)) — except kTrigLength is INERT
|
||||
// while any spline EG is active (splineActive, play_params.h): a contour is a pure
|
||||
// function over the FULL sample length, so truncating playEnd_ to a %-length would
|
||||
// hard-cut it mid-shape. The staged Trigger AHD below (trigSpan) plays the same full
|
||||
// span in that case, matching the "drawn-but-dead" treatment of the other staged knobs.
|
||||
double frac = splineActive(p) ? 1.0 : p.trigger.lengthFraction;
|
||||
// Trigger: play [start, playEnd) where playEnd = start + round(frac*(frames-start)).
|
||||
// The spline fold lives in effectiveLengthFraction (trigger_seam.h), which the bake's
|
||||
// window derivation reads too — a second copy of it here is what let a stored-but-inert
|
||||
// %-knob shorten the bake while the voice played the whole take.
|
||||
double frac = instrument::map::effectiveLengthFraction(p);
|
||||
if (frac <= 0.0) frac = 0.0; // %=0 -> zero play length (finishes immediately)
|
||||
if (frac > 1.0) frac = 1.0;
|
||||
std::int64_t playLen = static_cast<std::int64_t>(
|
||||
|
||||
@@ -81,6 +81,17 @@ inline double filterNormPerOctave() {
|
||||
inline constexpr double kDeclickDecay = 0.95; // per-frame decay of the compensation
|
||||
inline constexpr double kDeclickFloor = 1e-4; // below this the ramp is done (~ -80 dB)
|
||||
|
||||
// How many frames the ramp emits before the weight drops under the floor. Counted the way
|
||||
// advanceFrame runs it — emit, decay, test — rather than solved in closed form, so the two
|
||||
// can never disagree. RATE-INDEPENDENT: the decay is per frame, not per second, so an offline
|
||||
// pass at any rate pads by the same count.
|
||||
inline constexpr std::int64_t declickRampFrames() {
|
||||
std::int64_t n = 0;
|
||||
for (double w = 1.0; w >= kDeclickFloor; w *= kDeclickDecay) ++n;
|
||||
return n;
|
||||
}
|
||||
inline constexpr std::int64_t kDeclickFrames = declickRampFrames();
|
||||
|
||||
// A single voice: one active note playing the loaded capture, repitched and enveloped.
|
||||
// Reads the sample by fractional frame position with linear interpolation, advancing by the
|
||||
// pitch ratio; loops the sustain region for held notes past the loop end.
|
||||
|
||||
Reference in New Issue
Block a user