One taper, one modifier law: extract param_taper, raise the stage ceiling to 10 s, and make the AHDSR schematic axis the taper itself

This commit is contained in:
2026-08-01 19:09:19 -04:00
parent e589addc54
commit 3eb72d01c4
23 changed files with 1208 additions and 193 deletions
+22 -10
View File
@@ -11,14 +11,15 @@
#include "core/instrument/map/play_seconds.h" // PlaySeconds (the deck's edit target)
#include "core/instrument/ui/deck_groups.h" // DeckParam
#include "core/instrument/ui/envelope_overlay.h" // kGateStageMaxSeconds
#include "core/instrument/ui/param_taper.h" // UnitCategory + the shared tapers
namespace reasampler::instrument::ui {
using map::PlaySeconds;
// Every stage-time knob spans [0, kEnvTimeMaxSeconds] seconds — rate-free, exactly what the
// parameter set stores. READ from the overlay's schematic scale rather than restated: the AHDSR
// schematic anchors a maxed knob at the canvas edge, which only holds while the two agree.
// parameter set stores. An ALIAS of the overlay's schematic domain, which is itself an alias of
// the taper's; param_taper.h owns why the number has one home.
inline constexpr double kEnvTimeMaxSeconds = kGateStageMaxSeconds;
// Pitch depth throw: +/-kVelocityPitchRangeSemitones, centred. The one throw the pitch
@@ -28,10 +29,11 @@ inline constexpr double kPitchDepthMaxSemis = kVelocityPitchRangeSemitones;
// Key-track knob ceiling (0..200%), shared by the pitch and filter key-track controls.
inline constexpr double kKeyTrackMax = 2.0;
// The normalized [0,1] a control shows: seconds over the ceiling, levels and fractions as-is,
// signed depths centred at 0.5, curve exponents over their logarithmic travel. Controls backed
// by per-instance state rather than the parameter set (voice count, master gain, the pitch
// key-track scalar, preview velocity) are not here — the shell reads those from the processor.
// The normalized [0,1] a control shows: stage times through the shared time taper, levels and
// fractions as-is, signed depths through the centre-expanded depth taper, curve exponents over
// their logarithmic travel. Controls backed by per-instance state rather than the parameter set
// (voice count, master gain, the pitch key-track scalar, preview velocity) are not here — the
// shell reads those from the processor.
double deckParamNorm(DeckParam id, const PlaySeconds& play);
// Applies a committed interaction: a knob's normalized `value`, or a toggle's `segment` (0/1).
@@ -39,13 +41,23 @@ double deckParamNorm(DeckParam id, const PlaySeconds& play);
void setDeckParam(DeckParam id, PlaySeconds& play, double value, int segment);
// Resets `id` to its default. The default IS what a fresh PlaySeconds carries, so there is no
// second table of defaults to drift from the real one. It arrives via the norm round trip, so
// landing EXACTLY on a stage time (0.003 s attack, 0.060 s release) depends on
// kEnvTimeMaxSeconds being a power of two — x/2^n*2^n is lossless, an arbitrary ceiling is not.
// Move that ceiling off a power of two and a reset lands a mantissa bit off its own default.
// second table of defaults to drift from the real one, and the value is COPIED rather than
// round-tripped through norm -> value. That bypass is MANDATORY: a reset must land on the stored
// default bit for bit, and no round trip through a log taper over a non-power-of-two ceiling can
// promise that for every control. Never "simplify" it back into a round trip.
// For knob-valued controls — a toggle has no reset gesture.
void resetDeckParam(DeckParam id, PlaySeconds& play);
// THE snap-unit table: which whole unit Shift snaps each control to. Includes the deck's
// processor-side ids (voice count, master gain), which have no entry in the two functions above
// because their VALUE lives outside the parameter set — the unit does not.
UnitCategory deckParamUnit(DeckParam id);
// Applies that snap to a control's normalized value. Snapping happens in the DISPLAYED unit, so
// this is where each control's full scale enters: 0..100 %, 0..200 % and +/-100 % all snap to a
// whole displayed percent and therefore take different norm steps.
double snapDeckParamNorm(DeckParam id, double norm);
// A time constant as MILLISECONDS, e.g. "12 ms". Never switches to seconds: the editor reads in
// one unit so two stage times are comparable at a glance. Sub-10 ms keeps one decimal so a short
// attack is not rounded to a bare "0 ms". Writes at most `len` bytes including the terminator.