MayaFlux 0.3.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)
12 : m_registered_sample_rate(sample_rate)
13 , m_registered_block_size(block_size)
14{
16}
17
18void NodeGraphManager::add_to_root(const std::shared_ptr<Node>& node,
19 ProcessingToken token,
20 unsigned int channel)
21{
22 set_channel_mask(node, channel);
23 node->set_sample_rate(m_registered_sample_rate);
24
25 if (token == ProcessingToken::VISUAL_RATE) {
26 node->set_gpu_compatible(true);
27 }
28
29 auto& root = get_root_node(token, channel);
30 root.register_node(node);
31}
32
33void NodeGraphManager::remove_from_root(const std::shared_ptr<Node>& node,
34 ProcessingToken token,
35 unsigned int channel)
36{
37 unset_channel_mask(node, channel);
38
39 auto& root = get_root_node(token, channel);
40 root.unregister_node(node);
41}
42
44 std::function<void(std::span<RootNode*>)> processor)
45{
46 m_token_processors[token] = std::move(processor);
47}
48
49const std::unordered_map<unsigned int, std::shared_ptr<RootNode>>& NodeGraphManager::get_all_channel_root_nodes(ProcessingToken token) const
50{
51 static std::unordered_map<unsigned int, std::shared_ptr<RootNode>> audio_roots;
52 audio_roots.clear();
53
54 auto it = m_token_roots.find(token);
55 if (it != m_token_roots.end()) {
56 for (const auto& [channel, root] : it->second) {
57 audio_roots[channel] = root;
58 }
59 }
60 return audio_roots;
61}
62
64{
65 auto& processing_ptr = m_token_network_processing[token];
66
67 if (!processing_ptr) {
68 processing_ptr = std::make_unique<std::atomic<bool>>(false);
69 }
70
71 bool expected = false;
72 return processing_ptr->compare_exchange_strong(
73 expected, true,
74 std::memory_order_acquire,
75 std::memory_order_relaxed);
76}
77
78void NodeGraphManager::process_token(ProcessingToken token, unsigned int num_samples)
79{
80 if (m_terminate_requested.load())
81 return;
82
83 auto roots = get_all_root_nodes(token);
84
85 if (auto it = m_token_processors.find(token); it != m_token_processors.end()) {
86 it->second(std::span<RootNode*>(roots.data(), roots.size()));
87 return;
88 }
89
90 if (!preprocess_networks(token)) {
91 return;
92 }
93
94 auto it = m_token_networks.find(token);
95 if (it != m_token_networks.end()) {
96 for (auto& network : it->second) {
97 if (!network || !network->is_enabled()) {
98 continue;
99 }
100
101 if (!network->is_processed_this_cycle()) {
102 network->mark_processing(true);
103 network->process_batch(num_samples);
104 network->mark_processing(false);
105 network->mark_processed(true);
106 }
107 }
108 }
109
110 postprocess_networks(token, std::nullopt);
111
112 if (token == ProcessingToken::AUDIO_RATE) {
113 for (auto* root : roots) {
114 root->process_batch(num_samples);
115 }
116 } else if (token == ProcessingToken::VISUAL_RATE) {
117 for (auto* root : roots) {
118 root->process_batch_frame(num_samples);
119 }
120 }
121}
122
123std::vector<std::vector<double>> NodeGraphManager::process_audio_networks(ProcessingToken token, uint32_t num_samples, uint32_t channel)
124{
125 if (!preprocess_networks(token)) {
126 return {};
127 }
128
129 std::vector<std::vector<double>> all_network_outputs;
130
131 auto audio_it = m_audio_networks.find(token);
132 if (audio_it != m_audio_networks.end()) {
133 for (auto& network : audio_it->second) {
134 if (!network || !network->is_enabled()) {
135 continue;
136 }
137
138 if (!network->is_registered_on_channel(channel)) {
139 continue;
140 }
141
142 if (!network->is_processed_this_cycle()) {
143 network->mark_processing(true);
144 network->process_batch(num_samples);
145 network->mark_processing(false);
146 network->mark_processed(true);
147 }
148
149 const auto& net_buffer = network->get_audio_buffer();
150 if (net_buffer && network->get_output_mode() == Network::OutputMode::AUDIO_SINK) {
151 if (network->needs_channel_routing()) {
152 double scale = network->get_routing_state().amount[channel];
153 if (scale == 0.0)
154 continue;
155
156 if (scale == 1.0) {
157 all_network_outputs.push_back(*net_buffer);
158 } else {
159 std::vector<double> scaled_buffer = *net_buffer;
160 for (auto& sample : scaled_buffer)
161 sample *= scale;
162
163 all_network_outputs.push_back(std::move(scaled_buffer));
164 }
165 } else {
166 all_network_outputs.push_back(*net_buffer);
167 }
168 }
169 }
170 }
171
172 postprocess_networks(token, channel);
173 return all_network_outputs;
174}
175
176void NodeGraphManager::postprocess_networks(ProcessingToken token, std::optional<uint32_t> channel)
177{
178 if (token == ProcessingToken::AUDIO_RATE && channel.has_value()) {
179 auto ch = channel.value_or(0U);
180 reset_audio_network_state(token, ch);
181 } else if (auto it = m_token_networks.find(token); it != m_token_networks.end()) {
182 for (auto& network : it->second) {
183 if (network && network->is_enabled()) {
184 network->mark_processed(false);
185 }
186 }
187 }
188
189 if (auto it = m_token_network_processing.find(token); it != m_token_network_processing.end()) {
190 it->second->store(false, std::memory_order_release);
191 }
192}
193
195{
196 auto audio_it = m_audio_networks.find(token);
197 if (audio_it != m_audio_networks.end()) {
198 for (auto& network : audio_it->second) {
199 if (network) {
200 if (network->is_registered_on_channel(channel)) {
201 network->request_reset_from_channel(channel);
202 }
203 }
204 }
205 }
206}
207
213
215 TokenSampleProcessor processor)
216{
217 m_token_sample_processors[token] = std::move(processor);
218}
219
221 unsigned int channel, unsigned int num_samples)
222{
223 if (channel == 0) {
225 }
226
227 auto& root = get_root_node(token, channel);
228
229 if (auto it = m_token_channel_processors.find(token); it != m_token_channel_processors.end()) {
230 return it->second(&root, num_samples);
231 }
232
233 std::vector<double> samples = root.process_batch(num_samples);
234
235 uint32_t normalize_coef = root.get_node_size();
236 for (double& sample : samples) {
237 normalize_sample(sample, normalize_coef);
238 }
239 return samples;
240}
241
243{
244 if (m_terminate_requested.load())
245 return 0.0;
246
247 auto& root = get_root_node(token, channel);
248
249 if (auto it = m_token_sample_processors.find(token); it != m_token_sample_processors.end()) {
250 return it->second(&root, channel);
251 }
252
253 double sample = root.process_sample();
254 normalize_sample(sample, root.get_node_size());
255 return sample;
256}
257
258void NodeGraphManager::normalize_sample(double& sample, uint32_t num_nodes)
259{
260 if (num_nodes == 0)
261 return;
262
263 sample /= std::sqrt(static_cast<double>(num_nodes));
264
265 const double threshold = 0.95;
266 const double knee = 0.1;
267 const double abs_sample = std::abs(sample);
268
269 if (abs_sample > threshold) {
270 const double excess = abs_sample - threshold;
271 const double compressed_excess = std::tanh(excess / knee) * knee;
272 const double limited_abs = threshold + compressed_excess;
273 sample = std::copysign(limited_abs, sample);
274 }
275}
276
277std::unordered_map<unsigned int, std::vector<double>> NodeGraphManager::process_token_with_channel_data(
278 ProcessingToken token, unsigned int num_samples)
279{
280 std::unordered_map<unsigned int, std::vector<double>> channel_data;
281
282 auto channels = get_all_channels(token);
283
284 for (unsigned int channel : channels) {
285 channel_data[channel] = process_channel(token, channel, num_samples);
286 }
287
288 return channel_data;
289}
290
292{
293 auto channels = get_all_channels(token);
294 return static_cast<unsigned int>(channels.size());
295}
296
298{
299 std::vector<RootNode*> roots;
300
301 auto it = m_token_roots.find(token);
302 if (it != m_token_roots.end()) {
303 for (auto& [channel, root] : it->second) {
304 roots.push_back(root.get());
305 }
306 }
307
308 return roots;
309}
310
311void NodeGraphManager::process_all_tokens(unsigned int num_samples)
312{
313 for (auto token : get_active_tokens()) {
314 process_token(token, num_samples);
315 }
316}
317
319{
320 ensure_root_exists(token, channel);
321 return *m_token_roots[token][channel];
322}
323
325{
326 if (m_token_roots[token].find(channel) == m_token_roots[token].end()) {
327 m_token_roots[token][channel] = std::make_shared<RootNode>(token, channel);
328 }
329}
330
332{
333 for (uint32_t ch = 0; ch < num_channels; ++ch) {
334 ensure_root_exists(token, ch);
335 }
336}
337
338void NodeGraphManager::register_global(const std::shared_ptr<Node>& node)
339{
340 if (!is_node_registered(node)) {
341 std::stringstream ss;
342 ss << "node_" << node.get();
343 std::string generated_id = ss.str();
344 m_Node_registry[generated_id] = node;
345 }
346}
347
348void NodeGraphManager::set_channel_mask(const std::shared_ptr<Node>& node, uint32_t channel_id)
349{
350 register_global(node);
351 node->register_channel_usage(channel_id);
352}
353
354void NodeGraphManager::unregister_global(const std::shared_ptr<Node>& node)
355{
356 for (const auto& pair : m_Node_registry) {
357 if (pair.second == node) {
358 m_Node_registry.erase(pair.first);
359 break;
360 }
361 }
362}
363
364void NodeGraphManager::unset_channel_mask(const std::shared_ptr<Node>& node, uint32_t channel_id)
365{
366 unregister_global(node);
367 node->unregister_channel_usage(channel_id);
368}
369
370std::vector<ProcessingToken> NodeGraphManager::get_active_tokens() const
371{
372 std::vector<ProcessingToken> tokens;
373 for (const auto& [token, channels] : m_token_roots) {
374 if (!channels.empty()) {
375 tokens.push_back(token);
376 }
377 }
378 return tokens;
379}
380
381std::vector<unsigned int> NodeGraphManager::get_all_channels(ProcessingToken token) const
382{
383 std::vector<unsigned int> channels;
384 auto it = m_token_roots.find(token);
385 if (it != m_token_roots.end()) {
386 for (const auto& [channel, root] : it->second) {
387 channels.push_back(channel);
388 }
389 }
390 return channels;
391}
392
394{
395 size_t count = 0;
396 auto it = m_token_roots.find(token);
397 if (it != m_token_roots.end()) {
398 for (const auto& [channel, root] : it->second) {
399 count += root->get_node_size();
400 }
401 }
402 return count;
403}
404
406{
409 "=== NodeGraphManager Summary ===");
410
411 for (auto token : get_active_tokens()) {
412 auto channels = get_all_channels(token);
413 size_t total_nodes = get_node_count(token);
414
417 "Token {}: {} nodes across {} channels",
418 static_cast<int>(token), total_nodes, channels.size());
419
420 for (auto channel : channels) {
421 auto& root = const_cast<NodeGraphManager*>(this)->get_root_node(token, channel);
422 auto networks = get_networks(token, channel);
423
426 " Channel {}: {} nodes, {} networks",
427 channel, root.get_node_size(), networks.size());
428
429 for (const auto& network : networks) {
430 if (network) {
433 " Network: {} internal nodes, mode={}, enabled={}",
434 network->get_node_count(),
435 static_cast<int>(network->get_output_mode()),
436 network->is_enabled());
437 }
438 }
439 }
440 }
441}
442
443std::shared_ptr<Node> NodeGraphManager::get_node(const std::string& id)
444{
445 auto it = m_Node_registry.find(id);
446
447 if (it != m_Node_registry.end()) {
448 return it->second;
449 }
450 return nullptr;
451}
452
453bool NodeGraphManager::is_node_registered(const std::shared_ptr<Node>& node)
454{
455 return std::ranges::any_of(m_Node_registry,
456 [&node](const auto& pair) { return pair.second == node; });
457}
458
459void NodeGraphManager::connect(const std::string& source_id, const std::string& target_id)
460{
461 auto source = get_node(source_id);
462 auto target = get_node(target_id);
463
464 if (source && target) {
465 auto chain = std::make_shared<ChainNode>(source, target, *this);
466 chain->initialize();
467 }
468}
469
470//-----------------------------------------------------------------------------
471// NodeNetwork Management
472//-----------------------------------------------------------------------------
473
474void NodeGraphManager::add_network(const std::shared_ptr<Network::NodeNetwork>& network,
475 ProcessingToken token)
476{
477 if (!network) {
478 return;
479 }
480
482
483 network->set_enabled(true);
484
485 if (network->get_output_mode() == Network::OutputMode::AUDIO_SINK
486 || network->get_output_mode() == Network::OutputMode::AUDIO_COMPUTE) {
487 uint32_t channel_mask = network->get_channel_mask();
488
489 if (channel_mask == 0) {
490 channel_mask = 1;
491 network->add_channel_usage(0);
492 }
493
494 auto channels = network->get_registered_channels();
495 m_audio_networks[token].push_back(network);
496
497 for (auto ch : channels) {
498 ensure_root_exists(token, ch);
501 "Added audio network to token {} channel {}: {} nodes",
502 static_cast<int>(token), ch, network->get_node_count());
503 }
504
505 } else {
506 m_token_networks[token].push_back(network);
507
510 "Added network to token {}: {} nodes, mode={}",
511 static_cast<int>(token),
512 network->get_node_count(),
513 static_cast<int>(network->get_output_mode()));
514 }
515}
516
517void NodeGraphManager::remove_network(const std::shared_ptr<Network::NodeNetwork>& network,
518 ProcessingToken token)
519{
520 if (!network) {
521 return;
522 }
523
524 if (network->get_output_mode() == Network::OutputMode::AUDIO_SINK
525 || network->get_output_mode() == Network::OutputMode::AUDIO_COMPUTE) {
526 auto token_it = m_audio_networks.find(token);
527 if (token_it != m_audio_networks.end()) {
528 auto& networks = token_it->second;
529 std::erase_if(networks, [&](const auto& n) { return n == network; });
530 }
531 } else {
532 auto it = m_token_networks.find(token);
533 if (it != m_token_networks.end()) {
534 auto& networks = it->second;
535 std::erase_if(networks, [&](const auto& n) { return n == network; });
536 }
537 }
538
540}
541
542std::vector<std::shared_ptr<Network::NodeNetwork>>
543NodeGraphManager::get_networks(ProcessingToken token, unsigned int channel) const
544{
545 auto token_it = m_audio_networks.find(token);
546 if (token_it != m_audio_networks.end()) {
547 std::vector<std::shared_ptr<Network::NodeNetwork>> networks_on_channel;
548 for (const auto& network : token_it->second) {
549 if (network && network->is_registered_on_channel(channel)) {
550 networks_on_channel.push_back(network);
551 }
552 }
553 return networks_on_channel;
554 }
555 return {};
556}
557
558std::vector<std::shared_ptr<Network::NodeNetwork>>
560{
561 std::vector<std::shared_ptr<Network::NodeNetwork>> all_networks;
562
563 auto audio_it = m_audio_networks.find(token);
564 if (audio_it != m_audio_networks.end()) {
565 all_networks.insert(all_networks.end(),
566 audio_it->second.begin(),
567 audio_it->second.end());
568 }
569
570 auto token_it = m_token_networks.find(token);
571 if (token_it != m_token_networks.end()) {
572 all_networks.insert(all_networks.end(),
573 token_it->second.begin(),
574 token_it->second.end());
575 }
576
577 return all_networks;
578}
579
581{
582 size_t count = 0;
583
584 auto audio_it = m_audio_networks.find(token);
585 if (audio_it != m_audio_networks.end()) {
586 count += audio_it->second.size();
587 }
588
589 auto token_it = m_token_networks.find(token);
590 if (token_it != m_token_networks.end()) {
591 count += token_it->second.size();
592 }
593
594 return count;
595}
596
598{
599 m_audio_networks.erase(token);
600 m_token_networks.erase(token);
601}
602
603void NodeGraphManager::register_network_global(const std::shared_ptr<Network::NodeNetwork>& network)
604{
605 if (!is_network_registered(network)) {
606 std::stringstream ss;
607 ss << "network_" << network.get();
608 std::string generated_id = ss.str();
609 m_network_registry[generated_id] = network;
610 network->set_sample_rate(m_registered_sample_rate);
611 network->set_block_size(m_registered_block_size);
612 }
613}
614
615void NodeGraphManager::unregister_network_global(const std::shared_ptr<Network::NodeNetwork>& network)
616{
617 for (const auto& pair : m_network_registry) {
618 if (pair.second == network) {
619 m_network_registry.erase(pair.first);
620 break;
621 }
622 }
623}
624
625bool NodeGraphManager::is_network_registered(const std::shared_ptr<Network::NodeNetwork>& network)
626{
627 return std::ranges::any_of(m_network_registry,
628 [&network](const auto& pair) { return pair.second == network; });
629}
630
632{
633 if (m_terminate_requested.load())
634 return;
635
636 for (auto& [token, networks] : m_audio_networks) {
637 for (auto& network : networks) {
638 if (network) {
640 }
641 }
642 }
643
644 for (auto& [token, networks] : m_token_networks) {
645 for (auto& network : networks) {
646 if (network) {
648 }
649 }
650 }
651
652 m_terminate_requested.store(true);
653
654 for (auto token : get_active_tokens()) {
655 auto roots = get_all_root_nodes(token);
656 for (auto* root : roots) {
657 root->terminate_all_nodes();
658 }
659 }
660}
661
672
674{
675 for (const auto& [id, node] : m_Node_registry) {
676 if (!node->needs_channel_routing())
677 continue;
678 update_routing_state(node->get_routing_state());
679 }
680
681 for (const auto& network : get_all_networks(token)) {
682 if (!network || !network->needs_channel_routing())
683 continue;
684 update_routing_state(network->get_routing_state());
685 }
686}
687
689 const std::shared_ptr<Node>& node,
690 const std::vector<uint32_t>& target_channels,
691 uint32_t fade_cycles,
692 ProcessingToken token)
693{
694 uint32_t current_channels = node->get_channel_mask();
695
696 uint32_t target_bitmask = 0;
697 for (auto ch : target_channels) {
698 target_bitmask |= (1 << ch);
699 }
700
701 uint32_t fade_blocks = (fade_cycles + m_registered_block_size - 1) / m_registered_block_size;
702 fade_blocks = std::max(1U, fade_blocks);
703
704 RoutingState state;
705 state.from_channels = current_channels;
706 state.to_channels = target_bitmask;
707 state.fade_cycles = fade_blocks;
708 state.phase = RoutingState::ACTIVE;
709
710 for (uint32_t ch = 0; ch < 32; ch++) {
711 state.amount[ch] = (current_channels & (1 << ch)) ? 1.0 : 0.0;
712 }
713
714 node->get_routing_state() = state;
715
716 for (auto ch : target_channels) {
717 if (!(current_channels & (1 << ch))) {
718 add_to_root(node, token, ch);
719 }
720 }
721}
722
724 const std::shared_ptr<Network::NodeNetwork>& network,
725 const std::vector<uint32_t>& target_channels,
726 uint32_t fade_cycles,
727 ProcessingToken token)
728{
729 if (network->get_output_mode() != Network::OutputMode::AUDIO_SINK) {
732 "Attempted to route network that is not an audio sink. Operation ignored.");
733 return;
734 }
735
737 network->set_enabled(true);
738
739 auto& networks = m_audio_networks[token];
740 if (std::ranges::find(networks, network) == networks.end()) {
741 networks.push_back(network);
742 }
743
744 uint32_t current_channels = network->get_channel_mask();
745
746 uint32_t target_bitmask = 0;
747 for (auto ch : target_channels) {
748 target_bitmask |= (1 << ch);
749 }
750
751 uint32_t combined_mask = current_channels | target_bitmask;
752 network->set_channel_mask(combined_mask);
753 for (auto ch : target_channels) {
754 network->add_channel_usage(ch);
755 ensure_root_exists(token, ch);
756 }
757
758 uint32_t fade_blocks = (fade_cycles + m_registered_block_size - 1) / m_registered_block_size;
759 fade_blocks = std::max(1u, fade_blocks);
760
761 RoutingState state;
762 state.from_channels = current_channels;
763 state.to_channels = target_bitmask;
764 state.fade_cycles = fade_blocks;
765 state.phase = RoutingState::ACTIVE;
766
767 for (uint32_t ch = 0; ch < 32; ch++) {
768 state.amount[ch] = (current_channels & (1 << ch)) ? 1.0 : 0.0;
769 }
770
771 network->get_routing_state() = state;
772}
773
775{
776 std::vector<std::pair<std::shared_ptr<Node>, uint32_t>> nodes_to_remove;
777
778 for (const auto& [id, node] : m_Node_registry) {
779 if (!node->needs_channel_routing())
780 continue;
781
782 auto& state = node->get_routing_state();
783
784 if (state.phase == RoutingState::COMPLETED) {
785 for (uint32_t ch = 0; ch < 32; ch++) {
786 if ((state.from_channels & (1 << ch)) && !(state.to_channels & (1 << ch))) {
787 nodes_to_remove.emplace_back(node, ch);
788 }
789 }
790 state = RoutingState {};
791 }
792 }
793
794 for (auto& [node, channel] : nodes_to_remove) {
795 remove_from_root(node, token, channel);
796 }
797
798 std::vector<std::pair<std::shared_ptr<Network::NodeNetwork>, uint32_t>> networks_to_cleanup;
799
800 for (const auto& network : get_all_networks(token)) {
801 if (!network || !network->needs_channel_routing())
802 continue;
803
804 auto& state = network->get_routing_state();
805
806 if (state.phase == RoutingState::COMPLETED) {
807 network->set_channel_mask(state.to_channels);
808
809 for (uint32_t ch = 0; ch < 32; ch++) {
810 if ((state.from_channels & (1 << ch)) && !(state.to_channels & (1 << ch))) {
811 networks_to_cleanup.emplace_back(network, ch);
812 }
813 }
814 state = RoutingState {};
815 }
816 }
817
818 for (auto& [network, channel] : networks_to_cleanup) {
819 network->remove_channel_usage(channel);
820
821 if (network->get_channel_mask() == 0) {
822 auto& networks = m_audio_networks[token];
823 std::erase_if(networks, [&](const auto& n) { return n == network; });
825 }
826 }
827}
828
829}
#define MF_INFO(comp, ctx,...)
#define MF_PRINT(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
Eigen::Index count
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.
NodeGraphManager(uint32_t sample_rate=48000, uint32_t block_size=512)
Creates a new NodeGraphManager.
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.
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.
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:11
@ 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