Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::state::StateStore Class Reference

Centralized parameter storage with lock-free value access. More...

#include <store.hpp>

Classes

struct  ParamWrite
 One parameter write in a set_values_rt() batch. More...
struct  ModulationWatchers
class  ModulationWatch
 RAII handle for watch_modulation(). Move-only; dropping it unwatches. More...

Public Member Functions

 StateStore ()
 ~StateStore ()
 StateStore (const StateStore &)=delete
StateStore & operator= (const StateStore &)=delete
void add_parameter (const ParamInfo &info)
 Register a parameter.
void add_group (const ParamGroup &group)
 Register a parameter group. Call during initialization only.
float get_value (ParamID id) const
 Read a parameter's base value (lock-free).
ParamReader param_reader (ParamID id) const
 Resolve a read handle for a parameter's base value.
float get_modulated (ParamID id) const
 Read a parameter's modulated value: base + mod_offset (lock-free).
BaseOffsetValue get_base_offset (ParamID id) const
 Read the canonical base-vs-offset pair without collapsing its fields.
void set_value (ParamID id, float value)
 Write a parameter's base value (lock-free).
void set_value_rt (ParamID id, float value)
 Real-time-safe parameter write for use from the audio thread.
void set_values_rt (std::span< const ParamWrite > writes)
 set_value_rt() for several parameters as one store write: one writer claim for the batch and one listener-snapshot lease for its notifications.
void set_normalized_rt (ParamID id, float normalized)
 Real-time-safe normalized-value write.
std::optional< ParameterFeedbackBaseline > capture_feedback_baseline (ParamID id) const noexcept
 Capture an exact per-parameter identity at the caller's ordering point.
ConditionalParameterApplyResult set_value_rt_if_baseline (const ParameterFeedbackBaseline &baseline, float value)
 Publish asynchronous feedback only if the captured identity is still current.
void set_mod_offset (ParamID id, float offset)
 Set the absolute modulation offset for a parameter.
void add_mod_offset (ParamID id, float delta)
 Add a delta to a parameter's modulation offset.
void reset_all_mod ()
 Clear all modulation offsets to zero.
void set_display_modulation (ParamID id, float plain_value) noexcept
 Publish the value (plain units) a plugin's own modulator plays for id.
void clear_display_modulation (ParamID id) noexcept
 Stop showing a plugin-published modulated value for id.
std::optional< float > displayed_modulation (ParamID id) const noexcept
 The modulated value a control should show, normalized to the parameter's range, or nullopt when nothing modulates id.
ModulationWatch watch_modulation (ParamID id, std::function< void(std::optional< float >)> on_change)
 Call on_change on the main thread, from pump_listeners(), whenever displayed_modulation(id) changes (nullopt when it stops).
float get_normalized (ParamID id) const
 Read a parameter's value mapped to [0, 1] (lock-free).
void set_normalized (ParamID id, float normalized)
 Write a parameter from a normalized [0, 1] value (lock-free).
std::uint64_t state_generation () const noexcept
 Current mutation generation for every parameter-state writer.
bool state_snapshot_is_current (std::uint64_t generation) const noexcept
 True when no writer is in flight and none has advanced the generation past generation.
ParameterGestureApplyResult apply_normalized_gesture_if_generation (std::uint64_t expected_generation, ParamID id, float normalized)
 Atomically claim expected_generation and apply one complete host gesture if it is still current.
float get_default (ParamID id) const
 Get the default value for a parameter (from its ParamRange).
void reset_to_default (ParamID id)
 Reset a single parameter to its default value.
void reset_all_to_defaults ()
 Reset all parameters to their default values.
bool reset_triggers_rt ()
 Reset every trigger / momentary parameter to its range default.
bool has_trigger_params () const
 True when at least one registered parameter is a trigger / momentary control.
const ParamInfo * info (ParamID id) const
 Look up immutable metadata for a parameter.
bool set_parameter_display_name (ParamID id, std::string name)
 Override only the host-facing presentation name of a stable parameter.
