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

SequencerStateChannel is the audio-safe transport for a plugin's structured NON-parameter state: the bulk, observable state a step sequencer / mod-matrix / pattern engine holds outside its automatable parameter set (e.g. More...

Namespaces

namespace  detail
namespace  stable_sort_detail
namespace  test_support

Classes

struct  ContentInstallLimits
 Caps on what an archive may inflate to. More...
class  ContentSizeBudget
 Running admission of archive entries against a ContentInstallLimits. More...
struct  ContentPackInfo
 Metadata for one installed content pack. More...
struct  ContentInstallPolicy
struct  ContentInstallPreview
struct  ContentInstallResult
class  ContentRegistry
 Installed content lookup. More...
class  Binding
 Reactive binding between a UI widget and a StateStore parameter. More...
class  CachedProperty
 Cached accessor for a StateTree property. More...
struct  ContentCapabilityManifest
 Capabilities a plugin declares before consuming installed content packs. More...
struct  EditAction
 Base class for undoable actions. More...
class  LambdaEdit
 Convenience action using lambdas. More...
class  EditHistory
 Global undo/redo history for the application. More...
struct  ExternalBindingConfig
 Configuration for an ExternalBinding: the getter/setter that back a UI control whose value is NOT a StateStore parameter — e.g. More...
class  ExternalBinding
 Reactive binding between a UI widget and an arbitrary external value source, interface-compatible with state::Binding but backed by getter/setter lambdas instead of a StateStore parameter. More...
class  ListenerToken
 RAII handle for a registered parameter-change listener. More...
struct  MidiMapScale
 Normalized [0, 1] output window a CC sweep is mapped onto. More...
class  MidiParameterMap
struct  ModulationSource
struct  ModulationTarget
struct  ModulationLane
struct  ModulationLaneValidation
struct  ParamSnapshotEntry
class  ParamCursor
struct  ParamOrderingViolation
 One way a new descriptor version broke a previously-shipped parameter's host-facing identity. More...
struct  BaseOffsetValue
 Canonical automation value shared by graph, Processor, and timeline delivery. More...
struct  ParamRange
 Defines the numeric range of a parameter, including normalization. More...
struct  SkewedRange
 Skew-aware normalized range with optional symmetric center. More...
struct  ParamInfo
 Immutable parameter metadata, registered once at plugin initialization. More...
class  ParamValue
 Thread-safe atomic parameter value for lock-free audio/UI communication. More...
class  ParameterEdit
struct  ParameterEvent
struct  ModulationEvent
 Timestamped host modulation event. More...
class  ModulationEventQueue
struct  ParameterEventQueueTelemetry
class  ParameterEventQueue
struct  PresetInfo
 Metadata for a single preset file. More...
struct  ParamSetting
 One parameter value read from a preset file. More...
class  PresetManager
 Built-in preset manager for Pulp plugins. More...
class  PropertiesFile
 JSON-backed persistent settings file. More...
class  ApplicationProperties
 Application-level properties with platform-standard paths. More...
struct  StepCell
 One step in one lane. More...
struct  PlayheadState
 Volatile, high-rate transport/playhead state. More...
struct  SequencerConfig
 Lanes/Steps/Patterns are MAXIMUM CAPACITY (active extent lives in the Snapshot). More...
struct  DirtyRegion
struct  SetCellEditT
 SetCell carries a full cell by value, so it is templated on the Config's cell type. More...
struct  ClearEdit
struct  RandomizeLaneEdit
struct  SetPatternLengthEdit
struct  SwitchPatternEdit
struct  StepEditCommandT
struct  PatternStateT
struct  SnapshotT
 The full non-param state, published for bulk replacement / resync only. More...
struct  StepRangeAppliedT
 The exact cells the engine wrote for a step-range edit. More...
struct  AppliedEditT
class  SequencerStateChannelT
 Ownership: the engine (audio) thread is the single reader of the command queue and the single writer of the applied queue / snapshot / playhead. More...
class  StateMigrationRegistry
 Offline migration support for serialized StateStore payloads. More...
struct  PropertyArrayValue
struct  PropertyObjectValue
struct  PropertyArray
struct  PropertyObject
struct  TreeEditError
 Error value for a refused StateTree edit. More...
class  StateTree
 Reactive tree node — each node has a type name, properties, and children. More...
class  ObservableValue
 Observable value — wraps a single value with change notification. More...
struct  SyncDelta
 A single change to synchronize. More...
class  StateTreeSynchroniser
 Encodes StateTree changes as deltas for transmission. More...
struct  ParamGroup
 Named parameter group for hierarchical UI organization. More...
struct  RtListenerQueueTelemetry
 Snapshot of StateStore's real-time listener queue. More...
struct  ParameterGestureApplyResult
class  ParameterFeedbackBaseline
 Opaque exact identity captured when asynchronous work is ordered against a parameter. More...
struct  ConditionalParameterApplyResult
class  ParamReader
 Pre-resolved audio-thread read handle for one parameter's base value. More...
class  StateStore
 Centralized parameter storage with lock-free value access. More...
struct  UndoAction
 A single undoable action with undo and redo functions. More...
struct  UndoTransaction
 A group of actions that undo/redo together as one step. More...
class  UndoManager
 Manages undo/redo history with configurable depth. More...

Typedefs

using ModulationSourceId = uint32_t
using ParamID = uint32_t
 Unique parameter identifier, stable across plugin versions.
using ParamChangeCallback = std::function<void(ParamID id, float new_value)>
 Callback signature for parameter change notifications.
using ContentPresetSource
 Lists installed content-pack presets for a plugin's content manifest.
using Epoch = std::uint64_t
using EngineSequence = std::uint64_t
using ClientSequence = std::uint64_t
using EditTransactionId = std::uint32_t
using ReferenceSequencerConfig
 The canonical way to name the transport types is via the channel's member typedefs (e.g.
