Add tail manual fine-adjust (scroll) + per-project tail persistence

Relocate TailSetting into ReaSamplerSession; persist serializes it to
a new forever-stable "tail_setting" ext-state key (load-per-project,
save-on-save). Footer scroll-wheel adjusts Manual length in 250ms
steps; label now shows "Tail: Manual X.Xs". Pure step/label/JSON
round-trip covered by tests.
This commit is contained in:
2026-07-23 19:12:12 -04:00
parent 938c85a223
commit 37affc6a70
6 changed files with 365 additions and 38 deletions
+26 -5
View File
@@ -9,6 +9,7 @@
// only (plus render_settings for the pure TailMode enum). Builds and unit-tests
// without REAPER.
#include <optional>
#include <string>
#include "render_settings.h" // TailMode (pure enum) — the three-state tail contract
@@ -16,10 +17,15 @@
namespace reasampler {
// The Manual-mode starting length. 2 s is a musically useful default tail (a bar of
// reverb throw at a moderate tempo) that is well under the 8 s cap. A fine-adjust UI
// (+/- click zones or scroll) is a noted follow-on; this pass ships a fixed default.
// reverb throw at a moderate tempo) that is well under the 8 s cap. Also the value a
// project with no stored tail setting (older / never-adjusted) falls back to on load.
inline constexpr double kDefaultManualTailMs = 2000.0;
// The fine-adjust step per scroll-wheel notch in Manual mode. 250 ms is coarse enough
// that a few notches cover the useful range, fine enough to dial a length precisely.
// Daniel-set. The panel maps one wheel notch to +/- this many ms via adjustManualMs.
inline constexpr double kManualStepMs = 250.0;
// The panel's current tail setting: the mode plus the length used ONLY when the
// mode is Manual. Held as in-memory panel/session state (bank_panel.cpp), default
// None so a capture with no explicit choice stays exact-bounds / byte-identical to
@@ -41,9 +47,24 @@ TailMode cycleTailMode(TailMode current);
// tailMs into the CaptureRequest. Meaningful only for TailMode::Manual.
double clampManualMs(double manualMs);
// The toggle's label for a setting, e.g. "Tail: Off", "Tail: Auto", "Tail: Manual".
// (Manual omits the length here — the panel is unobtrusive; a length readout can be
// added with the fine-adjust follow-on.) Pure so the exact strings are test-pinned.
// Applies `notches` scroll-wheel steps of `stepMs` each to `current`, clamped to
// [0, kMaxTailMs]. Positive notches lengthen, negative shorten. Pure so the fine-adjust
// arithmetic (and its clamp at both bounds) is unit-tested; the panel wheel handler
// owns no arithmetic of its own. Meaningful only for TailMode::Manual.
double adjustManualMs(double current, int notches, double stepMs);
// The toggle's label for a setting, e.g. "Tail: Off", "Tail: Auto". In Manual mode the
// clamped length is appended in seconds to one decimal, e.g. "Tail: Manual 2.0s" —
// Off/Auto carry no length. Pure so the exact strings (and the Manual format) are
// test-pinned, including the boundary lengths (0.0s, 8.0s).
std::string tailToggleLabel(const TailSetting& setting);
// JSON round-trip of a TailSetting (mode + manualMs), for persist to store the tail
// setting per-project alongside the bank and view model. Kept pure/testable here —
// the natural home, mirroring bank_model's serialize/deserialize. serialize emits a
// compact object; deserialize returns std::nullopt on malformed input so the caller
// (persist) falls back to a default setting, exactly as an absent key does.
std::string serializeTailSetting(const TailSetting& setting);
std::optional<TailSetting> deserializeTailSetting(const std::string& json);
} // namespace reasampler