std::string parameter_display_name (ParamID id) const
 Current host-facing name: overlay when present, otherwise ParamInfo::name.
std::uint64_t parameter_display_revision () const noexcept
 Monotonic edge for format adapters that republish ParameterInfo.
template<std::size_t N>
std::array< float, N > snapshot (const std::array< ParamID, N > &ids) const noexcept
 Block-local snapshot of N parameter values.
template<std::size_t N>
std::array< float, N > snapshot_modulated (const std::array< ParamID, N > &ids) const noexcept
 Modulated variant of snapshot — returns each parameter's base + per-buffer modulation offset (see set_mod_offset).
std::span< const ParamInfo > all_params () const
 View of all registered parameters (in registration order).
std::span< const ParamGroup > all_groups () const
 View of all registered groups (in registration order).
std::size_t param_count () const
 Number of registered parameters.
void begin_gesture (ParamID id)
 Signal the host that a gesture (drag, click) has begun on a parameter.
void end_gesture (ParamID id)
 Signal the host that the current gesture has ended.
void acquire_gesture (ParamID id)
 Acquire/release a shared gesture lease.
void release_gesture (ParamID id)
void defer_gesture_release (ParamID id)
 Release a lease without synchronously entering host code.
void flush_deferred_gesture_releases () noexcept
void release_open_gestures ()
 Close every gesture still open and report each end to the host.
std::size_t open_gesture_count () const noexcept
 Number of parameters with an open gesture (begin without a matching end).
void run_gesture_on_main (std::function< void()> gesture)
 Run a complete parameter gesture (begin_gesture → value writes → end_gesture) on the host's main thread, from ANY thread.
std::uint64_t gesture_thread_violation_count () const
 Number of times a gesture entry point (begin_gesture / end_gesture) was called off the host main thread while a main-thread backend was registered.
void set_main_loop (pulp::events::EventLoop *loop)
 Install an EventLoop used to marshal ListenerThread::Main listeners onto the main thread.
ListenerToken add_listener (ParamChangeCallback callback, ListenerThread thread)
 Subscribe to parameter-value changes.
ListenerToken add_listener (ParamChangeCallback callback, ListenerThread thread, ListenerRestoreBehavior restore_behavior)
 Subscribe with explicit state-restore behavior.
ListenerToken add_audio_listener (ParamChangeCallback callback)
 Convenience for opting into real-time-safe inline invocation.
void remove_listener (ListenerToken &token)
 Remove a listener explicitly.
std::size_t pump_listeners ()
 Drain queued main-thread listener invocations posted by set_value_rt() / set_normalized_rt() from the audio thread.
std::size_t reconcile_restore_listeners ()
 Reconcile opted-in Main listeners with the current parameter snapshot.
RtListenerQueueTelemetry rt_listener_queue_telemetry () const
 Latest telemetry for the RT-to-main listener queue used by set_value_rt() / pump_listeners().
void reset_rt_listener_queue_overflow_count ()
 Reset only the RT listener queue overflow counter.
void add_listener (ParamChangeCallback callback)
 Legacy permanent-listener registration.
std::vector< uint8_t > serialize () const
 Serialize all parameter values to a binary blob for preset/state save.
bool deserialize (std::span< const uint8_t > data)
 Restore parameter values from a parameter-only binary blob.
std::uint64_t state_restore_revision () const noexcept
 Monotonic reconciliation edge published after each successful deserialize().
void set_state_version (uint32_t version)
 Set the schema version embedded in serialized state.
uint32_t state_version () const
 Get the current state schema version.
bool register_state_migration (uint32_t from_version, uint32_t to_version, StateMigrationRegistry::MigrationFn migration)
 Register a load-time migration for this store's parameter schema.
void copy_state_migrations_from (const StateStore &source)
 Copy schema migrations from another store with the same registered parameters.
void set_gesture_callbacks (std::function< void(ParamID)> begin_fn, std::function< void(ParamID)> end_fn)
 Install callbacks that forward gesture begin/end to the plugin host.