using SequencerStateChannel = SequencerStateChannelT<ReferenceSequencerConfig>
using Snapshot = SnapshotT<ReferenceSequencerConfig>
using PatternState = PatternStateT<ReferenceSequencerConfig>
using StepEditCommand = StepEditCommandT<ReferenceSequencerConfig>
using AppliedEdit = AppliedEditT<ReferenceSequencerConfig>
using StepRangeApplied = StepRangeAppliedT<ReferenceSequencerConfig>
using SetCellEdit = SetCellEditT<ReferenceSequencerConfig>
using PropertyValue
 Property value — can hold scalar values plus immutable recursive arrays and string-keyed objects.
using TreeListener
 Listener callback — receives the tree node, property name, old value, new value.
using ChildListener = std::function<void(StateTree& parent, StateTree& child, int index)>
 Child listener — receives parent, child, index.
using ChildMovedListener
 Reorder listener — a child moved within the same parent from old_index to new_index (both positions at the time of the edit).
using ParentChangedListener = std::function<void(StateTree& node, StateTree* old_parent)>
 Parent-changed listener — node's parent pointer changed.
using AncestorChangedListener = std::function<void(StateTree& node)>
 Ancestor-changed listener — some ancestor link above node changed (the node itself or one of its ancestors was added, removed or moved).
using TreeEditResult = runtime::Result<std::monostate, TreeEditError>
 Result of a checked StateTree edit: success carries no value.
using PropertyValidator
 Property validator used by checked edits.

Enumerations

enum class  ContentReloadPolicy { hot_reload , manual_rescan , restart_required }
enum class  ListenerThread { Main , Audio }
 Where a parameter-change listener runs. More...
enum class  ListenerRestoreBehavior { Silent , Reconcile }
 Whether a Main listener participates in the UI refresh that follows a successful state restore. More...
enum class  ModulationScope : uint8_t { Global , Voice , Note , GraphNode }
enum class  ModulationRate : uint8_t { Control , Audio }
enum class  ModulationMixMode : uint8_t { Add , Replace , Multiply }
enum class  ModulationLaneRejectReason : uint8_t {
  None , InvalidSource , InvalidTarget , TargetNotWritable ,
  TargetNotModulatable , ScopeMismatch , AudioSourceRequiresAudioTarget
}
enum class  BaseOffsetRefusal : std::uint8_t { None , NonFiniteBase , NonFiniteOffset , OutOfRange }
enum class  ParamRate { ControlRate , AudioRate }
 Parameter update-rate classification. More...
enum class  ParamKind { Continuous , Integer , Toggle , Enum }
 Author-declared parameter semantics. More...
enum class  ParamDesignation { None , Bypass , Reset }
 Declared semantic role of a parameter. More...
enum class  DirtyKind : std::uint8_t {
  None , FullSnapshot , Pattern , Lane ,
  StepRange , Cell
}
enum class  StepEditKind : std::uint8_t {
  SetCell , Clear , RandomizeLane , SetPatternLength ,
  SwitchPattern
}
enum class  ClearScope : std::uint8_t { Cell , Lane , Pattern , All }
enum class  GesturePhase : std::uint8_t {
  None , Begin , Update , End ,
  Cancel
}
 Host-undo gesture bracketing hint. More...
enum class  AppliedEditKind : std::uint8_t { StepRangeChanged , PatternLengthChanged , ActivePatternChanged , CommandRejected }
enum class  ListenerDelivery { kCoalesced , kImmediate }
 When a listener is told about edits made inside a StateTree::Transaction. More...
enum class  TreeEditErrorCode {
  kInvalidName , kMissingProperty , kNullChild , kIndexOutOfRange ,
  kWouldCreateCycle , kTransactionConflict , kRejectedByValidator , kNotInTransaction ,
  kReentrantTransaction , kTransactionClosed
}
 Why a checked StateTree edit was refused. More...
enum class  SyncDeltaType : uint8_t {
  PropertySet = 1 , PropertyRemove = 2 , ChildAdd = 3 , ChildRemove = 4 ,
  ChildMove = 5
}
 Delta types for tree synchronization. More...
enum class  ParameterGestureApplyStatus {
  Applied , GenerationConflict , InvalidParameter , ConcurrentMutation ,
  CallbackFailureRolledBack , CallbackFailureUnknown
}
 Outcome of a generation-bound complete parameter gesture. More...
enum class  ConditionalParameterApplyStatus { Applied , Conflict , InvalidParameter }

Functions

ContentInstallLimits clamp_content_install_bytes (ContentInstallLimits limits, std::uint64_t max_bytes)
 Lower both byte caps to at most max_bytes (a user-facing --max-pack-bytes value).
ContentPresetSource content_registry_preset_source ()
 A PresetManager content-preset source backed by this registry: it lists the installed packs' presets under data_root, or under platform_data_root() when data_root is empty.
ContentInstallPreview preview_content_pack_install (const std::filesystem::path &input, const ContentCapabilityManifest &plugin, const std::filesystem::path &data_root=ContentRegistry::platform_data_root(), const ContentInstallLimits &limits={})
 Validate a local content-pack directory or .pulpcontent archive against a trusted plugin runtime manifest without copying any files.
ContentInstallResult install_content_pack (const std::filesystem::path &input, const ContentCapabilityManifest &plugin, const std::filesystem::path &data_root=ContentRegistry::platform_data_root(), bool approved=false, const ContentInstallLimits &limits={})
 Install a previously previewable data-only content pack.
const char * to_string (ContentReloadPolicy policy)
std::vector< Binding > create_bindings (StateStore &store)
 Create a Binding for every parameter registered in a store.
bool property_is_absent (const PropertyValue &val)
std::optional< ContentCapabilityManifest > parse_content_capability_manifest (std::string_view json, std::string *error=nullptr)
 Parse the plugin-side content capability manifest embedded in a built plugin/app bundle.
std::optional< ContentCapabilityManifest > load_content_capability_manifest (const std::filesystem::path &path, std::string *error=nullptr)
 Load and parse a plugin content capability manifest from disk.
