instrument: fix AHD node-tracking/tie-break/live-latch defects and close staged-envelope-curve test gaps
This commit is contained in:
@@ -85,7 +85,7 @@ if(WIN32 AND EXISTS "${VST3_SDK}/public.sdk/source/main/pluginfactory.cpp")
|
||||
capture_browser keyboard_strip sample_bands sample_chrome
|
||||
waveform_view bank_sync browser_scroll param_slider tooltip
|
||||
theme component_geometry bank_grid trigger_seam envelope_overlay envelope_edit
|
||||
knob_deck deck_groups curve_popup master_gain sample_usage file_bytes)
|
||||
knob_deck deck_groups curve_popup master_gain sample_usage file_bytes curve_law)
|
||||
# SDK_INC gives the REAPER VST3 interfaces + API header for the bridge; WDL_INC gives
|
||||
# LICE for the editor. The VST3 SDK headers arrive via vst3_sdk PUBLIC.
|
||||
target_include_directories(reasampler_vst PRIVATE ${REASAMPLER_SRC_DIR} ${SDK_INC} ${WDL_INC})
|
||||
|
||||
@@ -54,6 +54,29 @@ namespace {
|
||||
constexpr double kEnvTimeMaxSeconds = instrument::ui::kGateStageMaxSeconds;
|
||||
constexpr double kPitchDepthMaxSemis = 24.0; // pitch depth throw: +/-24 st, centered
|
||||
constexpr double kKeyTrackMax = 2.0; // key-track slider ceiling (0..200%)
|
||||
|
||||
// The raw stored curve exponent for a curve-dial control id, read DIRECTLY off the field —
|
||||
// never round-tripped through curveFromKnobNorm(knobNormFromCurve(x)): the knob-norm law's
|
||||
// centre detent (curve_law.h) snaps anything near-neutral back to exactly 1.0, so a round trip
|
||||
// can misreport a stored exponent that isn't neutral as "^1.00".
|
||||
double curveExponentFor(int id, const PlaySeconds& play) {
|
||||
using DeckParam = instrument::ui::DeckParam; // ReaSamplerEditor::ParamControl is an alias
|
||||
switch (static_cast<DeckParam>(id)) {
|
||||
case DeckParam::kAttackCurve: return play.adsr.attackCurve;
|
||||
case DeckParam::kDecayCurve: return play.adsr.decayCurve;
|
||||
case DeckParam::kReleaseCurve: return play.adsr.releaseCurve;
|
||||
case DeckParam::kTrigAttackCurve: return play.trigAhd.attackCurve;
|
||||
case DeckParam::kTrigDecayCurve: return play.trigAhd.decayCurve;
|
||||
case DeckParam::kPitchEnvAttackCurve: return play.pitchEnv.shape.attackCurve;
|
||||
case DeckParam::kPitchEnvDecayCurve: return play.pitchEnv.shape.decayCurve;
|
||||
case DeckParam::kFilterEnvAttackCurve: return play.filter.env.attackCurve;
|
||||
case DeckParam::kFilterEnvDecayCurve: return play.filter.env.decayCurve;
|
||||
case DeckParam::kFilterEnvReleaseCurve: return play.filter.env.releaseCurve;
|
||||
case DeckParam::kFilterTrigAttackCurve: return play.filter.trigEnv.attackCurve;
|
||||
case DeckParam::kFilterTrigDecayCurve: return play.filter.trigEnv.decayCurve;
|
||||
default: return util::kCurveNeutral;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ReaSamplerEditor::FaceLayout ReaSamplerEditor::faceLayout(int w, int h) const {
|
||||
@@ -373,7 +396,7 @@ std::string ReaSamplerEditor::deckValueLabel(int id) const {
|
||||
case ParamControl::kFilterEnvReleaseCurve:
|
||||
case ParamControl::kFilterTrigAttackCurve:
|
||||
case ParamControl::kFilterTrigDecayCurve:
|
||||
snprintf(buf, sizeof(buf), "^%.2f", util::curveFromKnobNorm(controlValue(id, play)));
|
||||
snprintf(buf, sizeof(buf), "^%.2f", curveExponentFor(id, play));
|
||||
break;
|
||||
default:
|
||||
// -2 (preview velocity) is labeled at its chrome call site; nothing else here.
|
||||
@@ -461,10 +484,11 @@ StageEnvelope ReaSamplerEditor::packEnvelope(OverlayEnv which, const PlaySeconds
|
||||
else packAhdsr(play.filter.env, env);
|
||||
break;
|
||||
case OverlayEnv::kAmp:
|
||||
case OverlayEnv::kNone:
|
||||
if (trigger) packAhd(play.trigAhd, t0, playSpan, env);
|
||||
else packAhdsr(play.adsr, env);
|
||||
break;
|
||||
case OverlayEnv::kNone:
|
||||
break; // nothing is overlay-active; a default-constructed StageEnvelope, not amp
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ bool ReaSamplerEditor::mouseDownChrome(const FaceLayout& fl, int x, int y) {
|
||||
if (contains(cr.velCell, x, y)) {
|
||||
drag_ = DragKind::kDeckKnob;
|
||||
dragParamId_ = -2; // sentinel: the preview velocity knob (a processor param)
|
||||
dragInnerCellId_ = -1; // peer of mouseDownDeck's own grab-time init, for symmetry
|
||||
dragKnobStartValue_ = previewVelocity01();
|
||||
dragStartX_ = x;
|
||||
dragStartY_ = y;
|
||||
|
||||
@@ -158,8 +158,8 @@ inline void drawKnobFace(LICE_IBitmap* bmp, const instrument::ui::Rect& knobRect
|
||||
|
||||
// The concentric INNER dial: a second value on the same cell, drawn in the categorical
|
||||
// tertiary accent so it reads as a different KIND of control rather than a louder one — the
|
||||
// same purple the overlay traces the envelope in, which is what ties a segment's knot to its
|
||||
// dial by eye. Shares the outer knob's value<->angle map (param_slider's), so both needles
|
||||
// same purple the overlay traces the envelope in (curve_law.h owns the knot/dial pairing this
|
||||
// ties into). Shares the outer knob's value<->angle map (param_slider's), so both needles
|
||||
// point the same way for the same normalized value.
|
||||
inline void drawInnerDial(LICE_IBitmap* bmp, const instrument::ui::Rect& innerRect,
|
||||
double value01, ui::InteractionState st) {
|
||||
|
||||
@@ -111,7 +111,11 @@ void ReaSamplerEditor::paintDeck(LICE_IBitmap* bmp, const FaceLayout& fl) {
|
||||
// The overlay-select radio: filled in the tertiary accent (the colour the overlay
|
||||
// traces in) when this group's envelope is the one on the waveform, hollow otherwise.
|
||||
if (g.captionRadio.id >= 0) {
|
||||
const bool on = (overlayEnv_ == overlayEnvForRadio(g.captionRadio.id));
|
||||
// overlayEnvForRadio returns kNone for BOTH "not a radio id" and "no selection" —
|
||||
// a non-radio id must never read as lit just because nothing is selected, so the
|
||||
// picked env has to be checked against kNone itself, not just matched by equality.
|
||||
const OverlayEnv picked = overlayEnvForRadio(g.captionRadio.id);
|
||||
const bool on = picked != OverlayEnv::kNone && overlayEnv_ == picked;
|
||||
const bool hov = isHovered(HoverKind::kEnvRadio, g.captionRadio.id);
|
||||
const Rect& rb = g.captionRadio.box;
|
||||
LICE_DrawRect(bmp, rb.x, rb.y, rb.width - 1, rb.height - 1,
|
||||
|
||||
Reference in New Issue
Block a user