MayaFlux 0.2.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
NodeChain.cpp
Go to the documentation of this file.
1#include "NodeChain.hpp"
2
4
6
7namespace MayaFlux::Nodes {
8
9ChainNode::ChainNode(std::vector<std::shared_ptr<Node>> nodes)
10 : m_nodes(std::move(nodes))
11{
12 if (m_nodes.size() < 2) {
13 error<std::invalid_argument>(
15 std::source_location::current(),
16 "ChainNode requires at least 2 nodes, got {}", m_nodes.size());
17 }
18
19 for (size_t i = 0; i < m_nodes.size(); ++i) {
20 if (!m_nodes[i]) {
21 error<std::invalid_argument>(
23 std::source_location::current(),
24 "ChainNode node at index {} is null", i);
25 }
26 }
27}
28
30 std::vector<std::shared_ptr<Node>> nodes,
31 NodeGraphManager& manager,
32 ProcessingToken token)
33 : ChainNode(std::move(nodes))
34{
35 m_manager = &manager;
36 m_token = token;
37}
38
40 const std::shared_ptr<Node>& source,
41 const std::shared_ptr<Node>& target)
42 : ChainNode(std::vector<std::shared_ptr<Node>> { source, target })
43{
44}
45
47 const std::shared_ptr<Node>& source,
48 const std::shared_ptr<Node>& target,
49 NodeGraphManager& manager,
50 ProcessingToken token)
51 : ChainNode(std::vector<std::shared_ptr<Node>> { source, target })
52{
53 m_manager = &manager;
54 m_token = token;
55}
56
57void ChainNode::append(const std::shared_ptr<Node>& node)
58{
59 if (!node) {
60 error<std::invalid_argument>(
62 std::source_location::current(),
63 "Cannot append null node to ChainNode");
64 }
65 m_nodes.push_back(node);
66}
67
68void ChainNode::append_chain(const std::shared_ptr<ChainNode>& other)
69{
70 m_nodes.insert(m_nodes.end(),
71 std::make_move_iterator(other->m_nodes.begin()),
72 std::make_move_iterator(other->m_nodes.end()));
73}
74
76{
77 if (!m_is_initialized) {
78 if (m_manager) {
79 auto& last = m_nodes.back();
80 if (last) {
81 for (auto& channel : get_active_channels(last, 0)) {
82 m_manager->add_to_root(shared_from_this(), m_token, channel);
83 }
84 } else {
85 m_manager->add_to_root(shared_from_this(), m_token, 0);
86 }
87 }
88 m_is_initialized = true;
89 }
90
91 if (m_manager) {
92 auto semantics = m_manager->get_node_config().chain_semantics;
93 switch (semantics) {
95 auto& last = m_nodes.back();
96 if (last) {
97 for (auto& channel : get_active_channels(last, 0)) {
98 m_manager->remove_from_root(last, m_token, channel);
99 }
100 }
101 break;
102 }
104 for (auto& node : m_nodes) {
105 if (node) {
106 for (auto& channel : get_active_channels(node, 0)) {
107 m_manager->remove_from_root(node, m_token, channel);
108 }
109 }
110 }
111 break;
113 default:
114 break;
115 }
116 }
117}
118
119double ChainNode::process_sample(double input)
120{
121 if (m_nodes.empty())
122 return input;
123
124 if (!is_initialized())
125 initialize();
126
127 for (auto& node : m_nodes) {
128 atomic_inc_modulator_count(node->m_modulator_count, 1);
129 }
130
131 m_last_output = input;
132
133 for (auto& node : m_nodes) {
134 uint32_t state = node->m_state.load();
135 if (state & NodeState::PROCESSED) {
136 m_last_output += node->get_last_output();
137 } else {
138 m_last_output = node->process_sample(m_last_output);
140 }
141 }
142
143 for (auto& node : m_nodes) {
144 atomic_dec_modulator_count(node->m_modulator_count, 1);
145 }
146
147 for (auto& node : m_nodes) {
149 }
150
151 return m_last_output;
152}
153
154std::vector<double> ChainNode::process_batch(unsigned int num_samples)
155{
156 std::vector<double> output(num_samples);
157 for (size_t i = 0; i < num_samples; i++) {
158 output[i] = process_sample(0.F);
159 }
160 return output;
161}
162
164{
166 for (auto& node : m_nodes) {
167 if (node)
168 node->reset_processed_state();
169 }
170}
171
173{
174 for (auto& node : m_nodes) {
175 if (node)
176 node->save_state();
177 }
178 m_state_saved = true;
179}
180
182{
183 for (auto& node : m_nodes) {
184 if (node)
185 node->restore_state();
186 }
187 m_state_saved = false;
188}
189
191{
192 for (auto& node : m_nodes) {
193 auto state = node->m_state.load();
194 bool is_registered = node ? (state & NodeState::ACTIVE) : false;
195 if (is_registered)
196 return false;
197 }
198 return m_state.load() & NodeState::ACTIVE;
199}
200
202{
203 if (m_nodes.empty()) {
204 error<std::runtime_error>(
206 std::source_location::current(),
207 "ChainNode has no nodes when retrieving last context");
208 }
209 return m_nodes.back()->get_last_context();
210}
211
212}
NodeContext & get_last_context() override
Retrieves the last created context object.
std::vector< std::shared_ptr< Node > > m_nodes
void initialize()
Initializes the chain node.
Definition NodeChain.cpp:75
void append_chain(const std::shared_ptr< ChainNode > &other)
Appends all nodes from another chain.
Definition NodeChain.cpp:68
std::vector< double > process_batch(unsigned int num_samples) override
Processes multiple samples at once.
double process_sample(double input=0.) override
Processes a single data sample.
void restore_state() override
Restores the node's state from the last save Recursively cascades through all connected modulator nod...
ChainNode(std::vector< std::shared_ptr< Node > > nodes)
Creates a chain from an ordered sequence of nodes.
Definition NodeChain.cpp:9
void save_state() override
Saves the node's current state for later restoration Recursively cascades through all connected modul...
void reset_processed_state() override
Resets the processed state of the node and any attached input nodes.
NodeGraphManager * m_manager
void append(const std::shared_ptr< Node > &node)
Appends a node to the end of the chain.
Definition NodeChain.cpp:57
Connects an ordered sequence of nodes in series.
Definition NodeChain.hpp:26
Base context class for node callbacks.
Definition Node.hpp:30
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.
double m_last_output
The most recent sample value generated by this oscillator.
Definition Node.hpp:377
std::atomic< NodeState > m_state
Atomic state flag tracking the node's processing status.
Definition Node.hpp:468
Base interface for all computational processing nodes.
Definition Node.hpp:109
@ Init
Engine/subsystem initialization.
@ Runtime
General runtime operations (default fallback)
@ Nodes
DSP Generator and Filter Nodes, graph pipeline, node management.
@ 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:94
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.
@ PRESERVE_BOTH
Preserve both nodes in the chain, add new chain node to root, i.e doubling the target signal.
Definition NodeSpec.hpp:13
@ ONLY_CHAIN
Only keep the new chain node, unregistering the source and target.
Definition NodeSpec.hpp:14
@ REPLACE_TARGET
Unregister the target and register with the new chain node.
Definition NodeSpec.hpp:12
void try_reset_processed_state(std::shared_ptr< Node > node)
Attempts to reset the processed state of a node.
void atomic_inc_modulator_count(std::atomic< uint32_t > &count, int amount)
Atomically increments the modulator count by a specified amount.
void atomic_remove_flag(std::atomic< NodeState > &state, NodeState flag)
Atomically removes a flag from a node state.
void atomic_dec_modulator_count(std::atomic< uint32_t > &count, int amount)
Atomically decrements the modulator count by a specified amount.
Contains the node-based computational processing system components.
Definition Chronie.hpp:11
NodeChainSemantics chain_semantics
Definition NodeSpec.hpp:35