std::string content_capability_manifest_to_json (const ContentCapabilityManifest &manifest)
 Serialize a capability manifest for embedding in plugin bundle resources.
constexpr ModulationRate modulation_rate_for (ParamRate rate) noexcept
constexpr bool modulation_scopes_compatible (ModulationScope source, ModulationScope target) noexcept
ModulationLaneValidation validate_modulation_lane (const ModulationLane &lane) noexcept
std::string param_display_text (const ParamInfo &info, float value)
 Display text for value in info's own domain.
bool param_parse_display_text (const ParamInfo &info, const std::string &text, float &out_value)
 Parse display text back into info's own domain.
choc::value::Value param_metadata_to_value (const ParamInfo &info)
 A parameter's STATIC shape — everything that does not move when the value does.
choc::value::Value param_snapshot_to_value (const StateStore &store, const ParamInfo &info)
 A parameter's LIVE snapshot, in the inspector's established wire shape.
choc::value::Value param_catalog_snapshot_to_value (const StateStore &store, const ParamInfo &info)
 The canonical Product A catalog + live-value shape.
std::vector< ParamOrderingViolation > diff_param_ordering (std::span< const ParamInfo > old_params, std::span< const ParamInfo > new_params)
 Diff two parameter descriptors (old vs new) and return every ordering / identity violation, in old-version index order.
std::vector< ParamOrderingViolation > diff_param_ordering (const StateStore &old_store, const StateStore &new_store)
 StateStore convenience overload.
bool param_ordering_stable (std::span< const ParamInfo > old_params, std::span< const ParamInfo > new_params)
 True iff new_params is an append-only, identity-preserving evolution of old_params (no re-order, re-ID, or removal of a shipped parameter).
bool param_ordering_stable (const StateStore &old_store, const StateStore &new_store)
 StateStore convenience overload.
BaseOffsetRefusal validate_base_offset (BaseOffsetValue value, float minimum, float maximum) noexcept
bool is_discrete_param (const ParamInfo &info)
float value_from_host_normalized (const ParamInfo &info, double normalized)
 The plain value a host means by a normalized write.
double host_normalized_from_value (const ParamInfo &info, float value)
 The normalized value to report to a host for value: the inverse of value_from_host_normalized(), in double precision for a linear range, so a value the host reads back (a default, an output parameter) maps to exactly the same plain value when the host writes it again.
bool is_boolean_param (const ParamInfo &info)
uint32_t param_value_count (const ParamInfo &info)
float constrain_param_value (const ParamInfo &info, float value)
std::optional< float > param_value_for_label (const ParamInfo &info, std::string_view text)
bool is_bypass_param (const ParamInfo &info)
 Decide whether info is a bypass control.
bool is_modulatable_param (const ParamInfo &info)
 Decide whether a host may apply a modulation offset to info.
bool is_hidden_param (const ParamInfo &info)
 Whether the host should omit this parameter from its generic parameter list and automation lanes.
bool is_read_only_param (const ParamInfo &info)
 Whether the host may read this parameter but must not write it.
bool is_automatable_param (const ParamInfo &info)
 Whether the host may record and play back automation for this parameter.
template<typename It, typename Less>
void stable_sort_in_place (It first, It last, Less less)
 Sorts [first, last) by less, keeping equal elements in their original order, without allocating.
template<typename It, typename Key, typename Value, typename Count>
bool stable_counting_sort (It first, It last, Key key, std::span< Value > scratch, std::span< Count > counts)
 Stable counting sort of [first, last) on a small non-negative integer key, O(n + counts.size()) and allocation-free, using caller-lent storage (typically sized once at prepare time).
std::optional< uint32_t > serialized_state_version (std::span< const uint8_t > source)
bool operator== (const PropertyArrayValue &a, const PropertyArrayValue &b)
bool operator!= (const PropertyArrayValue &a, const PropertyArrayValue &b)
bool operator== (const PropertyObjectValue &a, const PropertyObjectValue &b)
bool operator!= (const PropertyObjectValue &a, const PropertyObjectValue &b)
bool operator== (const PropertyArray &a, const PropertyArray &b)
bool operator!= (const PropertyArray &a, const PropertyArray &b)
bool operator== (const PropertyObject &a, const PropertyObject &b)
bool operator!= (const PropertyObject &a, const PropertyObject &b)
PropertyValue make_property_array (std::vector< PropertyValue > values)
PropertyValue make_property_array (std::initializer_list< PropertyValue > values)
PropertyValue make_property_object (std::map< std::string, PropertyValue, std::less<> > values)
PropertyValue make_property_object (std::initializer_list< PropertyObject::Member > values)
const PropertyArray * get_property_array (const PropertyValue &value)
const PropertyObject * get_property_object (const PropertyValue &value)
template<class Config>
std::optional< AppliedEditT< Config > > apply_step_edit (SnapshotT< Config > &snapshot, const StepEditCommandT< Config > &cmd, EngineSequence &engine_seq)
 Reference reducer for the StepCell grid. Returns nullopt only for a no-op.
template<class Config, class Reducer>
void drain_and_apply (SequencerStateChannelT< Config > &channel, SnapshotT< Config > &snapshot, Epoch &epoch, EngineSequence &engine_seq, Reducer &&reduce)
 Drain the command FIFO and apply each command with reduce, publishing the echoes.
template<class Config>
void drain_and_apply (SequencerStateChannelT< Config > &channel, SnapshotT< Config > &snapshot, Epoch &epoch, EngineSequence &engine_seq)
 Convenience overload using the reference StepCell reducer.

Variables

constexpr std::uint8_t kPatternCount = 32
constexpr std::uint8_t kLaneCount = 12
constexpr std::uint8_t kStepCount = 32
constexpr std::size_t kCommandQueueCapacity = 1024
constexpr std::size_t kAppliedQueueCapacity = 1024

Detailed Description

SequencerStateChannel is the audio-safe transport for a plugin's structured NON-parameter state: the bulk, observable state a step sequencer / mod-matrix / pattern engine holds outside its automatable parameter set (e.g.

