// trigger_seam.h — PURE Trigger-mode frames↔fraction converter for the S-VIEW-3 envelope seam. // NO VST3, NO REAPER, NO SWELL/LICE types at the boundary. // // The TRIGGER SEAM (documented in envelope_overlay.h) converts between the two representations // of Trigger fade lengths: // // ENGINE domain (TriggerParams / sampler_core): SOURCE FRAMES — int64_t absolute frame counts // that anchor directly to the voice's source-timeline read pointer. // // OVERLAY domain (AmpEnvelope / envelope_overlay): FRACTIONS — doubles in [0,1] of the played // span, where the played span is: // playLengthFrames = round(lengthFraction * (frameCount - startFrame)) // The overlay stores fractions so the drawn shape stays invariant across sample-rate changes; // the engine stores frames so the voice advances correctly at the live rate. // // This module owns the one shared formula so the pack (frames->fractions) and unpack // (fractions->frames) paths are provably consistent and unit-tested independently of the shell. // The shell (reasampler_editor.cpp) calls these two functions from packEnvelope / unpackEnvelope. // // S-VIEW-F2 safety: the fractions produced here are in [0,1] by construction; a caller that // clamps the fractions to [0,1] before writing the AmpEnvelope preserves the slider-range // invariant (a drag can never produce a value a slider couldn't reach). #pragma once #include namespace reasampler::instrument::map { // The source-frame length of the Trigger played span: // postStart = max(0, frameCount - startFrame) // playLength = round(lengthFraction * postStart) // `frameCount` is the total decoded sample length in source frames. // `startFrame` is the effective start point (zone.startPoint, or 0 when absent). // `lengthFraction` is TriggerParams::lengthFraction — (0,1], the fraction of the post-start span. // Returns 0 when postStart == 0 or lengthFraction <= 0. std::int64_t triggerPlayLength(double lengthFraction, std::int64_t frameCount, std::int64_t startFrame); // Convert a source-frame fade count to a fraction of the play span (PACK direction, draw path). // Returns 0.0 when playLength == 0 (degenerate sample or zero %-length); the fraction is // NOT clamped — the caller clamps to [0,1] when filling AmpEnvelope so the overlay clamp logic // stays in envelope_edit, not here. double framesToFadeFraction(std::int64_t fadeFrames, std::int64_t playLength); // Convert a fade fraction to a source-frame count (UNPACK direction, commit path). // Rounds to nearest integer frame. Returns 0 when playLength == 0. std::int64_t fadeFractionToFrames(double fadeFraction, std::int64_t playLength); } // namespace reasampler::instrument::map