82 float apply(
float value)
const {
83 if (!std::isfinite(value))
88 const float t = std::clamp((value -
in_min) / span, 0.0f, 1.0f);
111 && pattern.find(
'\0') == std::string_view::npos;
117 return pattern.find_first_of(
"*?[{") != std::string_view::npos;
132 Command cmd{Command::Set, id, clamp_scale(scale), {}};
133 if (!store_pattern(cmd.pattern, pattern))
135 return commands_.try_push(cmd);
145 commands_.try_push(Command{Command::Arm, id, clamp_scale(scale), {}});
150 commands_.try_push(Command{Command::Clear, id,
OscMapScale{}, {}});
158 while (commands_.try_pop(cmd)) {
161 insert(std::string_view{cmd.pattern.data()}, cmd.id, cmd.scale);
165 learn_target_ = cmd.id;
166 learn_scale_ = cmd.scale;
169 remove_target(cmd.id);
183 template <
typename Apply>
184 void route(std::string_view address,
float value, Apply&& apply) {
186 insert(address, learn_target_, learn_scale_);
187 learn_armed_ =
false;
189 for (std::size_t i = 0; i < count_; ++i) {
190 const auto& m = map_[i];
191 if (matches(m, address))
192 apply(m.id, m.scale.apply(value));
209 if (!numeric_argument(msg, value))
228 using Pattern = std::array<char, kOscPatternCapacity>;
231 enum Type : std::uint8_t { Set, Arm, Clear } type;
245 static bool numeric_argument(
const Message& msg,
float& out) {
246 if (msg.args.empty())
248 if (
const auto* f = std::get_if<float>(&msg.args[0])) {
252 if (
const auto* i = std::get_if<std::int32_t>(&msg.args[0])) {
253 out =
static_cast<float>(*i);
259 static OscMapScale clamp_scale(OscMapScale scale) {
263 std::isfinite(
scale.out_min) ? std::clamp(
scale.out_min, 0.0f, 1.0f) : 0.0f;
265 std::isfinite(
scale.out_max) ? std::clamp(
scale.out_max, 0.0f, 1.0f) : 1.0f;
269 static bool store_pattern(Pattern& dest, std::string_view pattern) {
273 std::memcpy(dest.data(), pattern.data(), pattern.size());
277 static bool matches(
const Mapping& m, std::string_view address) {
278 const std::string_view pattern{
m.pattern.data()};
285 for (std::size_t i = 0;
i < count_; ++
i) {
286 if (std::string_view{map_[
i].pattern.data()} == pattern) {
294 Mapping&
m = map_[count_];
295 if (!store_pattern(
m.pattern, pattern))
305 for (std::size_t i = 0;
i < count_; ++
i)
306 if (map_[i].
id !=
id)
311 std::array<Mapping, kMaxMappings> map_{};
312 std::size_t count_ = 0;
313 bool learn_armed_ =
false;
315 OscMapScale learn_scale_{};
316 pulp::runtime::SpscQueue<Command, 64> commands_;
Definition osc_parameter_map.hpp:98
void route(std::string_view address, float value, Apply &&apply)
Route one address / value pair to a caller-supplied sink.
Definition osc_parameter_map.hpp:184
bool set_mapping(std::string_view pattern, pulp::state::ParamID id, OscMapScale scale)
Bind pattern → parameter through scale.
Definition osc_parameter_map.hpp:131
bool set_mapping(std::string_view pattern, pulp::state::ParamID id)
Bind pattern → parameter over the full normalized range, treating the surface as sending 0....
Definition osc_parameter_map.hpp:124
static bool pattern_fits(std::string_view pattern)
True if pattern can be held verbatim in a mapping's fixed-capacity, NUL-terminated storage.
Definition osc_parameter_map.hpp:109
void arm_learn(pulp::state::ParamID id, OscMapScale scale)
Arm learn: the next incoming address binds to id through scale.
Definition osc_parameter_map.hpp:144
void handle_message(pulp::state::StateStore &store, const Message &msg)
Route one OSC message, taking its first numeric argument as the value.
Definition osc_parameter_map.hpp:207
void clear(pulp::state::ParamID id)
Remove every mapping that targets id.
Definition osc_parameter_map.hpp:149
void arm_learn(pulp::state::ParamID id)
Arm learn: the next incoming address binds to id over the full range.
Definition osc_parameter_map.hpp:139
void handle_value(pulp::state::StateStore &store, std::string_view address, float value)
Route one address / value pair into store from a control thread.
Definition osc_parameter_map.hpp:197
std::size_t mapping_count() const
Number of installed mappings, up to kMaxMappings; further bindings are dropped.
Definition osc_parameter_map.hpp:223
static bool is_wildcard(std::string_view pattern)
True if pattern uses OSC wildcard syntax and must therefore be matched with address_matches rather th...
Definition osc_parameter_map.hpp:116
void pump()
Drain queued UI commands. Call before dispatching a batch of messages.
Definition osc_parameter_map.hpp:156
static constexpr std::size_t kMaxMappings
Largest number of simultaneous bindings.
Definition osc_parameter_map.hpp:101
bool learn_armed() const
True while an armed learn is still waiting for an address.
Definition osc_parameter_map.hpp:217
Centralized parameter storage with lock-free value access.
Definition store.hpp:164
void set_normalized(ParamID id, float normalized)
Write a parameter from a normalized [0, 1] value (lock-free).
@ f
Definition pitch.hpp:25
bool address_matches(std::string_view pattern, std::string_view address)
OSC address pattern matching per OSC 1.0 spec.
constexpr std::size_t kOscPatternCapacity
Longest OSC address pattern a mapping can hold, including the terminator.
Definition osc_parameter_map.hpp:96
@ i
Definition formant_filter_bank.hpp:20
void scale(const float *a, float scalar, float *dst, std::size_t count) noexcept
uint32_t ParamID
Unique parameter identifier, stable across plugin versions.
Definition parameter.hpp:55
@ m
Definition input_events.hpp:40
@ w
Definition input_events.hpp:41
std::string address
Definition osc.hpp:40
The incoming value range an OSC surface sends, and the normalized [0, 1] window it drives.
Definition osc_parameter_map.hpp:72
float out_min
Definition osc_parameter_map.hpp:75
float in_max
Definition osc_parameter_map.hpp:74
float apply(float value) const
Map a raw OSC argument onto this window.
Definition osc_parameter_map.hpp:82
float out_max
Definition osc_parameter_map.hpp:76
float in_min
Definition osc_parameter_map.hpp:73