15#include <unordered_map>
16#include <unordered_set>
38 std::string_view aax_id,
40 for (
const auto& binding : definition.
parameters) {
41 if (binding.aax_id == aax_id) {
68 return range.
denormalize(
static_cast<float>(normalized));
219 for (
const auto& binding : definition.
parameters) {
220 ids_.emplace(binding.id, binding.aax_id);
227 const auto it = ids_.find(
id);
228 return it == ids_.end() ? nullptr : &it->second;
232 std::unordered_map<state::ParamID, std::string> ids_;
307 using ValueReader = std::function<bool(
const char* aax_param_id,
float& out_value)>;
311 using ValueWriter = std::function<bool(
const char* aax_param_id,
float value)>;
323 : reader_(
std::move(reader))
324 , writer_(
std::move(writer))
326 params_.reserve(definition.
parameters.size());
327 for (
const auto& binding : definition.
parameters) {
328 params_.emplace(binding.id, Entry{binding.aax_id, binding.range});
335 const auto it = params_.find(
id);
336 if (it == params_.end()) {
339 Entry& entry = it->second;
341 float aax_value = 0.0f;
342 if (!reader_ || !reader_(entry.aax_id.c_str(), aax_value)) {
345 const bool already_agrees =
348 const bool write_is_a_no_op =
350 if (already_agrees || write_is_a_no_op) {
352 entry.consecutive_corrections = 0;
357 if (!entry.has_last_written || entry.last_written != store_value) {
358 entry.last_written = store_value;
359 entry.has_last_written =
true;
360 entry.consecutive_corrections = 0;
372 if (!entry.fuse_reported) {
373 entry.fuse_reported =
true;
375 "AAX mirror: parameter '{}' did not converge after {} corrective "
376 "writes of {}; AAX holds {}. Leaving the host authoritative.",
381 ++entry.consecutive_corrections;
383 return writer_ && writer_(entry.aax_id.c_str(), store_value);
397 const auto it = params_.find(
id);
398 return it != params_.end() &&
406 float last_written = 0.0f;
407 bool has_last_written =
false;
408 std::uint32_t consecutive_corrections = 0;
409 bool fuse_reported =
false;
412 std::unordered_map<state::ParamID, Entry> params_;
415 std::uint64_t suppressed_count_ = 0;
416 std::uint64_t refused_count_ = 0;
439 using Sink = std::function<void(
const char* aax_param_id)>;
443 , touch_(
std::move(touch))
450 const auto* aax_id = lookup(
id);
455 if (!touched_.insert(
id).second) {
458 if (touch_) touch_(aax_id->c_str());
465 const auto* aax_id = lookup(
id);
470 if (touched_.erase(
id) == 0) {
473 if (release_) release_(aax_id->c_str());
482 const std::unordered_set<state::ParamID> held = touched_;
483 for (
const auto id : held) {
502 const std::string* lookup(
state::ParamID id)
const {
return ids_.find(
id); }
507 std::unordered_set<state::ParamID> touched_;
508 std::uint64_t unknown_count_ = 0;
Centralized parameter storage with lock-free value access.
Definition store.hpp:164
void log_error(std::format_string< Args... > fmt, Args &&... args)
Definition log.hpp:195
uint32_t ParamID
Unique parameter identifier, stable across plugin versions.
Definition parameter.hpp:55
Defines the numeric range of a parameter, including normalization.
Definition parameter.hpp:131
float denormalize(float normalized) const
Map a normalized [0, 1] value back to the real range.
Definition parameter.hpp:188
float normalize(float value) const
Map a real value to the normalized [0, 1] range.
Definition parameter.hpp:168