MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
NodeGraphManager.cpp
Go to the documentation of this file.
2
4
6
8
9namespace MayaFlux::Nodes {
10
11NodeGraphManager::NodeGraphManager(uint32_t sample_rate, uint32_t block_size, uint32_t frame_rate)
12 : m_registered_sample_rate(sample_rate)
13 , m_registered_block_size(block_size)
14 , m_registered_frame_rate(frame_rate)
15{
17}
18
19void NodeGraphManager::add_to_root(const std::shared_ptr<Node>& node,
20 ProcessingToken token,
21 unsigned int channel)
22{
24 node->set_sample_rate(m_registered_sample_rate);
25 node->set_frame_rate(m_registered_frame_rate);
26
27 if (token == ProcessingToken::VISUAL_RATE) {
28 node->set_gpu_compatible(true);
29 }
30
31 auto& root = get_root_node(token, channel);
32 root.register_node(node);
33}
34
35void NodeGraphManager::remove_from_root(const std::shared_ptr<Node>& node,
36 ProcessingToken token,
37 unsigned int channel)
38{
40
41 auto& root = get_root_node(token, channel);
42 root.unregister_node(node);
43}
44
46 std::function<void(std::span<RootNode*>)> processor)
47{
48 m_token_processors[token] = std::move(processor);
49}
50
51const std::unordered_map<unsigned int, std::shared_ptr<RootNode>>& NodeGraphManager::get_all_channel_root_nodes(ProcessingToken token) const
52{
53 static std::unordered_map<unsigned int, std::shared_ptr<RootNode>> audio_roots;
54 audio_roots.clear();
55
56 auto it = m_token_roots.find(token);
57 if (it != m_token_roots.end()) {
58 for (const auto& [channel, root] : it->second) {
59 audio_roots[channel] = root;
60 }
61 }
62 return audio_roots;
63}
64
66{
67 auto& processing_ptr = m_token_network_processing[token];
68
69 if (!processing_ptr) {
70 processing_ptr = std::make_unique<std::atomic<bool>>(false);
71 }
72
73 bool expected = false;
74 return processing_ptr->compare_exchange_strong(
75 expected, true,
76 std::memory_order_acquire,
77 std::memory_order_relaxed);
78}
79
80void NodeGraphManager::process_token(ProcessingToken token, unsigned int num_samples)
81{
82 if (m_terminate_requested.load())
83 return;
84
85 auto roots = get_all_root_nodes(token);
86
87 if (auto it = m_token_processors.find(token); it != m_token_processors.end()) {
88 it->second(std::span<RootNode*>(roots.data(), roots.size()));
89 return;
90 }
91
92 if (!preprocess_networks(token)) {
93 return;
94 }
95
96 auto it = m_token_networks.find(token);
97 if (it != m_token_networks.end()) {
98 for (auto& network : it->second) {
99 if (!network || !network->is_enabled()) {
100 continue;
101 }
102
103 if (!network->is_processed_this_cycle()) {
104 network->mark_processing(true);
105 network->process_batch(num_samples);
106 network->mark_processing(false);
107 network->mark_processed(true);
108 }
109 }
110 }
111
112 postprocess_networks(token, std::nullopt);
113
114 if (token == ProcessingToken::AUDIO_RATE) {
115 for (auto* root : roots) {
116 root->process_batch(num_samples);
117 }
118 } else if (token == ProcessingToken::VISUAL_RATE) {
119 for (auto* root : roots) {
120 root->process_batch_frame(num_samples);
121 }
122 }
123}
124
125std::vector<std::vector<double>> NodeGraphManager::process_audio_networks(ProcessingToken token, uint32_t num_samples, uint32_t channel)
126{
127 if (!preprocess_networks(token)) {
128 return {};
129 }
130
131 std::vector<std::vector<double>> all_network_outputs;
132
133 auto audio_it = m_audio_networks.find(token);
134 if (audio_it != m_audio_networks.end()) {
135 for (auto& network : audio_it->second) {
136 if (!network || !network->is_enabled()) {
137 continue;
138 }
139
140 if (!network->is_registered_on_channel(channel)) {
141 continue;
142 }
143
144 if (!network->is_processed_this_cycle()) {
145 network->mark_processing(true);
146 network->process_batch(num_samples);
147 network->mark_processing(false);
148 network->mark_processed(true);
149 }
150
151 const auto& net_buffer = network->get_audio_buffer();
152 if (net_buffer && network->get_output_mode() == Network::OutputMode::AUDIO_SINK) {
153 if (network->needs_channel_routing()) {
154 double scale = network->get_routing_state().amount[channel];
155 if (scale == 0.0)
156 continue;
157
158 if (scale == 1.0) {
159 all_network_outputs.push_back(*net_buffer);
160 } else {
161 std::vector<double> scaled_buffer = *net_buffer;
162 for (auto& sample : scaled_buffer)
163 sample *= scale;
164
165 all_network_outputs.push_back(std::move(scaled_buffer));
166 }
167 } else {
168 all_network_outputs.push_back(*net_buffer);
169 }
170 }
171 }
172 }
173
175 return all_network_outputs;
176}
177
179{
180 if (token == ProcessingToken::AUDIO_RATE && channel.has_value()) {
181 auto ch = channel.value_or(0U);
182 reset_audio_network_state(token, ch);
183 } else if (auto it = m_token_networks.find(token); it != m_token_networks.end()) {
184 for (auto& network : it->second) {
185 if (network && network->is_enabled()) {
186 network->mark_processed(false);
187 }
188 }
189 }
190
191 if (auto it = m_token_network_processing.find(token); it != m_token_network_processing.end()) {
192 it->second->store(false, std::memory_order_release);
193 }
194}
195
197{
198 auto audio_it = m_audio_networks.find(token);
199 if (audio_it != m_audio_networks.end()) {
200 for (auto& network : audio_it->second) {
201 if (network) {
202 if (network->is_registered_on_channel(channel)) {
203 network->request_reset_from_channel(channel);
204 }
205 }
206 }
207 }
208}
209
215
217 TokenSampleProcessor processor)
218{
219 m_token_sample_processors[token] = std::move(processor);
220}
221
223 unsigned int channel, unsigned int num_samples)
224{
225 if (channel == 0) {
227 }
228
229 auto& root = get_root_node(token, channel);
230
231 if (auto it = m_token_channel_processors.find(token); it != m_token_channel_processors.end()) {
232 return it->second(&root, num_samples);
233 }
234
235 std::vector<double> samples = root.process_batch(num_samples);
236
237 uint32_t normalize_coef = root.get_node_size();
238 for (double& sample : samples) {
239 normalize_sample(sample, normalize_coef);
240 }
241 return samples;
242}
243
245{
246 if (m_terminate_requested.load())
247 return 0.0;
248
249 auto& root = get_root_node(token, channel);
250
251 if (auto it = m_token_sample_processors.find(token); it != m_token_sample_processors.end()) {
252 return it->second(&root, channel);
253 }
254
255 double sample = root.process_sample();
256 normalize_sample(sample, root.get_node_size());
257 return sample;
258}
259
260void NodeGraphManager::normalize_sample(double& sample, uint32_t num_nodes)
261{
262 if (num_nodes == 0)
263 return;
264
265 sample /= std::sqrt(static_cast<double>(num_nodes));
266
267 const double threshold = 0.95;
268 const double knee = 0.1;
269 const double abs_sample = std::abs(sample);
270
271 if (abs_sample > threshold) {
272 const double excess = abs_sample - threshold;
273 const double compressed_excess = std::tanh(excess / knee) * knee;
274 const double limited_abs = threshold + compressed_excess;
275 sample = std::copysign(limited_abs, sample);
276 }
277}
278
279std::unordered_map<unsigned int, std::vector<double>> NodeGraphManager::process_token_with_channel_data(
280 ProcessingToken token, unsigned int num_samples)
281{
282 std::unordered_map<unsigned int, std::vector<double>> channel_data;
283
284 auto channels = get_all_channels(token);
285
286 for (unsigned int channel : channels) {
287 channel_data[channel] = process_channel(token, channel, num_samples);
288 }
289
290 return channel_data;
291}
292
294{
295 auto channels = get_all_channels(token);
296 return static_cast<unsigned int>(channels.size());
297}
298
300{
301 std::vector<RootNode*> roots;
302
303 auto it = m_token_roots.find(token);
304 if (it != m_token_roots.end()) {
305 for (auto& [channel, root] : it->second) {
306 roots.push_back(root.get());
307 }
308 }
309
310 return roots;
311}
312
313void NodeGraphManager::process_all_tokens(unsigned int num_samples)
314{
315 for (auto token : get_active_tokens()) {
316 process_token(token, num_samples);
317 }
318}
319
321{
323 return *m_token_roots[token][channel];
324}
325
327{
328 if (m_token_roots[token].find(channel) == m_token_roots[token].end()) {
329 m_token_roots[token][channel] = std::make_shared<RootNode>(token, channel);
330 }
331}
332
334{
335 for (uint32_t ch = 0; ch < num_channels; ++ch) {
336 ensure_root_exists(token, ch);
337 }
338}
339
340void NodeGraphManager::register_global(const std::shared_ptr<Node>& node)
341{
342 if (!is_node_registered(node)) {
343 std::stringstream ss;
344 ss << "node_" << node.get();
345 std::string generated_id = ss.str();
346 m_Node_registry[generated_id] = node;
347 }
348}
349
350void NodeGraphManager::set_channel_mask(const std::shared_ptr<Node>& node, uint32_t channel_id)
351{
352 register_global(node);
353 node->register_channel_usage(channel_id);
354}
355
356void NodeGraphManager::unregister_global(const std::shared_ptr<Node>& node)
357{
358 for (const auto& pair : m_Node_registry) {
359 if (pair.second == node) {
360 m_Node_registry.erase(pair.first);
361 break;
362 }
363 }
364}
365
366void NodeGraphManager::unset_channel_mask(const std::shared_ptr<Node>& node, uint32_t channel_id)
367{
368 unregister_global(node);
369 node->unregister_channel_usage(channel_id);
370}
371
372std::vector<ProcessingToken> NodeGraphManager::get_active_tokens() const
373{
374 std::vector<ProcessingToken> tokens;
375 for (const auto& [token, channels] : m_token_roots) {
376 if (!channels.empty()) {
377 tokens.push_back(token);
378 }
379 }
380 return tokens;
381}
382
383std::vector<unsigned int> NodeGraphManager::get_all_channels(ProcessingToken token) const
384{
385 std::vector<unsigned int> channels;
386 auto it = m_token_roots.find(token);
387 if (it != m_token_roots.end()) {
388 for (const auto& [channel, root] : it->second) {
389 channels.push_back(channel);
390 }
391 }
392 return channels;
393}
394
396{
397 size_t count = 0;
398 auto it = m_token_roots.find(token);
399 if (it != m_token_roots.end()) {
400 for (const auto& [channel, root] : it->second) {
401 count += root->get_node_size();
402 }
403 }
404 return count;
405}
406
408{
411 "=== NodeGraphManager Summary ===");
412
413 for (auto token : get_active_tokens()) {
414 auto channels = get_all_channels(token);
415 size_t total_nodes = get_node_count(token);
416
419 "Token {}: {} nodes across {} channels",
420 static_cast<int>(token), total_nodes, channels.size());
421
422 for (auto channel : channels) {
423 auto& root = const_cast<NodeGraphManager*>(this)->get_root_node(token, channel);
424 auto networks = get_networks(token, channel);
425
428 " Channel {}: {} nodes, {} networks",
429 channel, root.get_node_size(), networks.size());
430
431 for (const auto& network : networks) {
432 if (network) {
435 " Network: {} internal nodes, mode={}, enabled={}",
436 network->get_node_count(),
437 static_cast<int>(network->get_output_mode()),
438 network->is_enabled());
439 }
440 }
441 }
442 }
443}
444
445std::shared_ptr<Node> NodeGraphManager::get_node(const std::string& id)
446{
447 auto it = m_Node_registry.find(id);
448
449 if (it != m_Node_registry.end()) {
450 return it->second;
451 }
452 return nullptr;
453}
454
455bool NodeGraphManager::is_node_registered(const std::shared_ptr<Node>& node)
456{
457 return std::ranges::any_of(m_Node_registry,
458 [&node](const auto& pair) { return pair.second == node; });
459}
460
461void NodeGraphManager::connect(const std::string& source_id, const std::string& target_id)
462{
463 auto source = get_node(source_id);
464 auto target = get_node(target_id);
465
466 if (source && target) {
467 auto chain = std::make_shared<ChainNode>(source, target, *this);
468 chain->initialize();
469 }
470}
471
472//-----------------------------------------------------------------------------
473// NodeNetwork Management
474//-----------------------------------------------------------------------------
475
476void NodeGraphManager::add_network(const std::shared_ptr<Network::NodeNetwork>& network,
477 ProcessingToken token)
478{
479 if (!network) {
480 return;
481 }
482
484
485 network->set_enabled(true);
486
487 if (network->get_output_mode() == Network::OutputMode::AUDIO_SINK
488 || network->get_output_mode() == Network::OutputMode::AUDIO_COMPUTE) {
489 uint32_t channel_mask = network->get_channel_mask();
490
491 if (channel_mask == 0) {
492 channel_mask = 1;
493 network->add_channel_usage(0);
494 }
495
496 auto channels = network->get_registered_channels();
497 m_audio_networks[token].push_back(network);
498
499 for (auto ch : channels) {
500 ensure_root_exists(token, ch);
503 "Added audio network to token {} channel {}: {} nodes",
504 static_cast<int>(token), ch, network->get_node_count());
505 }
506
507 } else {
508 m_token_networks[token].push_back(network);
509
512 "Added network to token {}: {} nodes, mode={}",
513 static_cast<int>(token),
514 network->get_node_count(),
515 static_cast<int>(network->get_output_mode()));
516 }
517}
518
519void NodeGraphManager::remove_network(const std::shared_ptr<Network::NodeNetwork>& network,
520 ProcessingToken token)
521{
522 if (!network) {
523 return;
524 }
525
526 if (network->get_output_mode() == Network::OutputMode::AUDIO_SINK
527 || network->get_output_mode() == Network::OutputMode::AUDIO_COMPUTE) {
528 auto token_it = m_audio_networks.find(token);
529 if (token_it != m_audio_networks.end()) {
530 auto& networks = token_it->second;
531 std::erase_if(networks, [&](const auto& n) { return n == network; });
532 }
533 } else {
534 auto it = m_token_networks.find(token);
535 if (it != m_token_networks.end()) {
536 auto& networks = it->second;
537 std::erase_if(networks, [&](const auto& n) { return n == network; });
538 }
539 }
540
542}
543
544std::vector<std::shared_ptr<Network::NodeNetwork>>
546{
547 auto token_it = m_audio_networks.find(token);
548 if (token_it != m_audio_networks.end()) {
549 std::vector<std::shared_ptr<Network::NodeNetwork>> networks_on_channel;
550 for (const auto& network : token_it->second) {
551 if (network && network->is_registered_on_channel(channel)) {
552 networks_on_channel.push_back(network);
553 }
554 }
555 return networks_on_channel;
556 }
557 return {};
558}
559
560std::vector<std::shared_ptr<Network::NodeNetwork>>
562{
563 std::vector<std::shared_ptr<Network::NodeNetwork>> all_networks;
564
565 auto audio_it = m_audio_networks.find(token);
566 if (audio_it != m_audio_networks.end()) {
567 all_networks.insert(all_networks.end(),
568 audio_it->second.begin(),
569 audio_it->second.end());
570 }
571
572 auto token_it = m_token_networks.find(token);
573 if (token_it != m_token_networks.end()) {
574 all_networks.insert(all_networks.end(),
575 token_it->second.begin(),
576 token_it->second.end());
577 }
578
579 return all_networks;
580}
581
583{
584 size_t count = 0;
585
586 auto audio_it = m_audio_networks.find(token);
587 if (audio_it != m_audio_networks.end()) {
588 count += audio_it->second.size();
589 }
590
591 auto token_it = m_token_networks.find(token);
592 if (token_it != m_token_networks.end()) {
593 count += token_it->second.size();
594 }
595
596 return count;
597}
598
600{
601 m_audio_networks.erase(token);
602 m_token_networks.erase(token);
603}
604
605void NodeGraphManager::register_network_global(const std::shared_ptr<Network::NodeNetwork>& network)
606{
607 if (!is_network_registered(network)) {
608 std::stringstream ss;
609 ss << "network_" << network.get();
610 std::string generated_id = ss.str();
611 m_network_registry[generated_id] = network;
612 network->set_sample_rate(m_registered_sample_rate);
613 network->set_block_size(m_registered_block_size);
614 }
615}
616
617void NodeGraphManager::unregister_network_global(const std::shared_ptr<Network::NodeNetwork>& network)
618{
619 for (const auto& pair : m_network_registry) {
620 if (pair.second == network) {
621 m_network_registry.erase(pair.first);
622 break;
623 }
624 }
625}
626
627bool NodeGraphManager::is_network_registered(const std::shared_ptr<Network::NodeNetwork>& network)
628{
629 return std::ranges::any_of(m_network_registry,
630 [&network](const auto& pair) { return pair.second == network; });
631}
632
634{
635 if (m_terminate_requested.load())
636 return;
637
638 for (auto& [token, networks] : m_audio_networks) {
639 for (auto& network : networks) {
640 if (network) {
642 }
643 }
644 }
645
646 for (auto& [token, networks] : m_token_networks) {
647 for (auto& network : networks) {
648 if (network) {
650 }
651 }
652 }
653
654 m_terminate_requested.store(true);
655
656 for (auto token : get_active_tokens()) {
657 auto roots = get_all_root_nodes(token);
658 for (auto* root : roots) {
659 root->terminate_all_nodes();
660 }
661 }
662}
663
674
676{
677 for (const auto& [id, node] : m_Node_registry) {
678 if (!node->needs_channel_routing())
679 continue;
680 update_routing_state(node->get_routing_state());
681 }
682
683 for (const auto& network : get_all_networks(token)) {
684 if (!network || !network->needs_channel_routing())
685 continue;
686 update_routing_state(network->get_routing_state());
687 }
688}
689
691 const std::shared_ptr<Node>& node,
692 const std::vector<uint32_t>& target_channels,
693 uint32_t fade_cycles,
694 ProcessingToken token)
695{
696 uint32_t current_channels = node->get_channel_mask();
697
698 uint32_t target_bitmask = 0;
699 for (auto ch : target_channels) {
700 target_bitmask |= (1 << ch);
701 }
702
703 uint32_t fade_blocks = (fade_cycles + m_registered_block_size - 1) / m_registered_block_size;
704 fade_blocks = std::max(1U, fade_blocks);
705
706 RoutingState state;
707 state.from_channels = current_channels;
708 state.to_channels = target_bitmask;
709 state.fade_cycles = fade_blocks;
710 state.phase = RoutingState::ACTIVE;
711
712 for (uint32_t ch = 0; ch < 32; ch++) {
713 state.amount[ch] = (current_channels & (1 << ch)) ? 1.0 : 0.0;
714 }
715
716 node->get_routing_state() = state;
717
718 for (auto ch : target_channels) {
719 if (!(current_channels & (1 << ch))) {
720 add_to_root(node, token, ch);
721 }
722 }
723}
724
726 const std::shared_ptr<Network::NodeNetwork>& network,
727 const std::vector<uint32_t>& target_channels,
728 uint32_t fade_cycles,
729 ProcessingToken token)
730{
731 if (network->get_output_mode() != Network::OutputMode::AUDIO_SINK) {
734 "Attempted to route network that is not an audio sink. Operation ignored.");
735 return;
736 }
737
739 network->set_enabled(true);
740
741 auto& networks = m_audio_networks[token];
742 if (std::ranges::find(networks, network) == networks.end()) {
743 networks.push_back(network);
744 }
745
746 uint32_t current_channels = network->get_channel_mask();
747
748 uint32_t target_bitmask = 0;
749 for (auto ch : target_channels) {
750 target_bitmask |= (1 << ch);
751 }
752
753 uint32_t combined_mask = current_channels | target_bitmask;
754 network->set_channel_mask(combined_mask);
755 for (auto ch : target_channels) {
756 network->add_channel_usage(ch);
757 ensure_root_exists(token, ch);
758 }
759
760 uint32_t fade_blocks = (fade_cycles + m_registered_block_size - 1) / m_registered_block_size;
761 fade_blocks = std::max(1u, fade_blocks);
762
763 RoutingState state;
764 state.from_channels = current_channels;
765 state.to_channels = target_bitmask;
766 state.fade_cycles = fade_blocks;
767 state.phase = RoutingState::ACTIVE;
768
769 for (uint32_t ch = 0; ch < 32; ch++) {
770 state.amount[ch] = (current_channels & (1 << ch)) ? 1.0 : 0.0;
771 }
772
773 network->get_routing_state() = state;
774}
775
777{
778 std::vector<std::pair<std::shared_ptr<Node>, uint32_t>> nodes_to_remove;
779
780 for (const auto& [id, node] : m_Node_registry) {
781 if (!node->needs_channel_routing())
782 continue;
783
784 auto& state = node->get_routing_state();
785
786 if (state.phase == RoutingState::COMPLETED) {
787 for (uint32_t ch = 0; ch < 32; ch++) {
788 if ((state.from_channels & (1 << ch)) && !(state.to_channels & (1 << ch))) {
789 nodes_to_remove.emplace_back(node, ch);
790 }
791 }
792 state = RoutingState {};
793 }
794 }
795
796 for (auto& [node, channel] : nodes_to_remove) {
797 remove_from_root(node, token, channel);
798 }
799
800 std::vector<std::pair<std::shared_ptr<Network::NodeNetwork>, uint32_t>> networks_to_cleanup;
801
802 for (const auto& network : get_all_networks(token)) {
803 if (!network || !network->needs_channel_routing())
804 continue;
805
806 auto& state = network->get_routing_state();
807
808 if (state.phase == RoutingState::COMPLETED) {
809 network->set_channel_mask(state.to_channels);
810
811 for (uint32_t ch = 0; ch < 32; ch++) {
812 if ((state.from_channels & (1 << ch)) && !(state.to_channels & (1 << ch))) {
813 networks_to_cleanup.emplace_back(network, ch);
814 }
815 }
816 state = RoutingState {};
817 }
818 }
819
820 for (auto& [network, channel] : networks_to_cleanup) {
821 network->remove_channel_usage(channel);
822
823 if (network->get_channel_mask() == 0) {
824 auto& networks = m_audio_networks[token];
825 std::erase_if(networks, [&](const auto& n) { return n == network; });
827 }
828 }
829}
830
831}
#define MF_INFO(comp, ctx,...)
#define MF_PRINT(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
Eigen::Index count
uint32_t channel
void register_token_processor(ProcessingToken token, std::function< void(std::span< RootNode * >)> processor)
Register subsystem processor for a specific token.
void update_routing_states_for_cycle(ProcessingToken token)
Updates routing states for all nodes and networks for a given token.
void remove_network(const std::shared_ptr< Network::NodeNetwork > &network, ProcessingToken token)
Remove a network from a processing token.
void register_token_sample_processor(ProcessingToken token, TokenSampleProcessor processor)
Register per-sample processor for a specific token.
void terminate_active_processing()
Terminates all active processing across all tokens and channels.
void clear_networks(ProcessingToken token)
Clear all networks from a token.
void print_summary() const
Prints a summary of all tokens, channels, and node counts.
const std::unordered_map< unsigned int, std::shared_ptr< RootNode > > & get_all_channel_root_nodes(ProcessingToken token=ProcessingToken::AUDIO_RATE) const
Gets all channel root nodes for the AUDIO_RATE domain.
std::vector< std::vector< double > > process_audio_networks(ProcessingToken token, uint32_t num_samples, uint32_t channel=0)
Process audio networks for a specific channel.
void route_node_to_channels(const std::shared_ptr< Node > &node, const std::vector< uint32_t > &target_channels, uint32_t fade_cycles, ProcessingToken token)
Routes a node's output to specific channels within a token domain.
std::unordered_map< ProcessingToken, std::vector< std::shared_ptr< Network::NodeNetwork > > > m_token_networks
Non-audio networks (token-level processing) For NONE, GRAPHICS_BIND, CUSTOM output modes.
std::atomic< bool > m_terminate_requested
Global termination flag.
std::unordered_map< ProcessingToken, std::function< void(std::span< RootNode * >)> > m_token_processors
Registered custom processors for each processing token.
void add_network(const std::shared_ptr< Network::NodeNetwork > &network, ProcessingToken token)
Add a network to a processing token.
size_t get_network_count(ProcessingToken token) const
Get count of networks for a token.
bool preprocess_networks(ProcessingToken token)
Preprocess networks for a specific token.
void normalize_sample(double &sample, uint32_t num_nodes)
Normalizes a sample to the range [-1, 1] based on the number of nodes.
size_t get_node_count(ProcessingToken token) const
Gets the total number of nodes registered under a given token.
void unregister_global(const std::shared_ptr< Node > &node)
Unregisters a node globally.
unsigned int get_channel_count(ProcessingToken token) const
Get the number of active channels for a specific token.
void unset_channel_mask(const std::shared_ptr< Node > &node, uint32_t channel_id)
Unsets the specified channel mask from a node's global registration.
std::unordered_map< std::string, std::shared_ptr< Network::NodeNetwork > > m_network_registry
Global network registry (like m_Node_registry)
void reset_audio_network_state(ProcessingToken token, uint32_t channel=0)
Resets the processing state of audio networks for a token and channel.
uint32_t m_registered_block_size
Block size for audio processing, used for normalizationbuffer.
void process_all_tokens(unsigned int num_samples=1)
Process all active tokens sequentially.
void register_global(const std::shared_ptr< Node > &node)
Registers a node globally if not already registered.
uint32_t m_registered_sample_rate
Sample rate for audio processing, used for normalization.
std::unordered_map< ProcessingToken, TokenSampleProcessor > m_token_sample_processors
Per-sample processors for each processing token.
std::unordered_map< std::string, std::shared_ptr< Node > > m_Node_registry
Registry of all nodes by their string identifiers.
std::vector< double > process_channel(ProcessingToken token, unsigned int channel, unsigned int num_samples)
Process a specific channel within a token domain.
void register_network_global(const std::shared_ptr< Network::NodeNetwork > &network)
Register network globally (like nodes)
void postprocess_networks(ProcessingToken token, std::optional< uint32_t > channel)
Postprocess networks for a specific token and channel.
NodeGraphManager(uint32_t sample_rate=48000, uint32_t block_size=512, uint32_t frame_rate=60)
Creates a new NodeGraphManager.
void ensure_root_exists(ProcessingToken token, unsigned int channel)
Ensures a root node exists for the given token and channel.
double process_sample(ProcessingToken token, uint32_t channel)
Process a single sample for a specific channel.
void connect(const std::string &source_id, const std::string &target_id)
Connects two nodes by their string identifiers.
void set_channel_mask(const std::shared_ptr< Node > &node, uint32_t channel_id)
Adds the specified channel mask to a node's global registration.
void add_to_root(const std::shared_ptr< Node > &node, ProcessingToken token, unsigned int channel=0)
Add node to specific processing token and channel.
RootNode & get_root_node(ProcessingToken token, unsigned int channel)
Gets or creates the root node for a specific token and channel.
bool is_node_registered(const std::shared_ptr< Node > &node)
Checks if a node is registered with this manager.
void route_network_to_channels(const std::shared_ptr< Network::NodeNetwork > &network, const std::vector< uint32_t > &target_channels, uint32_t fade_cycles, ProcessingToken token)
Routes a network's output to specific channels within a token domain.
std::unordered_map< ProcessingToken, std::unordered_map< unsigned int, std::shared_ptr< RootNode > > > m_token_roots
Multi-modal map of processing tokens to their channel root nodes.
void cleanup_completed_routing(ProcessingToken token)
Cleans up completed routing transitions for a given token.
std::vector< std::shared_ptr< Network::NodeNetwork > > get_all_networks(ProcessingToken token) const
Get all networks for a specific token across all channels.
~NodeGraphManager()
Destroys the NodeGraphManager.
uint32_t m_registered_frame_rate
Frame rate for visual processing, used for timing and normalization.
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.
std::unordered_map< unsigned int, std::vector< double > > process_token_with_channel_data(ProcessingToken token, unsigned int num_samples)
Process all channels for a token and return channel-separated data.
std::unordered_map< ProcessingToken, std::vector< std::shared_ptr< Network::NodeNetwork > > > m_audio_networks
Audio-sink networks Only populated for networks with OutputMode::AUDIO_SINK.
std::shared_ptr< Node > get_node(const std::string &id)
Looks up a node by its string identifier.
void unregister_network_global(const std::shared_ptr< Network::NodeNetwork > &network)
Unregister network globally.
std::vector< ProcessingToken > get_active_tokens() const
Gets all currently active processing tokens (domains)
std::unordered_map< ProcessingToken, TokenChannelProcessor > m_token_channel_processors
Per-channel processors for each processing token.
void ensure_token_exists(ProcessingToken token, uint32_t num_channels=1)
Ensures that a processing token entry exists.
bool is_network_registered(const std::shared_ptr< Network::NodeNetwork > &network)
Check if network is registered globally.
std::unordered_map< ProcessingToken, std::unique_ptr< std::atomic< bool > > > m_token_network_processing
Processing flags for each token's networks.
std::vector< std::shared_ptr< Network::NodeNetwork > > get_networks(ProcessingToken token, uint32_t channel=0) const
Get all networks for a specific token.
std::vector< RootNode * > get_all_root_nodes(ProcessingToken token)
Get spans of root nodes for a token (for custom processing)
std::vector< unsigned int > get_all_channels(ProcessingToken token) const
Gets all channel indices for a given processing token.
void process_token(ProcessingToken token, unsigned int num_samples=1)
Process all nodes in a specific token domain Calls registered processor if available,...
void register_token_channel_processor(ProcessingToken token, TokenChannelProcessor processor)
Register per-channel processor for a specific token.
Central manager for the computational processing node graph.
Container for top-level nodes in a processing channel with multi-modal support.
Definition RootNode.hpp:29
@ NodeProcessing
Node graph processing (Nodes::NodeGraphManager)
@ Nodes
DSP Generator and Filter Nodes, graph pipeline, node management.
@ AUDIO_COMPUTE
processed each cycle but not sent to output
@ AUDIO_SINK
Aggregated audio samples sent to output.
ProcessingToken
Enumerates the different processing domains for nodes.
@ AUDIO_RATE
Nodes that process at the audio sample rate.
@ VISUAL_RATE
Nodes that process at the visual frame rate.
std::function< double(RootNode *, uint32_t)> TokenSampleProcessor
void update_routing_state(RoutingState &state)
Updates the routing state for a node based on its current channel usage.
std::function< std::vector< double >(RootNode *, uint32_t)> TokenChannelProcessor
Contains the node-based computational processing system components.
Definition Chronie.hpp:13
@ COMPLETED
Routing transition has completed.
Definition NodeSpec.hpp:82
@ ACTIVE
Currently in the fade-out phase of a routing transition.
Definition NodeSpec.hpp:81
Represents the state of routing transitions for a node.
Definition NodeSpec.hpp:64