MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
NodeUtils.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "NodeSpec.hpp"
4
5namespace MayaFlux::Nodes {
6
7class Node;
8class NodeContext;
9
10/**
11 * @typedef TypedHook
12 * @brief Callback function type for node processing events, parameterised on context type.
13 *
14 * Defaults to NodeContext so existing code is unaffected. Concrete node classes
15 * specialise this with their own context type for their domain-specific callbacks,
16 * eliminating the need for callers to cast inside the lambda.
17 *
18 * Example (base interface):
19 * ```cpp
20 * node->on_tick([](NodeContext& ctx) { ... });
21 * ```
22 * Example (concrete node):
23 * ```cpp
24 * phasor->on_phase_wrap([](GeneratorContext& ctx) { ... });
25 * ```
26 */
27template <typename ContextT = NodeContext>
28using TypedHook = std::function<void(ContextT&)>;
29
30/**
31 * @typedef NodeHook
32 * @brief Alias for TypedHook<NodeContext>.
33 *
34 * Preserved for backward compatibility. All existing NodeHook usage continues
35 * to compile without changes. Migrate incrementally to TypedHook<ConcreteContext>
36 * on a per-class basis.
37 */
39
40/**
41 * @typedef NodeCondition
42 * @brief Predicate function type for conditional callbacks.
43 *
44 * Evaluated each tick; the paired callback fires only when this returns true.
45 *
46 * Example:
47 * ```cpp
48 * node->on_tick_if(
49 * [](NodeContext& ctx) { return ctx.value > 0.8; },
50 * [](NodeContext& ctx) { ... }
51 * );
52 * ```
53 */
54using NodeCondition = std::function<bool(NodeContext&)>;
55
56/**
57 * @brief Returns true if an equivalent callback is already present in the collection.
58 *
59 * Equivalence is determined by target_type() -- the same limitation as std::function
60 * comparison everywhere in the codebase.
61 */
62template <typename ContextT>
63bool callback_exists(const std::vector<TypedHook<ContextT>>& callbacks,
64 const TypedHook<ContextT>& callback)
65{
66 return std::ranges::any_of(callbacks,
67 [&callback](const TypedHook<ContextT>& hook) {
68 return hook.target_type() == callback.target_type();
69 });
70}
71
72/**
73 * @brief Adds a callback to the collection if an equivalent one is not already present.
74 * @return True if added, false if a duplicate was detected.
75 */
76template <typename ContextT>
77bool safe_add_callback(std::vector<TypedHook<ContextT>>& callbacks,
78 const TypedHook<ContextT>& callback)
79{
80 if (!callback_exists(callbacks, callback)) {
81 callbacks.push_back(callback);
82 return true;
83 }
84 return false;
85}
86
87/**
88 * @brief Removes all callbacks whose target_type() matches that of the supplied callback.
89 * @return True if at least one entry was removed.
90 */
91template <typename ContextT>
92bool safe_remove_callback(std::vector<TypedHook<ContextT>>& callbacks,
93 const TypedHook<ContextT>& callback)
94{
95 bool removed = false;
96 auto it = callbacks.begin();
97 while (it != callbacks.end()) {
98 if (it->target_type() == callback.target_type()) {
99 it = callbacks.erase(it);
100 removed = true;
101 } else {
102 ++it;
103 }
104 }
105 return removed;
106}
107
108/**
109 * @brief Returns true if a condition function is already present in a conditional callback collection.
110 */
112 const std::vector<std::pair<NodeHook, NodeCondition>>& callbacks,
113 const NodeCondition& callback);
114
115/**
116 * @brief Returns true if the exact callback+condition pair is already present.
117 */
119 const std::vector<std::pair<NodeHook, NodeCondition>>& callbacks,
120 const NodeHook& callback,
121 const NodeCondition& condition);
122
123/**
124 * @brief Adds a conditional callback if the exact pair is not already present.
125 * @return True if added, false if a duplicate was detected.
126 */
128 std::vector<std::pair<NodeHook, NodeCondition>>& callbacks,
129 const NodeHook& callback,
130 const NodeCondition& condition);
131
132/**
133 * @brief Removes all conditional callbacks whose condition target_type() matches.
134 * @return True if at least one entry was removed.
135 */
137 std::vector<std::pair<NodeHook, NodeCondition>>& callbacks,
138 const NodeCondition& callback);
139
140/**
141 * @brief Atomically sets a node state flag with strong memory ordering
142 * @param flag The atomic node state to modify
143 * @param expected The expected current state value
144 * @param desired The desired new state value
145 *
146 * This function safely updates a node's state, ensuring that state transitions
147 * are consistent across the audio processing graph. Node states track important
148 * conditions like whether a node is active, processed, or pending removal,
149 * which are critical for coordinating audio signal flow.
150 */
151void atomic_set_strong(std::atomic<NodeState>& flag, NodeState& expected, const NodeState& desired);
152
153/**
154 * @brief Atomically sets a node state flag to a specific value
155 * @param flag The atomic node state to modify
156 * @param desired The desired new state value
157 *
158 * Forcefully updates a node's state to a specific value. This is used when
159 * the node needs to be placed into a definitive state regardless of its
160 * current condition, such as when activating or deactivating nodes in the
161 * audio processing chain.
162 */
163void atomic_set_flag_strong(std::atomic<NodeState>& flag, const NodeState& desired);
164
165/**
166 * @brief Atomically adds a flag to a node state
167 * @param state The atomic node state to modify
168 * @param flag The flag to add to the state
169 *
170 * Adds a specific state flag to a node's state without affecting other state flags.
171 * This is used to mark nodes with specific conditions (like PROCESSED or ACTIVE)
172 * while preserving other aspects of the node's current state.
173 */
174void atomic_add_flag(std::atomic<NodeState>& state, NodeState flag);
175
176/**
177 * @brief Atomically removes a flag from a node state
178 * @param state The atomic node state to modify
179 * @param flags The flags to remove from the state
180 *
181 * Removes specific state flags from a node's state. This is commonly used to
182 * clear processing markers after a node has been processed, or to remove
183 * special states like PENDING_REMOVAL when they're no longer applicable.
184 */
185void atomic_remove_flag(std::atomic<NodeState>& state, NodeState flags);
186
187/**
188 * @brief Atomically sets a node state flag with weak memory ordering
189 * @param flag The atomic node state to modify
190 * @param expected The expected current state value
191 * @param desired The desired new state value
192 *
193 * A performance-optimized version of state setting that's used in less
194 * critical paths of the audio engine. This helps maintain node state
195 * consistency while potentially improving performance in high-throughput
196 * audio processing scenarios.
197 */
198void atomic_set_flag_weak(std::atomic<NodeState>& flag, NodeState& expected, const NodeState& desired);
199
200/**
201 * @brief Atomically increments the modulator count by a specified amount
202 * @param count The atomic counter to increment
203 * @param amount The amount to increment by
204 *
205 * Increases a node's modulator count, which tracks how many other nodes are
206 * currently using this node as a modulation source. This count is crucial for
207 * determining when a node's processed state can be safely reset, preventing
208 * redundant processing while ensuring all dependent nodes receive the correct
209 * modulation values.
210 */
211void atomic_inc_modulator_count(std::atomic<uint32_t>& count, int amount);
212
213/**
214 * @brief Atomically decrements the modulator count by a specified amount
215 * @param count The atomic counter to decrement
216 * @param amount The amount to decrement by
217 *
218 * Decreases a node's modulator count when it's no longer being used as a
219 * modulation source by another node. When the count reaches zero, the node
220 * becomes eligible for state resets, allowing the audio engine to optimize
221 * processing and avoid redundant calculations in the signal chain.
222 */
223void atomic_dec_modulator_count(std::atomic<uint32_t>& count, int amount);
224
225/**
226 * @brief Attempts to reset the processed state of a node
227 * @param node The node whose processed state should be reset
228 *
229 * Evaluates whether a node's processed state can be safely reset based on its
230 * current modulator count and other conditions. This is essential for the audio
231 * engine's processing cycle, as it determines which nodes need to be recalculated
232 * in the next cycle and which can reuse their previous output values, balancing
233 * processing efficiency with signal accuracy.
234 */
235void try_reset_processed_state(std::shared_ptr<Node> node);
236
237/**
238 * @brief Extracts active channel list from a node's channel mask
239 * @param node Node to inspect (can be null)
240 * @param fallback_channel Channel to use if node has no active channels (default: 0)
241 * @return Vector of active channel indices
242 */
243std::vector<uint32_t> get_active_channels(const std::shared_ptr<Nodes::Node>& node, uint32_t fallback_channel = 0);
244
245/**
246 * @brief Extracts active channel list from a channel mask
247 * @param channel_mask Bitmask of active channels
248 * @param fallback_channel Channel to use if mask is 0 (default: 0)
249 * @return Vector of active channel indices
250 */
251std::vector<uint32_t> get_active_channels(uint32_t channel_mask, uint32_t fallback_channel = 0);
252
253/**
254 * @brief Updates the routing state for a node based on its current channel usage
255 * @param state The routing state to update
256 *
257 * This function evaluates the current channel usage of a node and updates the
258 * routing state accordingly. It manages transitions between different routing
259 * phases (such as fade-in and fade-out(Active)) based on changes in channel counts,
260 * ensuring smooth audio output during dynamic reconfigurations of the processing graph.
261 */
262void update_routing_state(RoutingState& state);
263
264}
Eigen::Index count
Base context class for node callbacks.
Definition Node.hpp:30
TypedHook<> NodeHook
Alias for TypedHook<NodeContext>.
Definition NodeUtils.hpp:38
NodeState
Represents the processing state of a node in the audio graph.
Definition NodeSpec.hpp:43
bool callback_pair_exists(const std::vector< std::pair< NodeHook, NodeCondition > > &callbacks, const NodeHook &callback, const NodeCondition &condition)
Returns true if the exact callback+condition pair is already present.
Definition NodeUtils.cpp:15
void atomic_add_flag(std::atomic< NodeState > &state, NodeState flag)
Atomically adds a flag to a node state.
Definition NodeUtils.cpp:60
bool safe_remove_conditional_callback(std::vector< std::pair< NodeHook, NodeCondition > > &callbacks, const NodeCondition &callback)
Removes all conditional callbacks whose condition target_type() matches.
Definition NodeUtils.cpp:32
bool callback_exists(const std::vector< TypedHook< ContextT > > &callbacks, const TypedHook< ContextT > &callback)
Returns true if an equivalent callback is already present in the collection.
Definition NodeUtils.hpp:63
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_set_strong(std::atomic< NodeState > &flag, NodeState &expected, const NodeState &desired)
Atomically sets a node state flag with strong memory ordering.
Definition NodeUtils.cpp:49
bool conditional_callback_exists(const std::vector< std::pair< NodeHook, NodeCondition > > &callbacks, const NodeCondition &callback)
Returns true if a condition function is already present in a conditional callback collection.
Definition NodeUtils.cpp:7
void try_reset_processed_state(std::shared_ptr< Node > node)
Attempts to reset the processed state of a node.
Definition NodeUtils.cpp:97
void atomic_inc_modulator_count(std::atomic< uint32_t > &count, int amount)
Atomically increments the modulator count by a specified amount.
Definition NodeUtils.cpp:87
std::function< void(ContextT &)> TypedHook
Callback function type for node processing events, parameterised on context type.
Definition NodeUtils.hpp:28
void atomic_remove_flag(std::atomic< NodeState > &state, NodeState flag)
Atomically removes a flag from a node state.
Definition NodeUtils.cpp:71
void atomic_set_flag_strong(std::atomic< NodeState > &flag, const NodeState &desired)
Atomically sets a node state flag to a specific value.
Definition NodeUtils.cpp:54
bool safe_remove_callback(std::vector< TypedHook< ContextT > > &callbacks, const TypedHook< ContextT > &callback)
Removes all callbacks whose target_type() matches that of the supplied callback.
Definition NodeUtils.hpp:92
std::function< bool(NodeContext &)> NodeCondition
Predicate function type for conditional callbacks.
Definition NodeUtils.hpp:54
void atomic_dec_modulator_count(std::atomic< uint32_t > &count, int amount)
Atomically decrements the modulator count by a specified amount.
Definition NodeUtils.cpp:92
bool safe_add_conditional_callback(std::vector< std::pair< NodeHook, NodeCondition > > &callbacks, const NodeHook &callback, const NodeCondition &condition)
Adds a conditional callback if the exact pair is not already present.
Definition NodeUtils.cpp:23
void atomic_set_flag_weak(std::atomic< NodeState > &flag, NodeState &expected, const NodeState &desired)
Atomically sets a node state flag with weak memory ordering.
Definition NodeUtils.cpp:82
void update_routing_state(RoutingState &state)
Updates the routing state for a node based on its current channel usage.
bool safe_add_callback(std::vector< TypedHook< ContextT > > &callbacks, const TypedHook< ContextT > &callback)
Adds a callback to the collection if an equivalent one is not already present.
Definition NodeUtils.hpp:77
Contains the node-based computational processing system components.
Definition Chronie.hpp:13