Thread-safe atomic parameter value for lock-free audio/UI communication. More...
#include <parameter.hpp>
Public Types | |
| using | PackedIdentity = std::uint64_t |
| Packed base identity: low 32 bits are float bits, high 32 bits are a monotonic per-parameter revision. | |
| using | VersionedValue = PackedIdentity |
Public Member Functions | |
| ParamValue ()=default | |
| ParamValue (float initial) | |
| ParamValue (ParamValue &&other) noexcept | |
| ParamValue & | operator= (ParamValue &&other) noexcept |
| ParamValue (const ParamValue &other) | |
| ParamValue & | operator= (const ParamValue &other) |
| float | get () const |
| Read the current base value (lock-free, relaxed ordering). | |
| void | set (float v) noexcept |
| Write a new base value through the same bounded revision CAS as every other base-value writer. | |
| VersionedValue | versioned_value () const |
| std::uint64_t | committed_generation () const |
| Highest StateStore generation claimed or committed by a write to this parameter. | |
| bool | revision_available () const noexcept |
| bool | revisions_available (std::uint32_t writes) const noexcept |
| bool | set_versioned_if_newer (float value, std::uint64_t generation, std::uint32_t max_attempts) |
| Legacy generation-ordered writer retained for source compatibility. | |
| bool | set_packed_revisioned (float value, std::uint64_t generation, std::uint32_t max_attempts) noexcept |
| StateStore's ordinary base-value publication boundary. | |
| bool | compare_exchange_versioned (VersionedValue &expected, std::uint64_t expected_generation, float desired, std::uint64_t generation) |
| bool | compare_exchange_packed (VersionedValue &expected, float desired, std::uint64_t generation) |
| Conditional feedback publication boundary. | |
| float | get_modulated () const |
| Read the modulated value: base + mod_offset. | |
| float | get_mod_offset () const |
| BaseOffsetValue | get_base_offset () const noexcept |
| Read the explicit base-vs-offset pair used by every automation route. | |
| void | set_mod_offset (float offset) |
| Set the absolute modulation offset (replaces any existing offset). | |
| bool | set_mod_versioned_if_newer (float offset, std::uint64_t generation, std::uint32_t max_attempts) |
| void | add_mod_offset (float delta) |
| Add a delta to the current modulation offset (for stacking modulators). | |
| void | reset_mod () |
| Clear the modulation offset to zero. | |
| void | set_display_modulation (float plain) noexcept |
| The value a plugin's OWN modulator is playing for this parameter, in plain units, published for display only (StateStore:: set_display_modulation()). | |
| void | clear_display_modulation () noexcept |
| float | display_modulation () const noexcept |
| float | get_normalized (const ParamRange &range) const |
| Read the current value mapped to [0, 1] via the given range. | |
| void | set_normalized (float n, const ParamRange &range) |
| Write a normalized [0, 1] value, denormalized via the given range. | |
Static Public Member Functions | |
| static VersionedValue | make_versioned_value (float value, std::uint64_t revision) |
| static float | value_from_versioned (VersionedValue value) |
| static std::uint32_t | revision_from_versioned (VersionedValue value) |
Friends | |
| class | ParamValueTest |
Thread-safe atomic parameter value for lock-free audio/UI communication.
The audio thread reads and the UI thread writes via relaxed atomics. No locks, no allocation. Each parameter is independent, so relaxed ordering is correct — there is no dependency between reading param A and param B. For coherent multi-field reads (e.g., transport state), use SeqLock<T> instead.
| using pulp::state::ParamValue::PackedIdentity = std::uint64_t |
Packed base identity: low 32 bits are float bits, high 32 bits are a monotonic per-parameter revision.
The revision is not StateStore's global generation and never wraps.
|
default |
|
inlineexplicit |
| initial | Starting value for this parameter. |
|
inlinenoexcept |
|
inline |
|
inline |
Add a delta to the current modulation offset (for stacking modulators).
|
inlinenoexcept |
|
inline |
Highest StateStore generation claimed or committed by a write to this parameter.
It only ever rises. Ordinary generation-ordered writers claim it before publishing so an older paused writer cannot overwrite a newer one; conditional writers authorize on the packed identity and only raise it, so they never revoke a pending ordinary writer's claim.
|
inline |
Conditional feedback publication boundary.
Unlike the legacy generation API above, this compares only the exact packed identity and advances its per-parameter revision; the StateStore generation is diagnostic metadata and cannot participate in a split check/write.
|
inline |
|
inlinenoexcept |
|
inline |
Read the current base value (lock-free, relaxed ordering).
|
inlinenoexcept |
Read the explicit base-vs-offset pair used by every automation route.
|
inline |
|
inline |
Read the modulated value: base + mod_offset.
Used by the audio thread to get the final value after CLAP per-voice modulation.
|
inline |
Read the current value mapped to [0, 1] via the given range.
|
inlinestatic |
|
inline |
|
inlinenoexcept |
|
inline |
Clear the modulation offset to zero.
|
inlinenoexcept |
|
inlinestatic |
|
inlinenoexcept |
|
inlinenoexcept |
Write a new base value through the same bounded revision CAS as every other base-value writer.
A saturated revision is a terminal no-op.
|
inlinenoexcept |
The value a plugin's OWN modulator is playing for this parameter, in plain units, published for display only (StateStore:: set_display_modulation()).
NaN means nothing is published. Never read by DSP and never written to the host. Real-time safe.
|
inline |
Set the absolute modulation offset (replaces any existing offset).
|
inline |
|
inline |
Write a normalized [0, 1] value, denormalized via the given range.
|
inlinenoexcept |
StateStore's ordinary base-value publication boundary.
Ordinary writers are ordered by StateStore's global generation. Claim that generation before publishing the packed value; a writer that was paused after claiming an older generation must not overwrite a newer writer that has already published. Conditional feedback deliberately uses compare_exchange_packed() below instead, because its exact packed identity is the authorization token and the global generation is only diagnostic there.
|
inline |
Legacy generation-ordered writer retained for source compatibility.
StateStore uses set_packed_revisioned() instead; this split API is not suitable for conditional authorization.
|
inlinestatic |
|
inline |
|
friend |