The audio-side edit logic for a SequencerStateChannel, lifted out of any one engine so a producer never hand-rolls the protocol.

a 12-lane x 32-step x 32-pattern grid, ~12k step records). Parameters keep flowing through StateStore / the host; this channel carries the rest.

It is a THIN, typed bundle of the three lock-free primitives, with the ownership split that keeps a large grid cheap to edit and cheap to render:

  • UI -> audio: ordered edit commands SpscQueue<Command>
  • audio -> UI: ordered applied echoes SpscQueue<AppliedEdit>
  • audio -> UI: bulk/versioned state TripleBuffer<Snapshot>
  • audio -> UI: high-rate playhead SeqLock<Playhead>

The authoritative writer (the "engine") OWNS the state; the UI never mutates shared state — it submits commands and replays the engine's applied echoes onto its own render copy, so both sides converge without either diffing the whole grid every frame. Each applied echo names the exact DirtyRegion it touched, so the UI invalidates only what changed. A full Snapshot is only published for initial load, preset / bulk replacement, and overflow recovery — never per cell edit (it is a large copy).

NEUTRAL PRODUCER CONTRACT: the authoritative writer is any single thread. It need NOT be a framework processor and this header includes nothing from the format or state-store layers — only runtime primitives. A non-framework engine can own the channel and drive it directly (see step_edit_reducer.hpp for the reference apply/drain logic and the docs page docs/reference/sequencer-state-channel.md for the full contract).

Because TripleBuffer is latest-value and coalesces intermediate writes, a Snapshot must NEVER be used as an incremental change descriptor: two cell edits published back-to-back would collapse to one snapshot and lose the first cell's dirty region. Incremental "what changed" flows only on the ordered AppliedEdit echo stream; the Snapshot is a coherent resync point.

This channel is pure transport: it invents no epochs or sequence numbers. The engine controls Snapshot::epoch and *_sequence values; the channel moves the bytes and exposes the resync-epoch signal + FIFO telemetry.

DIMENSIONS ARE COMPILE-TIME (SequencerConfig), by design: the Snapshot is a nested std::array and therefore trivially copyable, which is the property that lets TripleBuffer/SpscQueue publish it lock-free and allocation-free on the audio thread. Config dims are MAXIMUM CAPACITY; active extent is explicit in the Snapshot (PatternState::length, active_lane_count, active_pattern_count).

  • apply_step_edit<Config>: the reference reducer. Mutates the authoritative Snapshot for one command and returns the exact AppliedEdit echo the UI replays (so the UI never diffs the grid or re-runs an engine algorithm). Defined for the reference StepCell; a custom cell type supplies its own reducer with the same signature.
  • drain_and_apply<Config, Reducer>: drains the command FIFO, applies each command via the reducer, publishes each echo, and OWNS the overflow recovery — on a full applied-FIFO it republishes the authoritative Snapshot and raises the resync bar, in the order that avoids live-locking the UI.

NEUTRAL: this header includes only sequencer_state_channel.hpp (runtime primitives) — nothing from <pulp/format/...>. A non-Pulp engine can use it.

Typedef Documentation

◆ AncestorChangedListener

using pulp::state::AncestorChangedListener = std::function<void(StateTree& node)>

Ancestor-changed listener — some ancestor link above node changed (the node itself or one of its ancestors was added, removed or moved).

◆ AppliedEdit

◆ ChildListener

using pulp::state::ChildListener = std::function<void(StateTree& parent, StateTree& child, int index)>

Child listener — receives parent, child, index.

The index is the child's position at the time of the edit; for a removal it is the index the child held before it was removed.

◆ ChildMovedListener

Initial value:
std::function<void(StateTree& parent, StateTree& child, int old_index, int new_index)>
Reactive tree node — each node has a type name, properties, and children.
Definition state_tree.hpp:293

Reorder listener — a child moved within the same parent from old_index to new_index (both positions at the time of the edit).

◆ ClientSequence

using pulp::state::ClientSequence = std::uint64_t

◆ ContentPresetSource

Initial value:
std::function<std::vector<PresetInfo>(
const ContentCapabilityManifest& manifest, const std::filesystem::path& data_root)>
Capabilities a plugin declares before consuming installed content packs.
Definition content_capability_manifest.hpp:19

Lists installed content-pack presets for a plugin's content manifest.

data_root is the explicit content data root, or empty for the platform default.

◆ EditTransactionId

using pulp::state::EditTransactionId = std::uint32_t

◆ EngineSequence

using pulp::state::EngineSequence = std::uint64_t

◆ Epoch

using pulp::state::Epoch = std::uint64_t

◆ ModulationSourceId

◆ ParamChangeCallback

using pulp::state::ParamChangeCallback = std::function<void(ParamID id, float new_value)>

Callback signature for parameter change notifications.

Parameters
idThe parameter that changed.
new_valueThe new raw value.

◆ ParamID

using pulp::state::ParamID = uint32_t

Unique parameter identifier, stable across plugin versions.

Use a hash or manual assignment to keep IDs consistent between releases.

◆ ParentChangedListener

using pulp::state::ParentChangedListener = std::function<void(StateTree& node, StateTree* old_parent)>

Parent-changed listener — node's parent pointer changed.

old_parent is the previous parent (null if the node was a root); it is only valid for the duration of the callback. Read node.parent() for the new parent.

◆ PatternState

◆ PropertyValidator

Initial value:
std::function<std::optional<std::string>(
const StateTree& node, std::string_view name, const PropertyValue& value)>
std::variant< std::monostate, bool, int64_t, double, std::string, PropertyArrayValue, PropertyObjectValue > PropertyValue
Property value — can hold scalar values plus immutable recursive arrays and string-keyed objects.
Definition state_tree.hpp:66

Property validator used by checked edits.

Return an error message to refuse the value, or std::nullopt to accept it.

◆ PropertyValue

