Cut shell/instrument comment bloat ~34% (comments only, zero code change)

This commit is contained in:
2026-07-29 20:48:43 -04:00
parent 1f24c4b095
commit d4d29146c7
19 changed files with 1131 additions and 1769 deletions
+44 -51
View File
@@ -1,8 +1,7 @@
// editor_controls.cpp — the ReaSamplerEditor's PARAMETER PLUMBING (Q-W2v split of
// reasampler_editor.cpp, T4-11): the control-value domain maps (controlValue /
// applyControl — seconds/fraction/frames <-> normalized 0..1), the r11 knob-deck
// group descriptors + control-id<->value binding, the S-VIEW-3 envelope pack/unpack
// (the TRIGGER SEAM converter), the curve-popup target resolution, and applyZoneControl.
// editor_controls.cpp — the ReaSamplerEditor's parameter plumbing: the control-value domain
// maps (controlValue / applyControl — seconds/fraction/frames <-> normalized 0..1), the
// knob-deck group descriptors + control-id<->value binding, the envelope pack/unpack
// (the trigger-seam converter), the curve-popup target resolution, and applyZoneControl.
// Value logic only — no painting, no window plumbing.
#include "shell/instrument/reasampler_editor.h"
@@ -13,8 +12,8 @@
#include <string>
#include <vector>
#include "core/instrument/engine/master_gain.h" // r11 master-gain dB<->linear<->knob taper (FB1)
#include "core/instrument/map/trigger_seam.h" // triggerPlayLength / fade fraction converters (S-VIEW-3)
#include "core/instrument/engine/master_gain.h" // master-gain dB<->linear<->knob taper
#include "core/instrument/map/trigger_seam.h" // triggerPlayLength / fade fraction converters
#include "core/util/clamp01.h"
#include "shell/instrument/editor_internal.h" // DeckGroup ids
#include "shell/instrument/reasampler_processor.h"
@@ -22,35 +21,32 @@
namespace reasampler::vst {
using namespace reasampler::instrument::map; // ZonePlaySeconds vocabulary + trigger_seam converters
using instrument::ui::EnvMode; // envelope_overlay's mode enum (Q-W6: shim retired)
using instrument::ui::EnvMode; // envelope_overlay's mode enum
using instrument::engine::formatMasterGainLabel;
using instrument::engine::masterGainLinearFromNorm;
using instrument::engine::masterGainNormFromLinear;
using util::clamp01;
namespace {
// The S12/S15/S16 control-surface value DOMAINS (the shell owns these — param_slider is
// engine-free and maps only 0..1). WALL-CLOCK time sliders (AHDSR A/H/D/R, pitch env A/D) span
// [0, kEnvTimeMaxSeconds] SECONDS — rate-free, exactly what the zone stores; the keymap build
// resolves seconds->frames at the live rate. SOURCE-timeline fade sliders (Trigger fade-in/out)
// STORE source frames (PLAN.md §S15 — never a wall-clock second; the storage domain is
// settled-correct and unchanged), but the knob's FULL-SCALE THROW is a wall-clock intent —
// kFadeMaxSeconds resolved against the live rate at use (fadeMaxFrames(), Q-W0 T3-03; the
// prior 88200-frame constant baked 2 s x 44.1 kHz into src/, against the no-hardcoded-rate
// ruling). Build-time residual — one place to retune; not persisted.
// Control-surface value domains (the shell owns these — param_slider is engine-free and maps
// only 0..1). Wall-clock time sliders (AHDSR A/H/D/R, pitch env A/D) span [0, kEnvTimeMaxSeconds]
// seconds — rate-free, exactly what the zone stores; the keymap build resolves seconds->frames
// at the live rate. Source-timeline fade sliders (Trigger fade-in/out) store source frames
// (never a wall-clock second), but the knob's full-scale throw is a wall-clock intent —
// kFadeMaxSeconds resolved against the live rate at use (fadeMaxFrames()) rather than a baked-in
// rate constant, per the no-hardcoded-rate ruling.
constexpr double kEnvTimeMaxSeconds = 2.0; // AHDSR A/H/D/R + pitch A/D throw ceiling (seconds)
constexpr double kFadeMaxSeconds = 2.0; // Trigger fade throw ceiling (wall-clock)
constexpr double kPitchDepthMaxSemis = 24.0; // AD pitch depth throw: +/-24 st, centered
constexpr double kKeyTrackMax = 2.0; // S-VIEW-6 key-track slider ceiling (0..200%)
constexpr double kKeyTrackMax = 2.0; // key-track slider ceiling (0..200%)
} // namespace
double ReaSamplerEditor::controlValue(int id, const ZonePlaySeconds& play) const {
// Wall-clock seconds -> normalized over the seconds ceiling; source frames -> normalized over
// the rate-resolved frames ceiling (T3-03). Two domains, kept explicit so neither leaks a rate.
// A stored fade exceeding fadeMaxFrames() at the current host rate reads as norm 1.0 (clamp01
// pins it) and gets rewritten down on the next knob touch — deliberate, matching the old
// fixed-ceiling clamp behavior in kind, just rate-dependent now instead of fixed at 88200.
// the rate-resolved frames ceiling. Two domains, kept explicit so neither leaks a rate. A
// stored fade exceeding fadeMaxFrames() at the current host rate reads as norm 1.0 (clamp01
// pins it) and gets rewritten down on the next knob touch.
const double fadeMax = fadeMaxFrames();
const auto secToNorm = [](double s) { return clamp01(s / kEnvTimeMaxSeconds); };
const auto framesToNorm = [fadeMax](std::int64_t f) {
@@ -80,7 +76,7 @@ double ReaSamplerEditor::controlValue(int id, const ZonePlaySeconds& play) const
void ReaSamplerEditor::applyControl(int id, ZonePlaySeconds& play, double value,
int segment) const {
const double fadeMax = fadeMaxFrames(); // T3-03: rate-resolved knob full-scale
const double fadeMax = fadeMaxFrames(); // rate-resolved knob full-scale
const auto normToSec = [](double v) { return clamp01(v) * kEnvTimeMaxSeconds; };
const auto normToFrames = [fadeMax](double v) -> std::int64_t {
// Ceiling unavailable (rate not yet known): inert until fadeMaxFrames() resolves.
@@ -122,14 +118,12 @@ double ReaSamplerEditor::liveSampleRate() const {
}
double ReaSamplerEditor::fadeMaxFrames() const {
// T3-03: the Trigger-fade knob's full-scale throw is kFadeMaxSeconds (2 s wall-clock)
// resolved against the live rate — the SAME time base the envelope overlay already uses
// to place these source-frame fades on screen (totalSeconds = frames / liveSampleRate()),
// and the rate captures are made at (the capture path renders at the project rate).
// Pre-setupProcessing the rate is still 0: rather than substitute a literal rate (the
// exact residue T3-03 removed), bail the same way paintEnvelopeOverlay does (~line 1396) —
// callers treat a <= 0 return as "ceiling unavailable yet" and degrade the knob to inert
// rather than guess a rate. Storage stays SOURCE FRAMES — this resolves the UI ceiling only.
// The Trigger-fade knob's full-scale throw is kFadeMaxSeconds (2 s wall-clock) resolved
// against the live rate — the same time base the envelope overlay already uses to place
// these source-frame fades on screen. Pre-setupProcessing the rate is still 0: rather than
// substitute a literal rate, callers treat a <= 0 return as "ceiling unavailable yet" and
// degrade the knob to inert rather than guess a rate. Storage stays source frames — this
// resolves the UI ceiling only.
const double rate = liveSampleRate();
if (rate <= 0.0) return 0.0;
return kFadeMaxSeconds * rate;
@@ -141,11 +135,11 @@ double ReaSamplerEditor::previewVelocity01() const {
}
std::vector<DeckGroupDesc> ReaSamplerEditor::zoneDeckGroupDescs(const ZonePlaySeconds& play) const {
// The PER-ZONE groups — the deck grammar both surfaces share (FB2: the Zone panel renders
// exactly these; the Sample face appends the per-instance groups in deckGroupDescs).
// Group widths are MODE-INDEPENDENT: AMP ENVELOPE reserves its 5-cell Gate width (Trigger
// leaves two blank cells), so a Gate<->Trigger flip repopulates in place and never reflows
// the neighbouring groups (r11).
// The per-zone groups — the deck grammar both surfaces share (the Zone panel renders
// exactly these; the Sample face appends the per-instance groups in deckGroupDescs). Group
// widths are mode-independent: AMP ENVELOPE reserves its 5-cell Gate width (Trigger leaves
// two blank cells), so a Gate<->Trigger flip repopulates in place and never reflows the
// neighbouring groups.
std::vector<DeckGroupDesc> out;
{
DeckGroupDesc amp;
@@ -159,8 +153,8 @@ std::vector<DeckGroupDesc> ReaSamplerEditor::zoneDeckGroupDescs(const ZonePlaySe
static_cast<int>(ParamControl::kSustain),
static_cast<int>(ParamControl::kRelease)};
} else {
// Trigger, TIME-ORDERED left-to-right (r11: Fade In · Length % · Fade Out —
// matches the drawn envelope), plus the two reserved blanks.
// Trigger, time-ordered left-to-right (Fade In / Length % / Fade Out — matches
// the drawn envelope), plus the two reserved blanks.
amp.cellIds = {static_cast<int>(ParamControl::kTrigFadeIn),
static_cast<int>(ParamControl::kTrigLength),
static_cast<int>(ParamControl::kTrigFadeOut), -1, -1};
@@ -190,9 +184,8 @@ std::vector<DeckGroupDesc> ReaSamplerEditor::zoneDeckGroupDescs(const ZonePlaySe
std::vector<DeckGroupDesc> ReaSamplerEditor::deckGroupDescs(const ZonePlaySeconds& play) const {
// The full Sample-face deck: the shared per-zone groups + the per-instance VOICE + MASTER
// groups. VOICE + MASTER are the FB1 homes for the provisional voice-deck controls and the
// post-mixer gain — the r11 spec predates both; per-instance state (ComponentState) stays
// OFF the Zone panel (FB2), so they are appended here, not in zoneDeckGroupDescs.
// groups. Per-instance state (ComponentState) stays off the Zone panel, so they are
// appended here, not in zoneDeckGroupDescs.
std::vector<DeckGroupDesc> out = zoneDeckGroupDescs(play);
{
DeckGroupDesc voice;
@@ -303,8 +296,8 @@ std::string ReaSamplerEditor::deckValueLabel(int id, const PerformanceZone& zone
EnvClampBounds ReaSamplerEditor::envClampBounds() const {
// Match the control-panel sliders' own domains so a node drag can never produce a param a
// slider couldn't (the S-VIEW-F2 invariant). AHDSR seconds cap at kEnvTimeMaxSeconds; the
// Trigger fade/length fractions cap at 1.0 (the natural full-span bound the sliders use).
// slider couldn't. AHDSR seconds cap at kEnvTimeMaxSeconds; the Trigger fade/length
// fractions cap at 1.0 (the natural full-span bound the sliders use).
EnvClampBounds b;
b.maxAttackSeconds = kEnvTimeMaxSeconds;
b.maxHoldSeconds = kEnvTimeMaxSeconds;
@@ -326,8 +319,8 @@ AmpEnvelope ReaSamplerEditor::packEnvelope(const ZonePlaySeconds& play, std::int
env.decaySeconds = play.adsr.decaySeconds;
env.sustainLevel = play.adsr.sustainLevel;
env.releaseSeconds = play.adsr.releaseSeconds;
// Trigger: lengthFraction copies 1-to-1; the fades are DERIVED — source frames over the played
// span (the TRIGGER SEAM converter, PACK direction). startFrame is the zone's effective start
// Trigger: lengthFraction copies 1-to-1; the fades are derived — source frames over the played
// span (the trigger-seam converter, pack direction). startFrame is the zone's effective start
// point so the fraction denominator matches the voice's actual post-start span. A zero play
// length yields 0 fractions.
env.lengthFraction = play.trigger.lengthFraction;
@@ -348,10 +341,10 @@ void ReaSamplerEditor::unpackEnvelope(const AmpEnvelope& env, std::int64_t frame
play.adsr.releaseSeconds = env.releaseSeconds;
} else {
// Trigger: lengthFraction copies back; the fades convert fractions -> source frames over
// the played span (the TRIGGER SEAM converter, UNPACK direction). startFrame is the zone's
// effective start point so the frame denominator matches the voice's actual post-start span.
// Keep the same (0,1] floor on lengthFraction the slider path enforces so a zero-length
// trigger never plays nothing.
// the played span (the trigger-seam converter, unpack direction). startFrame is the
// zone's effective start point so the frame denominator matches the voice's actual
// post-start span. Keep the same (0,1] floor on lengthFraction the slider path enforces
// so a zero-length trigger never plays nothing.
play.trigger.lengthFraction = (std::max)(0.01, env.lengthFraction);
const std::int64_t playLen =
triggerPlayLength(play.trigger.lengthFraction, frames, startFrame);
@@ -361,8 +354,8 @@ void ReaSamplerEditor::unpackEnvelope(const AmpEnvelope& env, std::int64_t frame
}
PerformanceZone ReaSamplerEditor::popupZone() const {
// The zone the popup displays: the Zone surface's SELECTED zone (FB2), else the Sample
// face's one-zone site (a read-only resolve — an edit materializes via popupZoneIndex).
// The zone the popup displays: the Zone surface's selected zone, else the Sample face's
// one-zone site (a read-only resolve — an edit materializes via popupZoneIndex).
if (view_ == View::kZone && selectedZone_ >= 0 &&
selectedZone_ < static_cast<int>(map_.zones.size())) {
return map_.zones[static_cast<std::size_t>(selectedZone_)];