8 const std::vector<HookEntry>*
entries;
45 if (
m_head.load(std::memory_order_relaxed) ==
nullptr) {
50 const auto* entries =
m_head.load();
55 return {
this, entries };
60 return m_head.load() ==
nullptr;
70 for (
const auto& entry :
snapshot()) {
71 if (entry.condition && !(*entry.condition)(ctx)) {
81 while (!
m_retired.compare_exchange_weak(node->next, node)) {
118 auto next = std::make_unique<std::vector<HookEntry>>();
123 const bool changed = edit(*next);
124 bool swapped =
false;
126 const std::vector<HookEntry>* replacement = next->empty() ? nullptr : next.get();
127 const std::vector<HookEntry>* expected =
current;
128 swapped =
m_head.compare_exchange_strong(expected, replacement);
129 if (swapped && replacement) {
152 mutate([&](std::vector<HookEntry>& entries) {
153 entries.push_back(
HookEntry { id, &key, tag, params, hook, std::nullopt });
163 mutate([&](std::vector<HookEntry>& entries) {
164 const auto it = std::ranges::find_if(entries, [&](
const HookEntry& entry) {
165 return *entry.
key == key && entry.
params == params;
167 if (it != entries.end()) {
172 entries.push_back(
HookEntry { fresh, &key, tag, params, hook, std::nullopt });
181 mutate([&](std::vector<HookEntry>& entries) {
182 entries.push_back(
HookEntry { id, &key, tag, {}, hook, condition });
192 mutate([&](std::vector<HookEntry>& entries) {
193 const auto it = std::ranges::find_if(entries, [&](
const HookEntry& entry) {
194 return *entry.
key == key && entry.
condition && entry.
condition->target_type() == condition.target_type();
196 if (it != entries.end()) {
201 entries.push_back(
HookEntry { fresh, &key, tag, {}, hook, condition });
209 return mutate([
id](std::vector<HookEntry>& entries) {
210 return std::erase_if(entries, [
id](
const HookEntry& entry) {
return entry.
id == id; }) > 0;
216 return mutate([&](std::vector<HookEntry>& entries) {
217 return std::erase_if(entries, [&](
const HookEntry& entry) {
return *entry.
key == key; }) > 0;
223 return mutate([&](std::vector<HookEntry>& entries) {
224 const auto it = std::ranges::find_if(entries, [&](
const HookEntry& entry) {
return *entry.
key == key; });
225 if (it == entries.end()) {
235 return mutate([&](std::vector<HookEntry>& entries) {
236 return std::erase_if(entries, [&](
const HookEntry& entry) {
244 return mutate([tag](std::vector<HookEntry>& entries) {
245 return std::erase_if(entries, [tag](
const HookEntry& entry) {
return entry.
tag == tag; }) > 0;
251 mutate([](std::vector<HookEntry>& entries) {
252 if (entries.empty()) {
262 flag.compare_exchange_strong(expected, desired);
267 auto expected = flag.load();
268 flag.compare_exchange_strong(expected, desired);
277 }
while (!state.compare_exchange_weak(
current, desired,
278 std::memory_order_acq_rel,
279 std::memory_order_acquire));
288 }
while (!state.compare_exchange_weak(
current, desired,
289 std::memory_order_acq_rel,
290 std::memory_order_acquire));
295 flag.compare_exchange_weak(expected, desired);
300 count.fetch_add(amount, std::memory_order_relaxed);
305 count.fetch_sub(amount, std::memory_order_relaxed);
310 if (node && node->m_modulator_count.load(std::memory_order_relaxed) == 0) {
311 node->reset_processed_state();
315std::vector<uint32_t>
get_active_channels(
const std::shared_ptr<Nodes::Node>& node, uint32_t fallback_channel)
317 uint32_t channel_mask = node ? node->get_channel_mask().load() : 0;
325 if (channel_mask == 0) {
326 channels.push_back(fallback_channel);
329 if (channel_mask & (1ULL << channel)) {
342 double progress = 0.;
346 for (uint32_t ch = 0; ch < 32; ++ch) {
348 state.
amount[ch] = will_be_in ? 1.0 : 0.0;
354 for (uint32_t ch = 0; ch < 32; ch++) {
358 if (was_in && will_be_in) {
360 }
else if (was_in && !will_be_in) {
361 state.
amount[ch] = 1.0 - progress;
362 }
else if (!was_in && will_be_in) {
363 state.
amount[ch] = progress;
The entries of a list at one instant, kept alive while this object exists.
HookId add(NodeHook hook, const std::type_info &key, uint8_t tag=0, std::array< double, 2 > params={})
Appends a hook with no duplicate check and returns its id.
Snapshot snapshot() const
The current entries, held stable for the lifetime of the returned object.
bool remove_by_tag(uint8_t tag)
Removes every entry carrying this tag.
std::atomic< const std::vector< HookEntry > * > m_head
HookId add_conditional(NodeHook hook, NodeCondition condition, const std::type_info &key, uint8_t tag=0)
Appends a hook that fires only while condition holds.
bool remove_by_key(const std::type_info &key)
Removes every entry registered with this callable type.
bool mutate(const std::function< bool(std::vector< HookEntry > &)> &edit)
bool remove(HookId id)
Removes the registration with this id.
void retire(const std::vector< HookEntry > *old)
HookId add_conditional_unique(NodeHook hook, NodeCondition condition, const std::type_info &key, uint8_t tag=0)
As add_conditional, returning the existing id when the same hook and condition types exist.
void fire(NodeContext &ctx) const
Calls every entry whose condition, if any, holds.
bool remove_first_by_key(const std::type_info &key)
Removes the first entry registered with this callable type.
bool remove_by_condition_key(const std::type_info &key)
Removes every entry whose condition has this callable type.
std::atomic< Retired * > m_retired
HookId add_unique(NodeHook hook, const std::type_info &key, uint8_t tag=0, std::array< double, 2 > params={})
Appends unless an entry with the same key and params exists, in which case that entry's id is returne...
std::atomic< uint32_t > m_readers
Base context class for node callbacks.
void register_hook_list(HookList &list)
Base interface for all computational processing nodes.
TypedHook<> NodeHook
Alias for TypedHook<NodeContext>.
NodeState
Represents the processing state of a node in the audio graph.
void try_reset_processed_state(std::shared_ptr< Node > node)
Attempts to reset the processed state of a node.
void atomic_set_flag_weak(std::atomic< NodeState > &flag, NodeState &expected, const NodeState &desired)
Atomically sets a node state flag with weak memory ordering.
void atomic_inc_modulator_count(std::atomic< uint32_t > &count, int amount)
Atomically increments the modulator count by a specified amount.
constexpr uint32_t MAX_CHANNEL_COUNT
Hard limit imposed by uint32_t channel mask width.
uint64_t HookId
Identifies one registration inside a HookList.
void atomic_dec_modulator_count(std::atomic< uint32_t > &count, int amount)
Atomically decrements the modulator count by a specified amount.
void update_routing_state(RoutingState &state)
Updates the routing state for a node based on its current channel usage.
void atomic_set_strong(std::atomic< NodeState > &flag, NodeState &expected, const NodeState &desired)
Atomically sets a node state flag with strong memory ordering.
void atomic_remove_flag(std::atomic< NodeState > &state, NodeState flag)
Atomically removes a flag from a node state.
std::function< bool(NodeContext &)> NodeCondition
Predicate function type for conditional callbacks.
void atomic_set_flag_strong(std::atomic< NodeState > &flag, const NodeState &desired)
Atomically sets a node state flag to a specific value.
std::vector< uint32_t > get_active_channels(const std::shared_ptr< Nodes::Node > &node, uint32_t fallback_channel)
Extracts active channel list from a node's channel mask.
void atomic_add_flag(std::atomic< NodeState > &state, NodeState flag)
Atomically adds a flag to a node state.
Contains the node-based computational processing system components.
std::array< double, 2 > params
const std::type_info * key
std::optional< NodeCondition > condition
One registration held by a HookList.
const std::vector< HookEntry > * entries
enum MayaFlux::Nodes::RoutingState::Phase NONE
@ COMPLETED
Routing transition has completed.
Represents the state of routing transitions for a node.