Initial value:
std::variant<
std::monostate,
bool,
int64_t,
double,
std::string,
>
Definition state_tree.hpp:35
Definition state_tree.hpp:46

Property value — can hold scalar values plus immutable recursive arrays and string-keyed objects.

Arrays/objects use immutable shared storage only to make the recursive variant possible; StateTree::set() deep-copies them on ingress so callers do not create mutable aliases inside the tree.

◆ ReferenceSequencerConfig

Initial value:
Lanes/Steps/Patterns are MAXIMUM CAPACITY (active extent lives in the Snapshot).
Definition sequencer_state_channel.hpp:105

The canonical way to name the transport types is via the channel's member typedefs (e.g.

MyChannel::Snapshot). These namespace-scope aliases are a convenience for the reference 12x32x32 StepCell shape used by the built-in StepGridView / StepSequencer example.

◆ SequencerStateChannel

◆ SetCellEdit

◆ Snapshot

◆ StepEditCommand

◆ StepRangeApplied

◆ TreeEditResult

Result of a checked StateTree edit: success carries no value.

◆ TreeListener

Initial value:
std::function<void(StateTree& node, std::string_view property,
const PropertyValue& old_val, const PropertyValue& new_val)>

Listener callback — receives the tree node, property name, old value, new value.

Enumeration Type Documentation

◆ AppliedEditKind

enum class pulp::state::AppliedEditKind : std::uint8_t
strong
Enumerator
StepRangeChanged 
PatternLengthChanged 
ActivePatternChanged 
CommandRejected 

◆ BaseOffsetRefusal

enum class pulp::state::BaseOffsetRefusal : std::uint8_t
strong
Enumerator
None 
NonFiniteBase 
NonFiniteOffset 
OutOfRange 

◆ ClearScope

enum class pulp::state::ClearScope : std::uint8_t
strong
Enumerator
Cell 
Lane 
Pattern 
All 

◆ ConditionalParameterApplyStatus

Enumerator
Applied 
Conflict 
InvalidParameter 

◆ ContentReloadPolicy

Enumerator
hot_reload 
manual_rescan 
restart_required 

◆ DirtyKind

enum class pulp::state::DirtyKind : std::uint8_t
strong
Enumerator
None 
FullSnapshot 
Pattern 
Lane 
StepRange 
Cell 

◆ GesturePhase

enum class pulp::state::GesturePhase : std::uint8_t
strong

Host-undo gesture bracketing hint.

The channel does not own an undo log; an undo manager above the channel groups edits by (transaction_id, phase).

Enumerator
None 
Begin 
Update 
End 
Cancel 

◆ ListenerDelivery

enum class pulp::state::ListenerDelivery
strong

When a listener is told about edits made inside a StateTree::Transaction.

  • kCoalesced (default): notifications are held while a transaction is open and delivered as one burst when the outermost transaction commits. An aborted transaction delivers nothing. Outside a transaction the listener fires inline after each edit, exactly as before.
  • kImmediate: the listener fires inline after every edit, including edits inside a transaction and the inverse edits an abort applies. Use it for observers that must replay every step in order (mirrors, IPC deltas). An immediate listener must not edit the tree that is notifying it.
Enumerator
kCoalesced 
kImmediate 

◆ ListenerRestoreBehavior

Whether a Main listener participates in the UI refresh that follows a successful state restore.

Deserialization remains silent for ordinary listeners. View bindings that cache parameter values opt into Reconcile so the editor can refresh those caches later, on its main-thread idle tick.

Enumerator
Silent 
Reconcile 

◆ ListenerThread

enum class pulp::state::ListenerThread
strong

Where a parameter-change listener runs.

Main is the safe default: callbacks are marshalled through the EventLoop installed via StateStore::set_main_loop. If no loop is installed (or the firing thread already is the main loop), callbacks run inline.

Audio is an explicit opt-in for advanced callers who can guarantee their callback is real-time safe (no allocation, no locking, bounded work). The callback runs inline on whichever thread invoked StateStore::set_value, including the audio thread.

Enumerator
Main 
Audio 

◆ ModulationLaneRejectReason

enum class pulp::state::ModulationLaneRejectReason : uint8_t
strong
Enumerator
None 
InvalidSource 
InvalidTarget 
TargetNotWritable 
TargetNotModulatable 
ScopeMismatch 
AudioSourceRequiresAudioTarget 

◆ ModulationMixMode

enum class pulp::state::ModulationMixMode : uint8_t
strong
Enumerator
Add 
Replace 
Multiply 

◆ ModulationRate

enum class pulp::state::ModulationRate : uint8_t
strong
Enumerator
Control 
Audio 

◆ ModulationScope

enum class pulp::state::ModulationScope : uint8_t
strong
Enumerator
Global 
Voice 
Note 
GraphNode 

◆ ParamDesignation

enum class pulp::state::ParamDesignation
strong

Declared semantic role of a parameter.

A designation lets the Processor author state what a parameter means rather than leaving format adapters to guess from its name and range. Adapters consult the declared designation first and fall back to a name/range heuristic only for parameters that declare None, so existing plugins keep working unchanged.

  • None — an ordinary parameter (the default). Adapters apply their legacy name/range heuristic to decide whether it is a bypass.
  • Bypass — a host-visible bypass control. Interpreted as a toggle with the threshold convention off < 0.5, on >= 0.5, regardless of the declared range: adapters short-circuit to pass-through audio when the current value is >= 0.5. Because of this threshold, format adapters present a declared Bypass parameter to the host as a two-state/boolean control even if its ParamRange is continuous. Declare this independently of the parameter's name.
  • Reset — a host-visible momentary "reset / panic" control. It behaves as a trigger parameter (see ParamInfo::is_trigger): the host sets it, the Processor observes it for one block, and the value auto-resets to its default after the block.
Enumerator
None 
Bypass 
Reset 

◆ ParameterGestureApplyStatus

Outcome of a generation-bound complete parameter gesture.

Enumerator
Applied 
GenerationConflict 
InvalidParameter 
ConcurrentMutation 
CallbackFailureRolledBack 
CallbackFailureUnknown 