Friends

struct test_support::StateWriterProbe
class ParamReader

Detailed Description

Centralized parameter storage with lock-free value access.

StateStore is the single source of truth for all plugin parameters. Register parameters at initialization via add_parameter(), then read/write values from any thread using the lock-free accessors.

store.add_parameter({.id = 1, .name = "Gain", .range = {-60, 12, 0}});
store.set_value(1, -3.0f);
float gain = store.get_value(1); // -3.0
Centralized parameter storage with lock-free value access.
Definition store.hpp:164
float get_value(ParamID id) const
Read a parameter's base value (lock-free).
Definition store.hpp:186
void add_parameter(const ParamInfo &info)
Register a parameter.
void set_value(ParamID id, float value)
Write a parameter's base value (lock-free).
Note
Parameter registration (add_parameter, add_group) is NOT thread-safe. Call these only during plugin initialization, before processing starts.
Value access (get_value, set_value, etc.) is lock-free and safe to call from the audio thread.

Constructor & Destructor Documentation

◆ StateStore() [1/2]

pulp::state::StateStore::StateStore ( )

◆ ~StateStore()

pulp::state::StateStore::~StateStore ( )

◆ StateStore() [2/2]

pulp::state::StateStore::StateStore ( const StateStore & )
delete

Member Function Documentation

◆ acquire_gesture()

void pulp::state::StateStore::acquire_gesture ( ParamID id)

Acquire/release a shared gesture lease.

Multiple live editors may bind controls to the same StateStore parameter; only the first lease emits begin_gesture() and only the last release emits end_gesture(). Main-thread only — see begin_gesture().

◆ add_audio_listener()

ListenerToken pulp::state::StateStore::add_audio_listener ( ParamChangeCallback callback)
nodiscard

Convenience for opting into real-time-safe inline invocation.

Equivalent to add_listener(cb, ListenerThread::Audio).

◆ add_group()

void pulp::state::StateStore::add_group ( const ParamGroup & group)

Register a parameter group. Call during initialization only.

◆ add_listener() [1/3]

void pulp::state::StateStore::add_listener ( ParamChangeCallback callback)

Legacy permanent-listener registration.

Prefer the ListenerToken-returning overload above for new code.

The callback is invoked inline on whichever thread fires set_value() and cannot be removed for the lifetime of the StateStore. Pulp's own subsystems are migrating to the token API; this overload remains for one release as a compatibility shim.

◆ add_listener() [2/3]

ListenerToken pulp::state::StateStore::add_listener ( ParamChangeCallback callback,
ListenerThread thread )
nodiscard

Subscribe to parameter-value changes.

The returned ListenerToken owns the subscription. Destroy it (or call ListenerToken::reset()) to remove the listener. The token MUST outlive the listener's expected firing window — discarding it removes the subscription immediately.

Parameters
callbackInvoked for every change. Pass an empty ParamChangeCallback to register a no-op slot.
threadListenerThread::Main (default) marshals the callback through the installed EventLoop; ListenerThread::Audio runs it inline on the firing thread and asserts caller RT-safety.
restore_behaviorListenerRestoreBehavior::Silent preserves deserialize's listener-silent contract. UI bindings whose cached presentation must follow restored state opt into ListenerRestoreBehavior::Reconcile.
Note
Main-thread listeners fed by the real-time path (set_value_rt / set_normalized_rt, drained by pump_listeners) are CURRENT-VALUE notifications: the float passed to the callback is a live snapshot read at drain time (not the value queued when the change fired), and deliveries are COALESCED to one call per changed parameter per pump. This keeps the value coherent under dense automation — a burst of N writes to one parameter yields a single callback carrying the latest value, never a sequence of stale intermediate values. ListenerThread::Audio listeners are unaffected: they fire inline per change with that change's value.

◆ add_listener() [3/3]

ListenerToken pulp::state::StateStore::add_listener ( ParamChangeCallback callback,
ListenerThread thread,
ListenerRestoreBehavior restore_behavior )
nodiscard

