MayaFlux 0.5.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_pending_count(0)
10 , m_channel(channel)
11 , m_skip_state_management(false)
12 , m_token(token)
13{
14}
15
16void RootNode::register_node(const std::shared_ptr<Node>& node)
17{
18 if (!node)
19 return;
20
21 for (auto& pending_op : m_pending_ops) {
22 bool expected = false;
23 if (pending_op.active.compare_exchange_strong(
24 expected, true,
25 std::memory_order_acquire,
26 std::memory_order_relaxed)) {
27 pending_op.node = node;
28 pending_op.is_addition = true;
31 m_pending_count.fetch_add(1, std::memory_order_relaxed);
32 return;
33 }
34 }
35
36 while (m_is_processing.load(std::memory_order_acquire))
37 m_is_processing.wait(true, std::memory_order_acquire);
38
39 if (m_Nodes.end() == std::ranges::find(m_Nodes, node)) {
40 m_Nodes.push_back(node);
42 atomic_add_flag(node->m_state, NodeState::ACTIVE);
43 }
44}
45
46void RootNode::unregister_node(const std::shared_ptr<Node>& node)
47{
48 if (!node)
49 return;
50
52
53 for (auto& pending_op : m_pending_ops) {
54 bool expected = false;
55 if (pending_op.active.compare_exchange_strong(
56 expected, true,
57 std::memory_order_acquire,
58 std::memory_order_relaxed)) {
59 pending_op.node = node;
60 pending_op.is_addition = false;
61 m_pending_count.fetch_add(1, std::memory_order_relaxed);
62 return;
63 }
64 }
65
66 while (m_is_processing.load(std::memory_order_acquire))
67 m_is_processing.wait(true, std::memory_order_acquire);
68
69 auto it = m_Nodes.begin();
70 while (it != m_Nodes.end()) {
71 if ((*it).get() == node.get()) {
72 it = m_Nodes.erase(it);
73 break;
74 }
75 ++it;
76 }
77
78 node->reset_processed_state();
79
80 uint32_t flag = node->m_state.load();
81 flag &= ~static_cast<uint32_t>(NodeState::PENDING_REMOVAL);
82 flag &= ~static_cast<uint32_t>(NodeState::ACTIVE);
83 flag |= static_cast<uint32_t>(NodeState::INACTIVE);
84 atomic_set_flag_strong(node->m_state, static_cast<NodeState>(flag));
85}
86
88{
90 return true;
91
92 bool expected = false;
93 if (m_request_terminate.load(std::memory_order_acquire)) {
94 return false;
95 }
96
97 if (!m_is_processing.compare_exchange_strong(expected, true,
98 std::memory_order_acquire, std::memory_order_relaxed)) {
99 return false;
100 }
101
102 if (m_pending_count.load(std::memory_order_relaxed) > 0) {
104 }
105
106 return true;
107}
108
110{
111 if (!preprocess())
112 return 0.;
113
114 auto sample = 0.;
115
116 for (auto& node : m_Nodes) {
117 if (!node)
118 continue;
119
120 uint32_t state = node->m_state.load();
121 double node_output = 0.0;
122
123 if (!(state & NodeState::PROCESSED)) {
124 if (node->should_mock_process()) {
125 node->process_sample();
126 } else {
127 node_output = node->process_sample();
128 }
130 } else {
131 node_output = node->get_last_output();
132 }
133
134 if (node->needs_channel_routing()) {
135 node_output *= node->get_routing_state().amount[m_channel];
136 }
137
138 sample += node_output;
139 }
140
141 postprocess();
142
143 return sample;
144}
145
147{
148 if (!preprocess())
149 return;
150
151 for (auto& node : m_Nodes) {
152 uint32_t state = node->m_state.load();
153 if (!(state & NodeState::PROCESSED)) {
154 node->process_sample();
156 }
157 }
158
159 postprocess();
160}
161
163{
165 return;
166
167 for (auto& node : m_Nodes) {
168 node->request_reset_from_channel(m_channel);
169 }
170
171 if (m_pending_count.load(std::memory_order_relaxed) > 0) {
173 }
174
175 m_is_processing.store(false, std::memory_order_release);
176 m_is_processing.notify_all();
177
178 if (m_request_terminate.load(std::memory_order_acquire)) {
180 }
181}
182
183std::vector<double> RootNode::process_batch(uint32_t num_samples)
184{
185 std::vector<double> output(num_samples);
186
187 for (unsigned int i = 0; i < num_samples; i++) {
188 output[i] = process_sample();
189 }
190 return output;
191}
192
193void RootNode::process_batch_frame(uint32_t num_frames)
194{
195 for (uint32_t i = 0; i < num_frames; i++) {
197 }
198}
199
201{
202 for (auto& pending_op : m_pending_ops) {
203 if (!pending_op.active.load(std::memory_order_acquire))
204 continue;
205
206 auto& op = pending_op;
207
208 if (op.is_addition) {
209 if (m_Nodes.end() == std::ranges::find(m_Nodes, op.node)) {
210 m_Nodes.push_back(op.node);
211 uint32_t state = op.node->m_state.load();
212 state &= ~static_cast<uint32_t>(NodeState::INACTIVE);
213 state |= static_cast<uint32_t>(NodeState::ACTIVE);
214 atomic_set_flag_strong(op.node->m_state, static_cast<NodeState>(state));
215 }
216 } else {
217 auto it = m_Nodes.begin();
218 while (it != m_Nodes.end()) {
219 if ((*it).get() == op.node.get()) {
220 it = m_Nodes.erase(it);
221 break;
222 }
223 ++it;
224 }
225 op.node->reset_processed_state();
226 uint32_t state = op.node->m_state.load();
227 state &= ~static_cast<uint32_t>(NodeState::PENDING_REMOVAL);
228 state &= ~static_cast<uint32_t>(NodeState::ACTIVE);
229 state |= static_cast<uint32_t>(NodeState::INACTIVE);
230 atomic_set_flag_strong(op.node->m_state, static_cast<NodeState>(state));
231 }
232
233 op.node.reset();
234 op.active.store(false, std::memory_order_release);
235 m_pending_count.fetch_sub(1, std::memory_order_relaxed);
236 }
237}
238
240{
241 m_request_terminate.store(true, std::memory_order_release);
242
243 m_is_processing.store(false, std::memory_order_release);
244
245 for (auto& node : m_Nodes) {
246 unregister_node(node);
247 }
248
250}
251
252}
std::shared_ptr< Core::VKImage > output
void process_pending_operations()
Processes any pending node registration/unregistration operations.
Definition RootNode.cpp:200
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
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:46
void process_frame()
Processes a single frame from all registered nodes.
Definition RootNode.cpp:146
bool preprocess()
Checks if the root node can process pending operations.
Definition RootNode.cpp:87
void register_node(const std::shared_ptr< Node > &node)
Adds a node to this root node.
Definition RootNode.cpp:16
std::atomic< bool > m_is_processing
Flag indicating if the root node is currently processing nodes.
Definition RootNode.hpp:176
double process_sample()
Processes a single sample from all registered nodes.
Definition RootNode.cpp:109
bool m_skip_state_management
Flag indicating whether to skip preprocessing and post processing.
Definition RootNode.hpp:245
void process_batch_frame(uint32_t num_frames)
Processes multiple frames from all registered nodes.
Definition RootNode.cpp:193
struct MayaFlux::Nodes::RootNode::PendingOp m_pending_ops[2048]
std::atomic< uint32_t > m_pending_count
Counter tracking the number of pending operations.
Definition RootNode.hpp:215
std::atomic< bool > m_request_terminate
Flag to request termination of processing.
Definition RootNode.hpp:184
void postprocess()
Performs post-processing after all nodes have been processed.
Definition RootNode.cpp:162
std::vector< double > process_batch(uint32_t num_samples)
Processes all registered nodes and combines their outputs.
Definition RootNode.cpp:183
void terminate_all_nodes()
Terminates all nodes registered with this root node.
Definition RootNode.cpp:239
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_add_flag(std::atomic< NodeState > &state, NodeState flag)
Atomically adds a flag to a node state.
Definition NodeUtils.cpp:60
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
Contains the node-based computational processing system components.
Definition Chronie.hpp:14