◆ ParamKind

enum class pulp::state::ParamKind
strong

Author-declared parameter semantics.

This is deliberately independent from ParamRange::step. A continuous parameter may still snap to a grid, while integer, toggle, and enum parameters must be advertised to hosts as discrete even if their range was assembled by compatibility code that omitted a step.

Enumerator
Continuous 
Integer 
Toggle 
Enum 

◆ ParamRate

enum class pulp::state::ParamRate
strong

Parameter update-rate classification.

ControlRate parameters are read as one coherent value per processing block. AudioRate parameters may accept dense per-sample modulation from host graph edges.

Enumerator
ControlRate 
AudioRate 

◆ StepEditKind

enum class pulp::state::StepEditKind : std::uint8_t
strong
Enumerator
SetCell 
Clear 
RandomizeLane 
SetPatternLength 
SwitchPattern 

◆ SyncDeltaType

enum class pulp::state::SyncDeltaType : uint8_t
strong

Delta types for tree synchronization.

Enumerator
PropertySet 
PropertyRemove 
ChildAdd 
ChildRemove 
ChildMove 

Reorder within one parent: child_index -> int64 value.

◆ TreeEditErrorCode

enum class pulp::state::TreeEditErrorCode
strong

Why a checked StateTree edit was refused.

The tree is left unchanged and no listener fires when an edit is refused.

Enumerator
kInvalidName 

Empty property name.

kMissingProperty 

remove of a property that does not exist.

kNullChild 

Child pointer was null.

kIndexOutOfRange 

Child index outside the valid range.

kWouldCreateCycle 

Edit would make a node its own descendant.

kTransactionConflict 

Edit spans two trees with different open transactions.

kRejectedByValidator 

A PropertyValidator refused the value.

kNotInTransaction 

Node does not belong to this transaction's tree.

kReentrantTransaction 

Transaction was begun from a listener during a commit burst.

kTransactionClosed 

Transaction already committed or aborted.

Function Documentation

◆ apply_step_edit()

template<class Config>
std::optional< AppliedEditT< Config > > pulp::state::apply_step_edit ( SnapshotT< Config > & snapshot,
const StepEditCommandT< Config > & cmd,
EngineSequence & engine_seq )

Reference reducer for the StepCell grid. Returns nullopt only for a no-op.

◆ clamp_content_install_bytes()

ContentInstallLimits pulp::state::clamp_content_install_bytes ( ContentInstallLimits limits,
std::uint64_t max_bytes )
inline

Lower both byte caps to at most max_bytes (a user-facing --max-pack-bytes value).

A value above a default never raises that default: the flag only tightens. The entry-count cap is untouched.

◆ constrain_param_value()

float pulp::state::constrain_param_value ( const ParamInfo & info,
float value )
inline

◆ content_capability_manifest_to_json()

std::string pulp::state::content_capability_manifest_to_json ( const ContentCapabilityManifest & manifest)

Serialize a capability manifest for embedding in plugin bundle resources.

◆ content_registry_preset_source()

ContentPresetSource pulp::state::content_registry_preset_source ( )

A PresetManager content-preset source backed by this registry: it lists the installed packs' presets under data_root, or under platform_data_root() when data_root is empty.

Install it on a PresetManager that opts into content discovery (PresetManager::set_content_preset_source).

◆ create_bindings()

std::vector< Binding > pulp::state::create_bindings ( StateStore & store)
inline

Create a Binding for every parameter registered in a store.

Returns
Vector of Bindings in parameter registration order.

◆ diff_param_ordering() [1/2]

std::vector< ParamOrderingViolation > pulp::state::diff_param_ordering ( const StateStore & old_store,
const StateStore & new_store )
inline

StateStore convenience overload.

◆ diff_param_ordering() [2/2]

std::vector< ParamOrderingViolation > pulp::state::diff_param_ordering ( std::span< const ParamInfo > old_params,
std::span< const ParamInfo > new_params )
inline

Diff two parameter descriptors (old vs new) and return every ordering / identity violation, in old-version index order.

The rule enforced is append-only stability:

  1. For every index present in BOTH versions, the host-facing ID must be identical (catches re-ordering, insertion-in-the-middle, and re-ID).
  2. Every ID shipped in the old version must still exist somewhere in the new version (catches removals, including a shrink at the tail).

Adding new parameters at the end of new_params is NOT a violation.

◆ drain_and_apply() [1/2]

template<class Config>
void pulp::state::drain_and_apply ( SequencerStateChannelT< Config > & channel,
SnapshotT< Config > & snapshot,
Epoch & epoch,
EngineSequence & engine_seq )

Convenience overload using the reference StepCell reducer.

◆ drain_and_apply() [2/2]

template<class Config, class Reducer>
void pulp::state::drain_and_apply ( SequencerStateChannelT< Config > & channel,
SnapshotT< Config > & snapshot,
Epoch & epoch,
EngineSequence & engine_seq,
Reducer && reduce )

Drain the command FIFO and apply each command with reduce, publishing the echoes.

OWNS the overflow-recovery invariant: if the applied FIFO is full, the UI would miss incremental echoes, so republish the authoritative snapshot and raise the resync bar — snapshot BEFORE the resync mark (the order the channel requires). reduce has signature std::optional<AppliedEditT<Config>>(SnapshotT<Config>&, const Command&, EngineSequence&) and must bump engine_seq for every applied edit (apply_step_edit does).

◆ get_property_array()

const PropertyArray * pulp::state::get_property_array ( const PropertyValue & value)
inline

◆ get_property_object()

const PropertyObject * pulp::state::get_property_object ( const PropertyValue & value)
inline

◆ host_normalized_from_value()

double pulp::state::host_normalized_from_value ( const ParamInfo & info,
float value )
inline

The normalized value to report to a host for value: the inverse of value_from_host_normalized(), in double precision for a linear range, so a value the host reads back (a default, an output parameter) maps to exactly the same plain value when the host writes it again.

