MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RootNode.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#define MAX_PENDING_NODES 2048
6
7namespace MayaFlux::Nodes {
8
9class Node;
10
11/**
12 * @class RootNode
13 * @brief Container for top-level nodes in a processing channel with multi-modal support
14 *
15 * The RootNode serves as a collection point for multiple independent nodes
16 * that contribute to a single channel's output. Unlike regular nodes,
17 * a RootNode doesn't process data itself but rather manages and combines
18 * the outputs of its registered nodes.
19 *
20 * With multi-modal support, the RootNode can handle different processing rates
21 * (e.g., audio rate, visual rate, custom rates) in a single channel. This enables
22 * advanced scenarios where nodes with different processing requirements coexist.
23 *
24 * Each processing channel has its own RootNode, which collects and
25 * processes all nodes that should output to that channel. The RootNode
26 * processes all registered nodes and aggregates their outputs based on their
27 * assigned processing rates.
28 */
29class MAYAFLUX_API RootNode {
30public:
31 /**
32 * @brief Constructs a RootNode for a specific processing token and channel
33 * @param token The processing domain (e.g., AUDIO_RATE)
34 * @param channel The channel index (default: 0)
35 *
36 * Initializes the root node for the given processing domain and channel.
37 * Each channel and processing domain combination should have its own RootNode.
38 */
39 RootNode(ProcessingToken token = ProcessingToken::AUDIO_RATE, uint32_t channel = 0);
40
41 /**
42 * @brief Adds a node to this root node
43 * @param node The node to register
44 *
45 * Registered nodes will be processed when the root node's process()
46 * method is called, and their outputs will be combined together.
47 * If called during processing, the operation is deferred until safe.
48 */
49 void register_node(const std::shared_ptr<Node>& node);
50
51 /**
52 * @brief Removes a node from this root node
53 * @param node The node to unregister
54 *
55 * After unregistering, the node will no longer contribute to
56 * the root node's output. If called during processing, the operation
57 * is deferred until safe.
58 */
59 void unregister_node(const std::shared_ptr<Node>& node);
60
61 /** @brief Checks if the root node can process pending operations
62 * @return True if successful
63 *
64 * This method can be used to determine if the root node is in the middle
65 * of a processing cycle. If true, queued pending operations will be executed
66 */
67 bool preprocess();
68
69 /** @brief Performs post-processing after all nodes have been processed
70 *
71 * This method unregisters channel usage on the node, cleans up state
72 * and resets processing flags.
73 */
74 void postprocess();
75
76 /**
77 * @brief Processes a single sample from all registered nodes
78 * @return Combined output sample from all nodes
79 *
80 * This method processes each registered node and combines their outputs
81 * into a single sample. It is typically called in a loop to process
82 * multiple samples, but can also be used for single-sample processing.
83 */
84 double process_sample();
85
86 /**
87 * @brief Processes a single frame from all registered nodes
88 *
89 * This method processes each registered node for a single frame.
90 * It is useful in scenarios where frame-based processing is required,
91 * such as visual or animation data processing.
92 */
93 void process_frame();
94
95 /**
96 * @brief Processes all registered nodes and combines their outputs
97 * @param num_samples Number of samples to process
98 * @return Vector containing the combined output samples
99 *
100 * This method calls process_batch() on each registered node and
101 * aggregates their outputs together. The result is the combined output
102 * of all nodes registered with this root node.
103 * If nodes are added or removed during processing, those operations are
104 * deferred until after processing completes.
105 */
106 std::vector<double> process_batch(uint32_t num_samples);
107
108 /**
109 * @brief Processes multiple frames from all registered nodes
110 * @param num_frames Number of frames to process
111 *
112 * This method calls process_batch_frame() on each registered node
113 * for the specified number of frames. It is useful for scenarios
114 * requiring batch frame processing.
115 */
116 void process_batch_frame(uint32_t num_frames);
117
118 /**
119 * @brief Gets the number of nodes registered with this root node
120 * @return Number of registered nodes
121 */
122 inline unsigned int get_node_size() { return m_Nodes.size(); }
123
124 /**
125 * @brief Removes all nodes from this root node
126 *
127 * After calling this method, the root node will have no registered
128 * nodes and will output zero values.
129 */
130 inline void clear_all_nodes() { m_Nodes.clear(); }
131
132 /**
133 * @brief Gets the channel index associated with this root node
134 * @return The channel index
135 */
136 inline uint32_t get_channel() { return m_channel; }
137
138 /**
139 * @brief Gets the processing token associated with this root node
140 * @return The processing token (domain)
141 */
142 inline ProcessingToken get_token() { return m_token; }
143
144 /**
145 * @brief Terminates all nodes registered with this root node
146 *
147 * This method unregisters all node processing and stops
148 * active processing contexts but does not clear nodes
149 */
150 void terminate_all_nodes();
151
152 /**
153 * @brief Gets the list of nodes registered with this root node
154 * @return Vector of shared pointers to registered nodes
155 */
156 [[nodiscard]] const std::vector<std::shared_ptr<Node>>& nodes() const { return m_Nodes; }
157
158private:
159 /**
160 * @brief Collection of nodes registered with this root node
161 *
162 * All nodes in this collection will be processed when the root
163 * node's process() method is called.
164 */
165 std::vector<std::shared_ptr<Node>> m_Nodes;
166
167 /**
168 * @brief Flag indicating if the root node is currently processing nodes
169 *
170 * This atomic flag prevents concurrent modifications to the node collection
171 * during processing cycles. When set to true, any attempts to register or
172 * unregister nodes will be queued as pending operations rather than being
173 * executed immediately, ensuring thread safety and preventing data corruption
174 * during audio processing.
175 */
176 std::atomic<bool> m_is_processing;
177
178 /**
179 * @brief Flag to request termination of processing
180 *
181 * When set to true, this flag indicates that all processing
182 * should be terminated cleanly.
183 */
184 std::atomic<bool> m_request_terminate { false };
185
186 /**
187 * @brief Structure for storing pending node registration/unregistration operations
188 *
189 * When nodes need to be added or removed while the root node is processing,
190 * these operations are stored in this structure and executed later when it's
191 * safe to modify the node collection. This prevents race conditions and ensures
192 * consistent audio processing without interruptions.
193 */
194 struct PendingOp {
195 /**
196 * @brief Flag indicating if this pending operation slot is in use
197 */
198 std::atomic<bool> active;
199
200 /**
201 * @brief The node to be registered or unregistered
202 */
203 std::shared_ptr<Node> node;
204
205 bool is_addition { true };
206 } m_pending_ops[MAX_PENDING_NODES];
207
208 /**
209 * @brief Counter tracking the number of pending operations
210 *
211 * This counter helps efficiently manage the pending operations array,
212 * allowing the system to quickly determine if there are operations
213 * waiting to be processed without scanning the entire array.
214 */
215 std::atomic<uint32_t> m_pending_count;
216
217 /**
218 * @brief Processes any pending node registration/unregistration operations
219 *
220 * This method is called after the processing cycle completes to handle any
221 * node registration or unregistration requests that came in during processing.
222 * It ensures that node collection modifications happen safely between
223 * processing cycles, maintaining audio continuity while allowing dynamic
224 * changes to the node graph.
225 */
226 void process_pending_operations();
227
228 /**
229 * @brief The processing channel index for this root node
230 *
231 * Each root node is associated with a specific processing channel,
232 * allowing multiple channels to coexist with their own independent
233 * node collections and processing logic.
234 */
235 uint32_t m_channel;
236
237 /**
238 * @brief Flag indicating whether to skip preprocessing and post processing
239 *
240 * This flag can be set to true to skip the pre and post processing steps,
241 * which is useful in scenarios where the root node is not expected
242 * to sync processing state with other channels or is used outside of the
243 * Engine context.
244 */
246
247 /**
248 * @brief The processing token indicating the domain of this root node
249 *
250 * This token specifies the type of processing this root node is responsible for,
251 * such as audio rate, visual rate, or custom processing rates.
252 */
254};
255
256}
#define MAX_PENDING_NODES
Definition RootNode.hpp:5
std::vector< std::shared_ptr< Node > > m_Nodes
Collection of nodes registered with this root node.
Definition RootNode.hpp:165
uint32_t m_channel
The processing channel index for this root node.
Definition RootNode.hpp:235
uint32_t get_channel()
Gets the channel index associated with this root node.
Definition RootNode.hpp:136
void clear_all_nodes()
Removes all nodes from this root node.
Definition RootNode.hpp:130
std::atomic< bool > m_is_processing
Flag indicating if the root node is currently processing nodes.
Definition RootNode.hpp:176
bool m_skip_state_management
Flag indicating whether to skip preprocessing and post processing.
Definition RootNode.hpp:245
std::atomic< uint32_t > m_pending_count
Counter tracking the number of pending operations.
Definition RootNode.hpp:215
unsigned int get_node_size()
Gets the number of nodes registered with this root node.
Definition RootNode.hpp:122
const std::vector< std::shared_ptr< Node > > & nodes() const
Gets the list of nodes registered with this root node.
Definition RootNode.hpp:156
ProcessingToken m_token
The processing token indicating the domain of this root node.
Definition RootNode.hpp:253
ProcessingToken get_token()
Gets the processing token associated with this root node.
Definition RootNode.hpp:142
Container for top-level nodes in a processing channel with multi-modal support.
Definition RootNode.hpp:29
ProcessingToken
Enumerates the different processing domains for nodes.
Contains the node-based computational processing system components.
Definition Chronie.hpp:14
void register_node(const std::shared_ptr< Nodes::Node > &node, const Nodes::ProcessingToken &token, uint32_t channel)
Definition Graph.cpp:123
void unregister_node(const std::shared_ptr< Nodes::Node > &node, const Nodes::ProcessingToken &token, uint32_t channel)
Removes a node from the root node of specified channels.
Definition Graph.cpp:84
std::shared_ptr< Node > node
The node to be registered or unregistered.
Definition RootNode.hpp:203
std::atomic< bool > active
Flag indicating if this pending operation slot is in use.
Definition RootNode.hpp:198
Structure for storing pending node registration/unregistration operations.
Definition RootNode.hpp:194