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