Subscribe with explicit state-restore behavior.

◆ add_mod_offset()

void pulp::state::StateStore::add_mod_offset ( ParamID id,
float delta )

Add a delta to a parameter's modulation offset.

◆ add_parameter()

void pulp::state::StateStore::add_parameter ( const ParamInfo & info)

Register a parameter.

Call during initialization only.

Parameters
infoImmutable metadata for this parameter.

◆ all_groups()

std::span< const ParamGroup > pulp::state::StateStore::all_groups ( ) const
inline

View of all registered groups (in registration order).

◆ all_params()

std::span< const ParamInfo > pulp::state::StateStore::all_params ( ) const
inline

View of all registered parameters (in registration order).

◆ apply_normalized_gesture_if_generation()

ParameterGestureApplyResult pulp::state::StateStore::apply_normalized_gesture_if_generation ( std::uint64_t expected_generation,
ParamID id,
float normalized )

Atomically claim expected_generation and apply one complete host gesture if it is still current.

A stale caller fails before begin_gesture. Callback failure restores the old value when no newer writer has replaced it. A concurrent writer is never overwritten during rollback; the caller must refresh when the result is not Applied.

◆ begin_gesture()

void pulp::state::StateStore::begin_gesture ( ParamID id)

Signal the host that a gesture (drag, click) has begun on a parameter.

Main-thread only. The registered gesture callbacks forward to the host's undo-grouping calls — VST3 beginEdit, AU AudioUnitEvent(kAudioUnitEvent_BeginParameterChangeGesture), CLAP CLAP_EVENT_PARAM_GESTURE_BEGIN — all of which are only legal on the host UI/main thread. Call this from the UI thread before a series of set_value() calls so the host groups them into a single undo step.

A background writer (e.g. a MIDI-learn engine setting a mapped parameter from a timer thread) must NOT call this directly; route the whole gesture through run_gesture_on_main(). When a main-thread backend is registered and this is called off it, the misuse is counted (see gesture_thread_violation_count) and, in debug builds, asserts.

◆ capture_feedback_baseline()

std::optional< ParameterFeedbackBaseline > pulp::state::StateStore::capture_feedback_baseline ( ParamID id) const
noexcept

Capture an exact per-parameter identity at the caller's ordering point.

This is a single lock-free load and performs no allocation.

◆ clear_display_modulation()

void pulp::state::StateStore::clear_display_modulation ( ParamID id)
noexcept

Stop showing a plugin-published modulated value for id.

◆ copy_state_migrations_from()

void pulp::state::StateStore::copy_state_migrations_from ( const StateStore & source)

Copy schema migrations from another store with the same registered parameters.

Used by restore probes that validate before touching live state.

◆ defer_gesture_release()

void pulp::state::StateStore::defer_gesture_release ( ParamID id)

Release a lease without synchronously entering host code.

The matching host end callback is queued for flush_deferred_gesture_releases().

◆ deserialize()

bool pulp::state::StateStore::deserialize ( std::span< const uint8_t > data)

Restore parameter values from a parameter-only binary blob.

Format adapters may decode a higher-level host blob first, then pass only the embedded StateStore payload here.

Returns
True if deserialization succeeded.

◆ displayed_modulation()

std::optional< float > pulp::state::StateStore::displayed_modulation ( ParamID id) const
noexcept

The modulated value a control should show, normalized to the parameter's range, or nullopt when nothing modulates id.

◆ end_gesture()

void pulp::state::StateStore::end_gesture ( ParamID id)

Signal the host that the current gesture has ended.

Main-thread only — see begin_gesture().

◆ flush_deferred_gesture_releases()

void pulp::state::StateStore::flush_deferred_gesture_releases ( )
noexcept

◆ gesture_thread_violation_count()

std::uint64_t pulp::state::StateStore::gesture_thread_violation_count ( ) const
inline

