MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RootNode.cpp
Go to the documentation of this file.
1#include "RootNode.hpp"
2
4
5namespace MayaFlux::Nodes {
6
7RootNode::RootNode(ProcessingToken token, uint32_t channel)
8 : m_is_processing(false)
9 , m_channel(channel)
10 , m_skip_state_management(false)
11 , m_token(token)
12{
13}
14
16{
17 while (!m_pending_ops.push(std::move(op))) {
18 bool expected = false;
19 if (m_is_processing.compare_exchange_strong(expected, true,
20 std::memory_order_acquire, std::memory_order_relaxed)) {
22 m_is_processing.store(false, std::memory_order_release);
23 m_is_processing.notify_all();
24 } else {
25 std::this_thread::yield();
26 }
27 }
28}
29
30void RootNode::register_node(const std::shared_ptr<Node>& node)
31{
32 if (!node)
33 return;
34
37
38 enqueue_operation({ node, true });
39}
40
41void RootNode::unregister_node(const std::shared_ptr<Node>& node)
42{
43 if (!node)
44 return;
45
47
48 enqueue_operation({ node, false });
49}
50
52{
54 return true;
55
56 bool expected = false;
57 if (m_request_terminate.load(std::memory_order_acquire)) {
58 return false;
59 }
60
61 if (!m_is_processing.compare_exchange_strong(expected, true,
62 std::memory_order_acquire, std::memory_order_relaxed)) {
63 return false;
64 }
65
66 if (m_pending_ops.has_pending()) {
68 }
69
70 return true;
71}
72
74{
75 if (!preprocess())
76 return 0.;
77
78 auto sample = 0.;
79
80 for (auto& node : m_Nodes) {
81 if (!node)
82 continue;
83
84 uint32_t state = node->m_state.load();
85 double node_output = 0.0;
86
87 if (!(state & NodeState::PROCESSED)) {
88 node_output = node->process_sample();
90 } else {
91 node_output = node->get_last_output();
92 }
93
94 if (node->is_output_excluded_from_graph()) {
95 continue;
96 }
97
98 if (node->needs_channel_routing()) {
99 node_output *= node->get_routing_state().amount[m_channel];
100 }
101
102 sample += node_output;
103 }
104
105 postprocess();
106
107 return sample;
108}
109
111{
112 if (!preprocess())
113 return;
114
115 for (auto& node : m_Nodes) {
116 uint32_t state = node->m_state.load();
117 if (!(state & NodeState::PROCESSED)) {
118 node->process_sample();
120 }
121 }
122
123 postprocess();
124}
125
127{
129 return;
130
131 for (auto& node : m_Nodes) {
132 node->request_reset_from_channel(m_channel);
133 }
134
135 if (m_pending_ops.has_pending()) {
137 }
138
139 m_is_processing.store(false, std::memory_order_release);
140 m_is_processing.notify_all();
141
142 if (m_request_terminate.load(std::memory_order_acquire)) {
144 }
145}
146
147std::vector<double> RootNode::process_batch(uint32_t num_samples)
148{
149 std::vector<double> output(num_samples);
150
151 for (unsigned int i = 0; i < num_samples; i++) {
152 output[i] = process_sample();
153 }
154 return output;
155}
156
157void RootNode::process_batch_frame(uint32_t num_frames)
158{
159 for (uint32_t i = 0; i < num_frames; i++) {
161 }
162}
163
165{
166 m_pending_ops.drain([this](PendingOp&& op) {
167 if (op.is_addition) {
168 if (m_Nodes.end() == std::ranges::find(m_Nodes, op.node)) {
169 m_Nodes.push_back(op.node);
170 uint32_t state = op.node->m_state.load();
171 state &= ~static_cast<uint32_t>(NodeState::INACTIVE);
172 state |= static_cast<uint32_t>(NodeState::ACTIVE);
173 atomic_set_flag_strong(op.node->m_state, static_cast<NodeState>(state));
174 }
175 } else {
176 auto it = std::ranges::find(m_Nodes, op.node);
177 if (it != m_Nodes.end()) {
178 m_Nodes.erase(it);
179 }
180 op.node->reset_processed_state();
181 uint32_t state = op.node->m_state.load();
182 state &= ~static_cast<uint32_t>(NodeState::PENDING_REMOVAL);
183 state &= ~static_cast<uint32_t>(NodeState::ACTIVE);
184 state |= static_cast<uint32_t>(NodeState::INACTIVE);
185 atomic_set_flag_strong(op.node->m_state, static_cast<NodeState>(state));
186 }
187 });
188}
189
190void RootNode::terminate_all_nodes()
191{
192 m_request_terminate.store(true, std::memory_order_release);
193
194 m_is_processing.store(false, std::memory_order_release);
195
196 const auto nodes = m_Nodes;
197 for (const auto& node : nodes) {
198 unregister_node(node);
199 }
200
201 process_pending_operations();
202}
203
204}
void process_pending_operations()
Processes any pending node registration/unregistration operations.
Definition RootNode.cpp:164
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
void enqueue_operation(PendingOp &&op)
Queues an operation, draining on the caller's behalf when the queue is full.
Definition RootNode.cpp:15
uint32_t m_channel
The processing channel index for this root node.
Definition RootNode.hpp:236
RootNode(ProcessingToken token=ProcessingToken::AUDIO_RATE, uint32_t channel=0)
Constructs a RootNode for a specific processing token and channel.
Definition RootNode.cpp:7
void unregister_node(const std::shared_ptr< Node > &node)
Removes a node from this root node.
Definition RootNode.cpp:41
void process_frame()
Processes a single frame from all registered nodes.
Definition RootNode.cpp:110
bool preprocess()
Checks if the root node can process pending operations.
Definition RootNode.cpp:51
void register_node(const std::shared_ptr< Node > &node)
Adds a node to this root node.
Definition RootNode.cpp:30
std::atomic< bool > m_is_processing
Flag indicating if the root node is currently processing nodes.
Definition RootNode.hpp:177
double process_sample()
Processes a single sample from all registered nodes.
Definition RootNode.cpp:73
bool m_skip_state_management
Flag indicating whether to skip preprocessing and post processing.
Definition RootNode.hpp:246
void process_batch_frame(uint32_t num_frames)
Processes multiple frames from all registered nodes.
Definition RootNode.cpp:157
std::atomic< bool > m_request_terminate
Flag to request termination of processing.
Definition RootNode.hpp:185
void postprocess()
Performs post-processing after all nodes have been processed.
Definition RootNode.cpp:126
std::vector< double > process_batch(uint32_t num_samples)
Processes all registered nodes and combines their outputs.
Definition RootNode.cpp:147
NodeState
Represents the processing state of a node in the audio graph.
Definition NodeSpec.hpp:43
@ PROCESSED
Node has been processed this cycle.
Definition NodeSpec.hpp:49
@ ACTIVE
Engine is processing this node.
Definition NodeSpec.hpp:45
@ INACTIVE
Engine is not processing this node.
Definition NodeSpec.hpp:44
@ PENDING_REMOVAL
Node is marked for removal.
Definition NodeSpec.hpp:46
ProcessingToken
Enumerates the different processing domains for nodes.
void atomic_remove_flag(std::atomic< NodeState > &state, NodeState flag)
Atomically removes a flag from a node state.
void atomic_set_flag_strong(std::atomic< NodeState > &flag, const NodeState &desired)
Atomically sets a node state flag to a specific value.
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.
Definition Chronie.hpp:14
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
Structure for storing pending node registration/unregistration operations.
Definition RootNode.hpp:195