◆ install_content_pack()

ContentInstallResult pulp::state::install_content_pack ( const std::filesystem::path & input,
const ContentCapabilityManifest & plugin,
const std::filesystem::path & data_root = ContentRegistry::platform_data_root(),
bool approved = false,
const ContentInstallLimits & limits = {} )

Install a previously previewable data-only content pack.

approved must be true so UI code cannot accidentally turn preview/drop into mutation. The same limits gate extraction as they gate the preview.

◆ is_automatable_param()

bool pulp::state::is_automatable_param ( const ParamInfo & info)
inline

Whether the host may record and play back automation for this parameter.

Automation is a host write, so a parameter the host must not write is not automatable regardless of how automatable was declared.

This is the single predicate every format adapter consults, so one declaration withholds VST3 kCanAutomate, CLAP CLAP_PARAM_IS_AUTOMATABLE and AU's writability together.

◆ is_boolean_param()

bool pulp::state::is_boolean_param ( const ParamInfo & info)
inline

◆ is_bypass_param()

bool pulp::state::is_bypass_param ( const ParamInfo & info)
inline

Decide whether info is a bypass control.

Designation-first, heuristic-fallback: a declared Bypass designation wins regardless of name or range. A parameter that declares None falls back to the legacy name/range heuristic (a boolean parameter named "Bypass": step >= 1, range exactly [0, 1]) so existing plugins are unchanged. A non-None, non-Bypass designation is never a bypass.

This is the single source of truth shared by every format adapter, so the bypass contract cannot drift between VST3 / AU / CLAP.

◆ is_discrete_param()

bool pulp::state::is_discrete_param ( const ParamInfo & info)
inline

◆ is_hidden_param()

bool pulp::state::is_hidden_param ( const ParamInfo & info)
inline

Whether the host should omit this parameter from its generic parameter list and automation lanes.

Refuses to hide a bypass control: hosts surface bypass in their own chrome and a plugin that hides it becomes un-bypassable from the host.

This is the single predicate every format adapter consults, so one declaration projects identically to VST3 kIsHidden, CLAP CLAP_PARAM_IS_HIDDEN and the AU expert-mode hint.

◆ is_modulatable_param()

bool pulp::state::is_modulatable_param ( const ParamInfo & info)
inline

Decide whether a host may apply a modulation offset to info.

Author intent first (ParamInfo::modulatable, default true), then three rules an author cannot override:

  • a bypass control is a host-owned discrete switch, and an additive offset on it has no defined meaning;
  • an auto-resetting trigger is cleared at the end of every process block, so a persistent offset would hold it raised forever;
  • a discrete parameter is an indexed choice, not a magnitude; an additive offset between two indices names no value the author defined. Kind, not range.step: a continuous parameter may quantize its plain value for display and still be a magnitude a host can offset.

This is the single predicate both the host-facing advertisement and the inbound modulation decode consult, so a host can never be told a parameter accepts modulation that the adapter then silently drops.

◆ is_read_only_param()

bool pulp::state::is_read_only_param ( const ParamInfo & info)
inline

Whether the host may read this parameter but must not write it.

Refuses a bypass control and a trigger: both are defined by the host writing to them, so a read-only one could never be operated.

This is the single predicate every format adapter consults, so one declaration projects identically to VST3 kIsReadOnly, CLAP CLAP_PARAM_IS_READONLY and AU's withheld IsWritable.

◆ load_content_capability_manifest()

std::optional< ContentCapabilityManifest > pulp::state::load_content_capability_manifest ( const std::filesystem::path & path,
std::string * error = nullptr )

Load and parse a plugin content capability manifest from disk.

◆ make_property_array() [1/2]

PropertyValue pulp::state::make_property_array ( std::initializer_list< PropertyValue > values)
inline

◆ make_property_array() [2/2]

PropertyValue pulp::state::make_property_array ( std::vector< PropertyValue > values)
inline

◆ make_property_object() [1/2]

PropertyValue pulp::state::make_property_object ( std::initializer_list< PropertyObject::Member > values)
inline

◆ make_property_object() [2/2]

PropertyValue pulp::state::make_property_object ( std::map< std::string, PropertyValue, std::less<> > values)
inline

◆ modulation_rate_for()

ModulationRate pulp::state::modulation_rate_for ( ParamRate rate)
constexprnoexcept

◆ modulation_scopes_compatible()

bool pulp::state::modulation_scopes_compatible ( ModulationScope source,
ModulationScope target )
constexprnoexcept

◆ operator!=() [1/4]

bool pulp::state::operator!= ( const PropertyArray & a,
const PropertyArray & b )
inline

◆ operator!=() [2/4]

bool pulp::state::operator!= ( const PropertyArrayValue & a,
const PropertyArrayValue & b )
inline

◆ operator!=() [3/4]

bool pulp::state::operator!= ( const PropertyObject & a,
const PropertyObject & b )
inline

◆ operator!=() [4/4]

bool pulp::state::operator!= ( const PropertyObjectValue & a,
const PropertyObjectValue & b )
inline

◆ operator==() [1/4]

bool pulp::state::operator== ( const PropertyArray & a,
const PropertyArray & b )
inline

◆ operator==() [2/4]

bool pulp::state::operator== ( const PropertyArrayValue & a,
const PropertyArrayValue & b )
inline

◆ operator==() [3/4]

bool pulp::state::operator== ( const PropertyObject & a,
const PropertyObject & b )
inline

◆ operator==() [4/4]

bool pulp::state::operator== ( const PropertyObjectValue & a,
const PropertyObjectValue & b )
inline

◆ param_catalog_snapshot_to_value()

choc::value::Value pulp::state::param_catalog_snapshot_to_value ( const StateStore & store,
const ParamInfo & info )

The canonical Product A catalog + live-value shape.

This is deliberately assembled here so control adapters do not grow a second parameter JSON serializer alongside scripted UI and the development tools.

{ metadata fields..., value, normalized, modulated, display? }