Number of times a gesture entry point (begin_gesture / end_gesture) was called off the host main thread while a main-thread backend was registered.

Always zero in headless tests (no backend) and for correctly main-thread-confined UIs. A non-zero value flags a threading bug — a background writer that bypassed run_gesture_on_main.

◆ get_base_offset()

BaseOffsetValue pulp::state::StateStore::get_base_offset ( ParamID id) const

Read the canonical base-vs-offset pair without collapsing its fields.

◆ get_default()

float pulp::state::StateStore::get_default ( ParamID id) const

Get the default value for a parameter (from its ParamRange).

◆ get_modulated()

float pulp::state::StateStore::get_modulated ( ParamID id) const

Read a parameter's modulated value: base + mod_offset (lock-free).

Note
Safe to call from the audio thread.

◆ get_normalized()

float pulp::state::StateStore::get_normalized ( ParamID id) const

Read a parameter's value mapped to [0, 1] (lock-free).

◆ get_value()

float pulp::state::StateStore::get_value ( ParamID id) const
inline

Read a parameter's base value (lock-free).

Note
Safe to call from the audio thread. Defined inline: processors call this for every parameter they read on every block.

◆ has_trigger_params()

bool pulp::state::StateStore::has_trigger_params ( ) const
inline

True when at least one registered parameter is a trigger / momentary control.

Adapters can skip calling reset_triggers_rt() when false.

◆ info()

const ParamInfo * pulp::state::StateStore::info ( ParamID id) const

Look up immutable metadata for a parameter.

Returns
Pointer to ParamInfo, or nullptr if id is not registered.

◆ open_gesture_count()

std::size_t pulp::state::StateStore::open_gesture_count ( ) const
inlinenoexcept

Number of parameters with an open gesture (begin without a matching end).

Observability for tests and adapters.

◆ operator=()

StateStore & pulp::state::StateStore::operator= ( const StateStore & )
delete

◆ param_count()

std::size_t pulp::state::StateStore::param_count ( ) const
inline

Number of registered parameters.

◆ param_reader()

ParamReader pulp::state::StateStore::param_reader ( ParamID id) const

Resolve a read handle for a parameter's base value.

Call off the audio thread (e.g. in prepare()); the returned handle's get() is cheaper than get_value() because the ID lookup is already done. An unknown ID yields an unbound handle that reads 0.0f.

◆ parameter_display_name()

std::string pulp::state::StateStore::parameter_display_name ( ParamID id) const

Current host-facing name: overlay when present, otherwise ParamInfo::name.

Returns an owned string so a concurrent overlay publication cannot invalidate the caller's view.

◆ parameter_display_revision()

std::uint64_t pulp::state::StateStore::parameter_display_revision ( ) const
inlinenoexcept

Monotonic edge for format adapters that republish ParameterInfo.

◆ pump_listeners()

std::size_t pulp::state::StateStore::pump_listeners ( )

Drain queued main-thread listener invocations posted by set_value_rt() / set_normalized_rt() from the audio thread.

Call this from the main thread (e.g. the editor's per-frame timer or the host's UI tick).

Returns
Number of changes drained from the queue.

◆ reconcile_restore_listeners()

std::size_t pulp::state::StateStore::reconcile_restore_listeners ( )

Reconcile opted-in Main listeners with the current parameter snapshot.

State restore writes parameter atomics without invoking listeners because the host may deserialize on a non-UI thread. ViewBridge calls this from its main-thread idle tick after observing a successful deserialize edge. Only listeners registered with ListenerRestoreBehavior::Reconcile participate; ordinary Main and Audio listeners are never invoked.

The restore revision is consumed store-wide, so multiple ViewBridges sharing this store do not replay the same callbacks. Each bridge still tracks the edge independently so every attached view repaints.

Listener additions and removals during callbacks are safe. A listener removed before its turn is skipped, and a listener added during this pass participates only in the next reconciliation.

Returns
Number of Main-listener callbacks invoked.

◆ register_state_migration()

