Report the instrument's automatable parameters to the host under a frozen id table, in signal-flow order, with real units
42 of 44 ids issued: pitch key-track and Trigger length stay reserved pending a live path. Master gain reclassified Live — it never reloaded.
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#include "core/instrument/engine/live_params.h" // LiveParams (the live-parameter block)
|
||||
#include "core/instrument/engine/meter_accumulate.h" // the meter's block-rate folds + consume
|
||||
#include "core/instrument/engine/voice_engine.h"
|
||||
#include "core/instrument/param/param_id.h" // the frozen ParamId space + DeckParam binding
|
||||
|
||||
namespace reasampler::vst {
|
||||
|
||||
@@ -124,6 +125,31 @@ public:
|
||||
// Hands the host our LICE IPlugView editor.
|
||||
Steinberg::IPlugView* PLUGIN_API createView(Steinberg::FIDString name) override;
|
||||
|
||||
// A host write of one exposed parameter. Applies it to THE model through that control's
|
||||
// existing commit tier — live publish, or the master-gain atomic — and never through a
|
||||
// fourth route. Nothing reachable from here touches reloadInstrument or rebuildVoiceEngine,
|
||||
// which is structural rather than careful: every reload- and rebuild-tier control is omitted
|
||||
// from the parameter list, so no id maps to one.
|
||||
//
|
||||
// Parameter values reach the audio thread through the SAME block the editor's knobs publish
|
||||
// into, which the engine observes ONCE per render() — i.e. at BLOCK BOUNDARIES, last write
|
||||
// wins for that block. Sample-accurate application would put a per-sample "did anything
|
||||
// change" question on the per-voice-per-sample path, which the phase-wide guardrail forbids.
|
||||
// process() reads no parameter queue and is unchanged by the parameter surface.
|
||||
Steinberg::tresult PLUGIN_API setParamNormalized(
|
||||
Steinberg::Vst::ParamID tag, Steinberg::Vst::ParamValue value) override;
|
||||
|
||||
// Pushes every exposed parameter's normalized value from the model into the controller
|
||||
// WITHOUT notifying the host — the load direction, which the SDK forbids reflecting back
|
||||
// through IComponentHandler. UI/main thread.
|
||||
void syncParamsFromModel();
|
||||
|
||||
// A knob drag's host-edit bracket, so a host in touch or latch mode records ONE continuous
|
||||
// edit rather than a burst of one-point gestures. Idempotent: a grab while one is open
|
||||
// closes it first, and endParamGesture with none open does nothing. UI thread only.
|
||||
void beginParamGesture(instrument::ui::DeckParam deck);
|
||||
void endParamGesture();
|
||||
|
||||
// Additionally exposes REAPER's IReaperUIEmbedInterface (queried by REAPER to drive the
|
||||
// inline TCP/MCP embed); all other iids delegate to SingleComponentEffect unchanged.
|
||||
Steinberg::tresult PLUGIN_API queryInterface(const Steinberg::TUID iid,
|
||||
@@ -276,6 +302,23 @@ public:
|
||||
std::string usageInstanceGuid();
|
||||
|
||||
private:
|
||||
// Builds the unit and parameter lists from the derived exposed set. Called once, from
|
||||
// initialize().
|
||||
void buildParameterList();
|
||||
|
||||
// The normalized value a control reads at, from the model — the projection §6.1 calls a
|
||||
// third surface. Master gain reads the processor's own atomic; everything else reads the
|
||||
// parameter set through the deck's binding.
|
||||
double modelParamNormalized(const InstrumentParams& params,
|
||||
instrument::ui::DeckParam deck) const;
|
||||
|
||||
// Notifies the host of every exposed control whose value differs between the two parameter
|
||||
// sets. Called from setInstrumentParams — the ONE funnel every writer already goes through —
|
||||
// so no internal write can leave the host displaying, and on next touch re-imposing, a
|
||||
// superseded value. The bake's reset is the first non-gesture writer this covers.
|
||||
void notifyParamsFromModel(const InstrumentParams& before, const InstrumentParams& after);
|
||||
void notifyParamChanged(instrument::param::ParamId id, double normalized);
|
||||
|
||||
// If process() published that the drain instrument is fully idle, move it into the
|
||||
// graveyard and prune — so an edited-away snapshot stops costing memory as soon as its
|
||||
// tails die. Off the audio thread only (driven by pollBankSync); safe against a racing
|
||||
@@ -333,6 +376,12 @@ private:
|
||||
|
||||
ReaperBridge bridge_;
|
||||
|
||||
// The parameter whose drag bracket is currently open, 0 for none. UI thread only.
|
||||
instrument::param::ParamId openGestureId_ = 0;
|
||||
// Set across setState so a LOAD is not reflected back to the host as an edit. Main thread
|
||||
// only, and non-atomic on purpose: the SDK calls setState there and nowhere else.
|
||||
bool paramNotifySuppressed_ = false;
|
||||
|
||||
// The ONE live-parameter block for this instance, declared ahead of the instrument slots
|
||||
// so it outlives every snapshot that points at it (members destruct in reverse order).
|
||||
// Both live_ and draining_ observe this same block — a block owned by a snapshot would
|
||||
|
||||
Reference in New Issue
Block a user