◆ param_display_text()

std::string pulp::state::param_display_text ( const ParamInfo & info,
float value )

Display text for value in info's own domain.

Order: the author's to_string if they supplied one, else an enum label from value_labels when the parameter is discrete, else a numeric fallback with the unit appended. Callers get the same string the host shows, because they are asking the same function.

◆ param_metadata_to_value()

choc::value::Value pulp::state::param_metadata_to_value ( const ParamInfo & info)

A parameter's STATIC shape — everything that does not move when the value does.

Safe for a consumer to fetch once and cache.

{ id, name, unit, min, max, default, step, skew, symmetricSkew, kind, labels, groupId, designation, isTrigger }

◆ param_ordering_stable() [1/2]

bool pulp::state::param_ordering_stable ( const StateStore & old_store,
const StateStore & new_store )
inline

StateStore convenience overload.

◆ param_ordering_stable() [2/2]

bool pulp::state::param_ordering_stable ( std::span< const ParamInfo > old_params,
std::span< const ParamInfo > new_params )
inline

True iff new_params is an append-only, identity-preserving evolution of old_params (no re-order, re-ID, or removal of a shipped parameter).

◆ param_parse_display_text()

bool pulp::state::param_parse_display_text ( const ParamInfo & info,
const std::string & text,
float & out_value )

Parse display text back into info's own domain.

Order: the author's from_string if supplied, else an enum label match, else a numeric parse that tolerates a trailing unit ("440 Hz", "-3 dB", "50%"). The result is constrained to the declared range and step. Returns false when the text names nothing — a caller must be able to tell "0" from "unparseable" rather than silently storing a zero.

◆ param_snapshot_to_value()

choc::value::Value pulp::state::param_snapshot_to_value ( const StateStore & store,
const ParamInfo & info )

A parameter's LIVE snapshot, in the inspector's established wire shape.

{ id, name, unit, value, normalized, modulated, default, min, max, display? } — display is omitted when empty, matching what the inspector has always sent.

◆ param_value_count()

uint32_t pulp::state::param_value_count ( const ParamInfo & info)
inline

◆ param_value_for_label()

std::optional< float > pulp::state::param_value_for_label ( const ParamInfo & info,
std::string_view text )
inline

◆ parse_content_capability_manifest()

std::optional< ContentCapabilityManifest > pulp::state::parse_content_capability_manifest ( std::string_view json,
std::string * error = nullptr )

Parse the plugin-side content capability manifest embedded in a built plugin/app bundle.

Schema: { "schema":"pulp.plugin-runtime.v1", "pluginId":"...", "content": { "capabilities":[...], "kinds":[...], "reload": { "hotReloadKinds":[...], "manualRescanKinds":[...] } } }

◆ preview_content_pack_install()

ContentInstallPreview pulp::state::preview_content_pack_install ( const std::filesystem::path & input,
const ContentCapabilityManifest & plugin,
const std::filesystem::path & data_root = ContentRegistry::platform_data_root(),
const ContentInstallLimits & limits = {} )

Validate a local content-pack directory or .pulpcontent archive against a trusted plugin runtime manifest without copying any files.

This is the runtime-side backend for in-app "Install Content Pack..." and drag/drop review flows. An archive whose declared decompressed sizes exceed limits is refused from its central directory, before any entry is inflated.

◆ property_is_absent()

bool pulp::state::property_is_absent ( const PropertyValue & val)
inline

◆ serialized_state_version()

std::optional< uint32_t > pulp::state::serialized_state_version ( std::span< const uint8_t > source)
nodiscard

◆ stable_counting_sort()

template<typename It, typename Key, typename Value, typename Count>
bool pulp::state::stable_counting_sort ( It first,
It last,
Key key,
std::span< Value > scratch,
std::span< Count > counts )

Stable counting sort of [first, last) on a small non-negative integer key, O(n + counts.size()) and allocation-free, using caller-lent storage (typically sized once at prepare time).

Returns false, leaving the range untouched, when scratch is too small or some key falls outside [0, counts.size()); the caller then falls back to stable_sort_in_place.

◆ stable_sort_in_place()

template<typename It, typename Less>
void pulp::state::stable_sort_in_place ( It first,
It last,
Less less )

Sorts [first, last) by less, keeping equal elements in their original order, without allocating.

Requires random-access iterators.

◆ to_string()

const char * pulp::state::to_string ( ContentReloadPolicy policy)

◆ validate_base_offset()

BaseOffsetRefusal pulp::state::validate_base_offset ( BaseOffsetValue value,
float minimum,
float maximum )
inlinenoexcept

◆ validate_modulation_lane()

ModulationLaneValidation pulp::state::validate_modulation_lane ( const ModulationLane & lane)
inlinenoexcept

◆ value_from_host_normalized()

float pulp::state::value_from_host_normalized ( const ParamInfo & info,
double normalized )
inline

The plain value a host means by a normalized write.

A host sees a continuous parameter as continuous (no step count), so its value is kept exactly: range.step quantizes what a UI control emits, not host automation, and plain-value formats (AU, CLAP) store the same exact value. Discrete parameters still snap to their steps.

Hosts hand normalized values as doubles. A linear range is mapped in double precision and rounded once, so a host's own 0 dB on a -60..24 range lands on 0.0f rather than a single-precision (or fused multiply-add) residue such as 1.4e-6 dB – which is a gain of 1 + 1 ulp, and a failed null test.

Variable Documentation

◆ kAppliedQueueCapacity

std::size_t pulp::state::kAppliedQueueCapacity = 1024
inlineconstexpr

◆ kCommandQueueCapacity

std::size_t pulp::state::kCommandQueueCapacity = 1024
inlineconstexpr

◆ kLaneCount

std::uint8_t pulp::state::kLaneCount = 12
inlineconstexpr

◆ kPatternCount

std::uint8_t pulp::state::kPatternCount = 32
inlineconstexpr

◆ kStepCount

std::uint8_t pulp::state::kStepCount = 32
inlineconstexpr