bool pulp::state::StateStore::register_state_migration ( uint32_t from_version,
uint32_t to_version,
StateMigrationRegistry::MigrationFn migration )

Register a load-time migration for this store's parameter schema.

Migrations are scoped to the StateStore instance because state schema versions are plugin-defined; two plugins may both need a different migration from version 1 to 2.

◆ release_gesture()

void pulp::state::StateStore::release_gesture ( ParamID id)

◆ release_open_gestures()

void pulp::state::StateStore::release_open_gestures ( )

Close every gesture still open and report each end to the host.

The store tracks which parameters have an open gesture (a begin_gesture with no matching end_gesture) so that begin/end are balanced 1:1 toward the host — a second begin_gesture on an already-open parameter is suppressed, and an end_gesture on a parameter that was never opened is a no-op. An editor torn down mid-drag (the user closes the plugin window without lifting the mouse) would otherwise leave the host's automation record open forever; a format adapter calls this on editor teardown to release everything still held. Main-thread only — see begin_gesture().

◆ remove_listener()

void pulp::state::StateStore::remove_listener ( ListenerToken & token)

Remove a listener explicitly.

Equivalent to letting the token fall out of scope.

◆ reset_all_mod()

void pulp::state::StateStore::reset_all_mod ( )

Clear all modulation offsets to zero.

◆ reset_all_to_defaults()

void pulp::state::StateStore::reset_all_to_defaults ( )

Reset all parameters to their default values.

◆ reset_rt_listener_queue_overflow_count()

void pulp::state::StateStore::reset_rt_listener_queue_overflow_count ( )

Reset only the RT listener queue overflow counter.

Queued events are untouched.

◆ reset_to_default()

void pulp::state::StateStore::reset_to_default ( ParamID id)

Reset a single parameter to its default value.

◆ reset_triggers_rt()

bool pulp::state::StateStore::reset_triggers_rt ( )

Reset every trigger / momentary parameter to its range default.

A trigger parameter (see ParamInfo::is_trigger / a Reset designation) is a one-shot "do this now" control. Format adapters call this once at the end of each process block, after the Processor has observed the value, so the control returns to its resting default for the next block.

Real-time safe: writes directly to the lock-free atomic value of each trigger parameter (no allocation, no listener dispatch, no queueing). The set of trigger indices is cached at registration, so this is O(number of trigger params), and a store with no triggers does no work.

Returns
true if any trigger parameter was reset this call.

◆ rt_listener_queue_telemetry()

RtListenerQueueTelemetry pulp::state::StateStore::rt_listener_queue_telemetry ( ) const

Latest telemetry for the RT-to-main listener queue used by set_value_rt() / pump_listeners().

◆ run_gesture_on_main()

void pulp::state::StateStore::run_gesture_on_main ( std::function< void()> gesture)

Run a complete parameter gesture (begin_gesture → value writes → end_gesture) on the host's main thread, from ANY thread.

This is the enforced marshalling path for background writers. If a main-thread backend is registered (i.e. inside a real host) and the caller is off it, gesture is posted via events::MainThreadDispatcher::call_async and runs later on the main thread. Otherwise (already on the main thread, or a headless test with no backend) it runs inline. The whole begin→set→end sequence must be posted as one unit so the host sees the calls in order on one thread — posting only begin/end while writing the value elsewhere would corrupt undo grouping.

◆ serialize()

std::vector< uint8_t > pulp::state::StateStore::serialize ( ) const

Serialize all parameter values to a binary blob for preset/state save.

This is the parameter-only payload. Format adapters may wrap it in a higher-level host blob alongside Processor::serialize_plugin_state().

Returns
Byte vector suitable for storage or transmission.

◆ set_display_modulation()

void pulp::state::StateStore::set_display_modulation ( ParamID id,
float plain_value )
noexcept

Publish the value (plain units) a plugin's own modulator plays for id.

Display only. Real-time safe (one relaxed store).

◆ set_gesture_callbacks()

