Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
external_binding.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <pulp/state/parameter.hpp> // ParamRange
7
8#include <cmath>
9#include <functional>
10#include <string>
11#include <utility>
12#include <vector>
13
14namespace pulp::state {
15
23 std::function<float()> get{};
25 std::function<void(float)> set{};
31 std::function<void()> begin_gesture{};
32 std::function<void()> end_gesture{};
34 std::string name{};
35 std::string unit{};
36};
37
56public:
57 using ChangeCallback = std::function<void(float new_value)>;
58
59 ExternalBinding() = default;
60
62 : cfg_(std::move(cfg)), last_polled_(cfg_.get ? cfg_.get() : 0.0f) {}
63
65 float get() const { return cfg_.get ? cfg_.get() : 0.0f; }
66
69 void set(float value) {
70 if (!cfg_.set) return;
71 const float old_value = get();
72 cfg_.set(value);
73 const float new_value = get();
74 if (std::abs(new_value - old_value) > 1e-7f) {
75 last_polled_ = new_value;
76 fire(new_value);
77 }
78 }
79
81 float get_normalized() const { return cfg_.range.normalize(get()); }
82
84 void set_normalized(float normalized) { set(cfg_.range.denormalize(normalized)); }
85
87 void begin_gesture() { if (cfg_.begin_gesture) cfg_.begin_gesture(); }
88 void end_gesture() { if (cfg_.end_gesture) cfg_.end_gesture(); }
89
91 void on_change(ChangeCallback cb) { callbacks_.push_back(std::move(cb)); }
92
95 bool poll() {
96 const float current = get();
97 if (std::abs(current - last_polled_) > 1e-7f) {
98 last_polled_ = current;
99 fire(current);
100 return true;
101 }
102 return false;
103 }
104
107 void notify() {
108 const float current = get();
109 last_polled_ = current;
110 fire(current);
111 }
112
114 void reset() { set(cfg_.range.default_value); }
115
116 const std::string& name() const { return cfg_.name; }
117 const std::string& unit() const { return cfg_.unit; }
118 const ParamRange& range() const { return cfg_.range; }
119
121 bool is_bound() const { return static_cast<bool>(cfg_.get); }
122
123private:
127 void fire(float value) {
128 if (firing_) return;
129 firing_ = true;
130 // Reset the guard even if a callback throws — a thrown host callback
131 // must not permanently wedge every future notification.
132 struct ResetOnExit {
133 bool& f;
134 ~ResetOnExit() { f = false; }
135 } reset_guard{firing_};
136
137 // Bounded reconciliation: a reentrant set()/notify() from inside a
138 // callback writes the real value through but has its own (nested) fire()
139 // suppressed by the guard. Without this loop, listeners would be left on
140 // the stale first value while last_polled_ already tracked the new one,
141 // so a later poll() could never correct them. Re-dispatch until the
142 // observed value stops moving (capped against a pathological oscillator).
143 float dispatched = value;
144 for (int pass = 0; pass < 8; ++pass) {
145 for (auto& cb : callbacks_) {
146 if (cb) cb(dispatched);
147 }
148 const float current = cfg_.get ? cfg_.get() : dispatched;
149 if (std::abs(current - dispatched) <= 1e-7f) break;
150 dispatched = current;
151 last_polled_ = current;
152 }
153 }
154
155 ExternalBindingConfig cfg_{};
156 float last_polled_ = 0.0f;
157 bool firing_ = false;
158 std::vector<ChangeCallback> callbacks_;
159};
160
161} // namespace pulp::state
float get() const
Read the current plain value.
Definition external_binding.hpp:65
void notify()
UI-thread accelerator: the host knows the external value changed and wants an immediate refresh witho...
Definition external_binding.hpp:107
void set_normalized(float normalized)
Write from a normalized [0, 1] value through the configured range.
Definition external_binding.hpp:84
const std::string & name() const
Definition external_binding.hpp:116
void begin_gesture()
Notify the host that a user gesture has begun / ended (optional).
Definition external_binding.hpp:87
std::function< void(float new_value)> ChangeCallback
Definition external_binding.hpp:57
bool poll()
Poll the source; fire on_change if it moved since the last observation.
Definition external_binding.hpp:95
void reset()
Reset to the range's default value and fire change callbacks.
Definition external_binding.hpp:114
ExternalBinding(ExternalBindingConfig cfg)
Definition external_binding.hpp:61
void end_gesture()
Definition external_binding.hpp:88
bool is_bound() const
True if a getter is configured (an unbound ExternalBinding reads 0).
Definition external_binding.hpp:121
const std::string & unit() const
Definition external_binding.hpp:117
float get_normalized() const
Read the value mapped to [0, 1] through the configured range.
Definition external_binding.hpp:81
void set(float value)
Write a new plain value.
Definition external_binding.hpp:69
const ParamRange & range() const
Definition external_binding.hpp:118
void on_change(ChangeCallback cb)
Register a callback that fires when the value changes via set/poll/notify.
Definition external_binding.hpp:91
@ pass
Definition validation_harness.hpp:20
SequencerStateChannel is the audio-safe transport for a plugin's structured NON-parameter state: the ...
Definition audio_device_manager.hpp:48
@ value
the widget's primary value (Knob, Fader, RangeSlider, Toggle, ProgressBar)
Definition binding_diagnostics.hpp:19
STL namespace.
Configuration for an ExternalBinding: the getter/setter that back a UI control whose value is NOT a S...
Definition external_binding.hpp:21
std::string unit
Definition external_binding.hpp:35
std::function< void(float)> set
Write a new plain value. Required for an editable control.
Definition external_binding.hpp:25
std::function< void()> end_gesture
Definition external_binding.hpp:32
std::string name
Display metadata for the widget (label / value formatting). Optional.
Definition external_binding.hpp:34
std::function< float()> get
Read the current plain (un-normalized) value. Required.
Definition external_binding.hpp:23
ParamRange range
Maps plain <-> normalized [0,1].
Definition external_binding.hpp:28
std::function< void()> begin_gesture
Optional host-undo gesture boundaries, called exactly like StateStore gestures around a drag/edit.
Definition external_binding.hpp:31
Defines the numeric range of a parameter, including normalization.
Definition parameter.hpp:131