MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
NodeCombine.cpp
Go to the documentation of this file.
1#include "NodeCombine.hpp"
2
4
6
7namespace MayaFlux::Nodes {
8
9BinaryOpContext::BinaryOpContext(double value, double lhs_value, double rhs_value)
10 : NodeContext(value)
11 , lhs_value(lhs_value)
12 , rhs_value(rhs_value)
13{
14}
15
16BinaryOpContextGpu::BinaryOpContextGpu(double value, double lhs_value, double rhs_value, std::span<const float> gpu_data)
17 : BinaryOpContext(value, lhs_value, rhs_value)
18 , GpuVectorData(gpu_data)
19{
20}
21
22CompositeOpContext::CompositeOpContext(double value, std::vector<double> input_values)
23 : NodeContext(value)
24 , input_values(std::move(input_values))
25{
26}
27
28CompositeOpContextGpu::CompositeOpContextGpu(double value, std::vector<double> input_values, std::span<const float> gpu_data)
29 : CompositeOpContext(value, std::move(input_values))
30 , GpuVectorData(gpu_data)
31{
32}
33
34BinaryOpNode::BinaryOpNode(const std::shared_ptr<Node>& lhs, const std::shared_ptr<Node>& rhs, CombineFunc func)
35 : m_lhs(lhs)
36 , m_rhs(rhs)
37 , m_func(std::move(func))
38 , m_context(0.0, 0.0, 0.0)
39 , m_context_gpu(0.0, 0.0, 0.0, get_gpu_data_buffer())
40{
41 if (!m_lhs || !m_rhs) {
42 error<std::invalid_argument>(
44 std::source_location::current(),
45 "BinaryOpNode requires both lhs and rhs nodes to be non-null");
46 }
47}
48
50 const std::shared_ptr<Node>& lhs,
51 const std::shared_ptr<Node>& rhs,
52 CombineFunc func,
53 NodeGraphManager& manager,
54 ProcessingToken token)
55 : BinaryOpNode(lhs, rhs, std::move(func))
56{
57 m_manager = &manager;
58 m_token = token;
59}
60
62{
63 if (!m_is_initialized) {
64
65 if (m_manager) {
66 auto self = shared_from_this();
67 uint32_t lhs_mask = m_lhs ? m_lhs->get_channel_mask().load() : 0;
68 uint32_t rhs_mask = m_rhs ? m_rhs->get_channel_mask().load() : 0;
69 uint32_t combined_mask = lhs_mask | rhs_mask;
70
71 if (combined_mask != 0) {
72 for (auto& channel : get_active_channels(combined_mask, 0)) {
73 m_manager->add_to_root(self, m_token, channel);
74 }
75 } else {
76 m_manager->add_to_root(self, m_token, 0);
77 }
78 m_is_initialized = true;
79 }
80 }
81
82 if (m_manager) {
84 switch (semantics) {
86 if (m_lhs) {
87 for (auto& channel : get_active_channels(m_lhs, 0)) {
89 }
90 }
91 if (m_rhs) {
92 for (auto& channel : get_active_channels(m_rhs, 0)) {
94 }
95 }
96 break;
98 default:
99 break;
100 }
101 }
102}
103
105{
106 if (!m_lhs || !m_rhs) {
107 return input;
108 }
109
110 if (!is_initialized())
111 initialize();
112
113 atomic_inc_modulator_count(m_lhs->m_modulator_count, 1);
114 atomic_inc_modulator_count(m_rhs->m_modulator_count, 1);
115
116 uint32_t lstate = m_lhs->m_state.load();
117 if (lstate & NodeState::PROCESSED) {
118 m_last_lhs_value = input + m_lhs->get_last_output();
119 } else {
120 m_last_lhs_value = m_lhs->process_sample(input);
122 }
123
124 uint32_t rstate = m_rhs->m_state.load();
125 if (rstate & NodeState::PROCESSED) {
126 m_last_rhs_value = input + m_rhs->get_last_output();
127 } else {
128 m_last_rhs_value = m_rhs->process_sample(input);
130 }
131
133
136
137 atomic_dec_modulator_count(m_lhs->m_modulator_count, 1);
138 atomic_dec_modulator_count(m_rhs->m_modulator_count, 1);
139
142
143 return m_last_output;
144}
145
146std::vector<double> BinaryOpNode::process_batch(unsigned int num_samples)
147{
148 std::vector<double> output(num_samples);
149 for (unsigned int i = 0; i < num_samples; ++i) {
150 output[i] = process_sample(0.0);
151 }
152 return output;
153}
154
156{
157 update_context(value);
158 auto& ctx = get_last_context();
159
160 for (const auto& callback : m_callbacks) {
161 callback(ctx);
162 }
163
164 for (const auto& [callback, condition] : m_conditional_callbacks) {
165 if (condition(ctx)) {
166 callback(ctx);
167 }
168 }
169}
170
172{
174 if (m_lhs)
175 m_lhs->reset_processed_state();
176 if (m_rhs)
177 m_rhs->reset_processed_state();
178}
179
181{
184
185 if (m_lhs)
186 m_lhs->save_state();
187 if (m_rhs)
188 m_rhs->save_state();
189
190 m_state_saved = true;
191}
192
194{
197
198 if (m_lhs)
199 m_lhs->restore_state();
200 if (m_rhs)
201 m_rhs->restore_state();
202
203 m_state_saved = false;
204}
205
218
220{
221 if (m_gpu_compatible) {
222 return m_context_gpu;
223 }
224 return m_context;
225}
226
228{
229 auto lstate = m_lhs->m_state.load();
230 auto rstate = m_rhs->m_state.load();
231 bool is_lhs_registered = m_lhs ? (lstate & NodeState::ACTIVE) : false;
232 bool is_rhs_registered = m_rhs ? (rstate & NodeState::ACTIVE) : false;
233 return !is_lhs_registered && !is_rhs_registered;
234}
235
236std::vector<std::pair<ModulatorRole, std::shared_ptr<Node>>>
238{
239 std::vector<std::pair<ModulatorRole, std::shared_ptr<Node>>> result;
240 if (m_lhs)
241 result.emplace_back(ModulatorRole::Lhs, m_lhs);
242 if (m_rhs)
243 result.emplace_back(ModulatorRole::Rhs, m_rhs);
244 return result;
245}
246
247namespace detail {
248
250 const std::vector<std::shared_ptr<Node>>& inputs,
251 NodeGraphManager& manager,
252 ProcessingToken token,
253 const std::shared_ptr<Node>& self)
254 {
255 uint32_t combined_mask = 0;
256 for (const auto& input : inputs)
257 combined_mask |= input->get_channel_mask().load();
258
259 if (combined_mask != 0) {
260 for (auto ch : get_active_channels(combined_mask, 0))
261 manager.add_to_root(self, token, ch);
262 } else {
263 manager.add_to_root(self, token, 0);
264 }
265 }
266
268 const std::vector<std::shared_ptr<Node>>& inputs,
269 NodeGraphManager& manager,
270 ProcessingToken token)
271 {
273 return;
274
275 for (const auto& input : inputs) {
276 for (auto ch : get_active_channels(input, 0))
277 manager.remove_from_root(input, token, ch);
278 }
279 }
280
281 void composite_validate(const std::vector<std::shared_ptr<Node>>& inputs, size_t N)
282 {
283 if (N > 0 && inputs.size() != N) {
284 error<std::invalid_argument>(
286 std::source_location::current(),
287 "CompositeOpNode<{}> requires exactly {} inputs, got {}",
288 N, N, inputs.size());
289 }
290
291 if (inputs.size() < 2) {
292 error<std::invalid_argument>(
294 std::source_location::current(),
295 "CompositeOpNode requires at least 2 inputs, got {}",
296 inputs.size());
297 }
298
299 for (size_t i = 0; i < inputs.size(); ++i) {
300 if (!inputs[i]) {
301 error<std::invalid_argument>(
303 std::source_location::current(),
304 "CompositeOpNode input at index {} is null", i);
305 }
306 }
307 }
308}
309
310} // namespace MayaFlux::Nodes
Core::GlobalInputConfig input
Definition Config.cpp:36
#define N(method_name, full_type_name)
Definition Creator.hpp:106
BinaryOpContextGpu(double value, double lhs_value, double rhs_value, std::span< const float > gpu_data)
double rhs_value
The value from the right-hand side node.
BinaryOpContext(double value, double lhs_value, double rhs_value)
Constructs a BinaryOpContext with the current operation state.
double lhs_value
The value from the left-hand side node.
Specialized context for binary operation callbacks.
bool m_is_initialized
Flag indicating whether the binary operator has been properly initialized.
void restore_state() override
Restores the node's state from the last save Recursively cascades through all connected modulator nod...
ProcessingToken m_token
The processing token indicating the domain in which this node operates.
void update_context(double value) override
updates context object for callbacks
NodeGraphManager * m_manager
Reference to the node graph manager for registration and callback management.
void initialize()
Initializes the binary operation node.
NodeContext & get_last_context() override
Retrieves the last created context object.
void notify_tick(double value) override
Notifies all registered callbacks about a new output value.
std::shared_ptr< Node > m_lhs
The left-hand side node.
std::function< double(double, double)> CombineFunc
Function type for combining two node outputs.
void reset_processed_state() override
Resets the processed state of the node and any attached input nodes.
CombineFunc m_func
The function used to combine the outputs of both nodes.
double process_sample(double input=0.) override
Processes a single sample through both nodes and combines the results.
void save_state() override
Saves the node's current state for later restoration Recursively cascades through all connected modul...
std::vector< std::pair< ModulatorRole, std::shared_ptr< Node > > > get_modulators() const override
Retrieves the current modulators connected to this node.
std::vector< double > process_batch(unsigned int num_samples) override
Processes multiple samples through both nodes and combines the results.
double m_last_rhs_value
The last output value from the right-hand side node.
double m_last_lhs_value
The last output value from the left-hand side node.
BinaryOpNode(const std::shared_ptr< Node > &lhs, const std::shared_ptr< Node > &rhs, CombineFunc func)
Creates a new binary operation node.
std::shared_ptr< Node > m_rhs
The right-hand side node.
BinaryOpContextGpu m_context_gpu
Combines the outputs of two nodes using a binary operation.
CompositeOpContextGpu(double value, std::vector< double > input_values, std::span< const float > gpu_data)
CompositeOpContext(double value, std::vector< double > input_values)
Context for N-ary composite operation callbacks.
GPU-uploadable 1D array data interface.
double value
Current sample value.
Definition Node.hpp:63
Base context class for node callbacks.
Definition Node.hpp:53
void add_to_root(const std::shared_ptr< Node > &node, ProcessingToken token, unsigned int channel=0)
Add node to specific processing token and channel.
void remove_from_root(const std::shared_ptr< Node > &node, ProcessingToken token, unsigned int channel=0)
Remove node from a specific processing token and channel.
NodeConfig & get_node_config()
Gets the current node configuration.
Central manager for the computational processing node graph.
std::vector< NodeHook > m_callbacks
Collection of standard callback functions.
Definition Node.hpp:434
double m_last_output
The most recent sample value generated by this oscillator.
Definition Node.hpp:405
std::atomic< NodeState > m_state
Atomic state flag tracking the node's processing status.
Definition Node.hpp:502
bool m_fire_events_during_snapshot
Internal flag controlling whether notify_tick fires during state snapshots Default: false (events don...
Definition Node.hpp:487
std::vector< std::pair< NodeHook, NodeCondition > > m_conditional_callbacks
Collection of conditional callback functions with their predicates.
Definition Node.hpp:444
bool m_gpu_compatible
Flag indicating if the node supports GPU processing This flag is set by derived classes to indicate w...
Definition Node.hpp:414
@ Init
Engine/subsystem initialization.
@ Nodes
DSP Generator and Filter Nodes, graph pipeline, node management.
void composite_validate(const std::vector< std::shared_ptr< Node > > &inputs, size_t N)
void composite_initialize(const std::vector< std::shared_ptr< Node > > &inputs, NodeGraphManager &manager, ProcessingToken token, const std::shared_ptr< Node > &self)
void composite_apply_semantics(const std::vector< std::shared_ptr< Node > > &inputs, NodeGraphManager &manager, ProcessingToken token)
@ PROCESSED
Node has been processed this cycle.
Definition NodeSpec.hpp:49
@ ACTIVE
Engine is processing this node.
Definition NodeSpec.hpp:45
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
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.
@ KEEP
Preserve both nodes in the binary op, add new binary op node to root, i.e doubling the signal.
Definition NodeSpec.hpp:23
@ REPLACE
Unregister both nodes and register with the new binary op node.
Definition NodeSpec.hpp:22
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
void atomic_remove_flag(std::atomic< NodeState > &state, NodeState flag)
Atomically removes a flag from a node state.
Definition NodeUtils.cpp:71
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
Contains the node-based computational processing system components.
Definition Chronie.hpp:14
NodeBinaryOpSemantics binary_op_semantics
Definition NodeSpec.hpp:36