void pulp::state::StateStore::set_gesture_callbacks ( std::function< void(ParamID)> begin_fn,
std::function< void(ParamID)> end_fn )
inline

Install callbacks that forward gesture begin/end to the plugin host.

Format adapters (VST3, AU, CLAP) call this during initialization so that UI-driven gestures are reported to the host for undo grouping.

◆ set_main_loop()

void pulp::state::StateStore::set_main_loop ( pulp::events::EventLoop * loop)

Install an EventLoop used to marshal ListenerThread::Main listeners onto the main thread.

If unset, Main listeners run inline on whichever thread fired set_value().

Format adapters and standalone hosts install this during plugin initialization; tests usually leave it unset.

◆ set_mod_offset()

void pulp::state::StateStore::set_mod_offset ( ParamID id,
float offset )

Set the absolute modulation offset for a parameter.

◆ set_normalized()

void pulp::state::StateStore::set_normalized ( ParamID id,
float normalized )

Write a parameter from a normalized [0, 1] value (lock-free).

◆ set_normalized_rt()

void pulp::state::StateStore::set_normalized_rt ( ParamID id,
float normalized )

Real-time-safe normalized-value write.

Denormalizes through the parameter's ParamRange and then dispatches through set_value_rt(). Used by the VST3 adapter where the host reports parameter changes in normalized [0, 1] form.

◆ set_parameter_display_name()

bool pulp::state::StateStore::set_parameter_display_name ( ParamID id,
std::string name )

Override only the host-facing presentation name of a stable parameter.

The registered ParamInfo remains immutable: its ID, ordering, range, value, and authoring name do not change. Format adapters may use this overlay when a plugin keeps a fixed automation slot but changes the semantic label shown by the host (for example, a generated macro slot changing from "Tone" to "Cutoff").

Passing an empty name clears the overlay and restores ParamInfo::name. Safe to call from non-audio threads while processing is active. Readers observe an immutable copy-on-write snapshot.

Returns
true only when a registered parameter's displayed name changed.

◆ set_state_version()

void pulp::state::StateStore::set_state_version ( uint32_t version)
inline

Set the schema version embedded in serialized state.

Increment this when the parameter layout changes between plugin versions.

◆ set_value()

void pulp::state::StateStore::set_value ( ParamID id,
float value )

Write a parameter's base value (lock-free).

Note
Safe to call from any thread.

◆ set_value_rt()

void pulp::state::StateStore::set_value_rt ( ParamID id,
float value )

Real-time-safe parameter write for use from the audio thread.

Performs the atomic value store (lock-free, no allocation) and fires registered ListenerThread::Audio listeners inline. Any ListenerThread::Main listeners are NOT invoked here — the change is pushed onto a single-producer/single-reader queue and drained by pump_listeners() on the main thread. This avoids the EventLoop::dispatch lambda allocation that the generic set_value() path performs when a Main listener exists.

Use this from format-adapter audio callbacks (CLAP / VST3 / AU process) for host-driven parameter writes. UI-driven writes from the main thread should use set_value().

Note
The pending-changes queue is bounded; if pump_listeners() is not called fast enough the oldest queued events are dropped (the atomic value is still up-to-date, so the UI picks up the latest on its next pump). Use rt_listener_queue_telemetry() to inspect this pressure.

◆ set_value_rt_if_baseline()

ConditionalParameterApplyResult pulp::state::StateStore::set_value_rt_if_baseline ( const ParameterFeedbackBaseline & baseline,
float value )

Publish asynchronous feedback only if the captured identity is still current.

The packed identity CAS is the linearization point. A conflict leaves the newer value untouched and emits no notification. current_identity is diagnostic only; callers recapture a fresh baseline before retrying and must not treat it as an authority token. Revision exhaustion is reported as Conflict and never wraps.

◆ set_values_rt()

void pulp::state::StateStore::set_values_rt ( std::span< const ParamWrite > writes)

set_value_rt() for several parameters as one store write: one writer claim for the batch and one listener-snapshot lease for its notifications.

Writes apply in batch order, each with its own state generation, exactly as consecutive set_value_rt() calls would: a repeated ID ends at its last value, and a write an Audio listener makes during the batch is overwritten by a later batch write to the same parameter. Every applied write notifies its parameter's listeners once, and Audio listeners run inside the batch. Real-time safe; format adapters use it to write a block's automation.

◆ snapshot()

template<std::size_t N>
std::array< float, N > pulp::state::StateStore::snapshot ( const std::array< ParamID, N > & ids) const
nodiscardnoexcept

Block-local snapshot of N parameter values.

Loads each parameter once and returns the values in a stack- allocated std::array. DSP code should call this once at the top of process() and read from the returned array inside the per-sample loop, instead of calling get_value() per sample (each per-sample atomic load is a memory fence and fans out across cores). Mirrors the usual audio-thread pattern: snapshot the values you need before entering the inner loop.

Template Parameters
NCompile-time count of parameter IDs to read.
Parameters
idsParameter IDs to snapshot, in the desired output order. Unknown IDs yield 0.0f at their slot.
Returns
std::array<float, N> — same order as ids.
constexpr std::array<ParamID, 2> kIds = { kGainId, kMixId };
auto p = store.snapshot(kIds);
for (int s = 0; s < n; ++s) {
out[s] = in[s] * p[0] + dry[s] * (1.f - p[1]);
}

◆ snapshot_modulated()

template<std::size_t N>
std::array< float, N > pulp::state::StateStore::snapshot_modulated ( const std::array< ParamID, N > & ids) const
nodiscardnoexcept

Modulated variant of snapshot — returns each parameter's base + per-buffer modulation offset (see set_mod_offset).

Use this from a synth that consumes CLAP's modulated values inside the voice loop.

◆ state_generation()

std::uint64_t pulp::state::StateStore::state_generation ( ) const
inlinenoexcept

Current mutation generation for every parameter-state writer.

Base-value writes (UI and audio), modulation changes, trigger resets, state restore, and generation-bound gestures all advance this one monotonic source. Registration does not: parameters are defined before the live store is published.

◆ state_restore_revision()

std::uint64_t pulp::state::StateStore::state_restore_revision ( ) const
inlinenoexcept

Monotonic reconciliation edge published after each successful deserialize().

Deserialization deliberately does not dispatch parameter listeners: format hosts may restore from a thread where author/UI callbacks are unsafe. An attached ViewBridge polls this revision on its main-thread idle tick and schedules one editor repaint, whose paint boundary can then reconcile listener-silent control state.

This is an edge, not a count of host-level restore successes. A higher-level restore that applies parameter state and then rejects its plugin-owned payload may deserialize the previous parameter snapshot as rollback, advancing this revision twice. Consumers compare for inequality and may coalesce either advance into one refresh of the final state.

◆ state_snapshot_is_current()

bool pulp::state::StateStore::state_snapshot_is_current ( std::uint64_t generation) const
inlinenoexcept

True when no writer is in flight and none has advanced the generation past generation.

A writer advances the generation BEFORE it stores its value, so a snapshot of values is trustworthy only when this holds both before the values are read and after (see format::boundary::refresh_param_snapshot); checking only afterwards accepts a snapshot that read a value a writer was about to replace.

◆ state_version()

uint32_t pulp::state::StateStore::state_version ( ) const
inline

Get the current state schema version.

◆ watch_modulation()

ModulationWatch pulp::state::StateStore::watch_modulation ( ParamID id,
std::function< void(std::optional< float >)> on_change )
nodiscard

Call on_change on the main thread, from pump_listeners(), whenever displayed_modulation(id) changes (nullopt when it stops).

The watch lasts as long as the returned token. Main thread only.

◆ ParamReader

friend class ParamReader
friend

◆ test_support::StateWriterProbe

friend struct test_support::StateWriterProbe
friend

The documentation for this class was generated from the following file:
  • /home/runner/work/pulp/pulp/core/state/include/pulp/state/store.hpp