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
11namespace {
12 const std::vector<std::shared_ptr<Node>> empty {};
13}
14
15NodeGraphManager::NodeGraphManager(uint32_t sample_rate, uint32_t block_size, uint32_t frame_rate)
16 : m_registered_sample_rate(sample_rate)
17 , m_registered_block_size(block_size)
18 , m_registered_frame_rate(frame_rate)
19{
21}
22
23void NodeGraphManager::add_to_root(const std::shared_ptr<Node>& node,
24 ProcessingToken token,
25 unsigned int channel)
26{
27 set_channel_mask(node, channel);
28 node->set_sample_rate(m_registered_sample_rate);
29 node->set_frame_rate(m_registered_frame_rate);
30
31 if (token == ProcessingToken::VISUAL_RATE) {
32 node->set_gpu_compatible(true);
33 }
34
35 auto& root = get_root_node(token, channel);
36 root.register_node(node);
37}
38
39void NodeGraphManager::remove_from_root(const std::shared_ptr<Node>& node,
40 ProcessingToken token,
41 unsigned int channel)
42{
43 unset_channel_mask(node, channel);
44
45 auto& root = get_root_node(token, channel);
46 root.unregister_node(node);
47}
48
49const std::vector<std::shared_ptr<Node>>&
50NodeGraphManager::get_nodes(ProcessingToken token, uint32_t channel) const
51{
52
53 auto token_it = m_token_roots.find(token);
54 if (token_it == m_token_roots.end()) {
57 "Attempted to get nodes for non-existent token {}. Returning empty vector.",
59 return empty;
60 }
61 auto channel_it = token_it->second.find(channel);
62
63 if (channel_it == token_it->second.end()) {
66 "Attempted to get nodes for token {} channel {} which does not exist. Returning empty vector.",
67 Reflect::enum_to_string(token), channel);
68 return empty;
69 }
70
71 return channel_it->second->nodes();
72}
73
75 std::function<void(std::span<RootNode*>)> processor)
76{
77 m_token_processors[token] = std::move(processor);
78}
79
80const std::unordered_map<unsigned int, std::shared_ptr<RootNode>>& NodeGraphManager::get_all_channel_root_nodes(ProcessingToken token) const
81{
82 static std::unordered_map<unsigned int, std::shared_ptr<RootNode>> audio_roots;
83 audio_roots.clear();
84
85 auto it = m_token_roots.find(token);
86 if (it != m_token_roots.end()) {
87 for (const auto& [channel, root] : it->second) {
88 audio_roots[channel] = root;
89 }
90 }
91 return audio_roots;
92}
93
95{
96 auto& processing_ptr = m_token_network_processing[token];
97
98 if (!processing_ptr) {
99 processing_ptr = std::make_unique<std::atomic<bool>>(false);
100 }
101
102 bool expected = false;
103 return processing_ptr->compare_exchange_strong(
104 expected, true,
105 std::memory_order_acquire,
106 std::memory_order_relaxed);
107}
108
109void NodeGraphManager::process_token(ProcessingToken token, unsigned int num_samples)
110{
111 if (m_terminate_requested.load())
112 return;
113
114 auto roots = get_all_root_nodes(token);
115
116 if (auto it = m_token_processors.find(token); it != m_token_processors.end()) {
117 it->second(std::span<RootNode*>(roots.data(), roots.size()));
118 return;
119 }
120
121 if (!preprocess_networks(token)) {
122 return;
123 }
124
125 auto it = m_token_networks.find(token);
126 if (it != m_token_networks.end()) {
127 for (auto& network : it->second) {
128 if (!network || !network->is_enabled()) {
129 continue;
130 }
131
132 if (!network->is_processed_this_cycle()) {
133 network->mark_processing(true);
134 network->process_batch(num_samples);
135 network->mark_processing(false);
136 network->mark_processed(true);
137 }
138 }
139 }
140
141 postprocess_networks(token, std::nullopt);
142
143 if (token == ProcessingToken::AUDIO_RATE) {
144 for (auto* root : roots) {
145 root->process_batch(num_samples);
146 }
147 } else if (token == ProcessingToken::VISUAL_RATE) {
148 for (auto* root : roots) {
149 root->process_batch_frame(num_samples);
150 }
151 }
152}
153
154std::vector<std::vector<double>> NodeGraphManager::process_audio_networks(ProcessingToken token, uint32_t num_samples, uint32_t channel)
155{
156 if (!preprocess_networks(token)) {
157 return {};
158 }
159
160 std::vector<std::vector<double>> all_network_outputs;
161
162 auto audio_it = m_audio_networks.find(token);
163 if (audio_it != m_audio_networks.end()) {
164 for (auto& network : audio_it->second) {
165 if (!network || !network->is_enabled()) {
166 continue;
167 }
168
169 if (!network->is_registered_on_channel(channel)) {
170 continue;
171 }
172
173 if (!network->is_processed_this_cycle()) {
174 network->mark_processing(true);
175 network->process_batch(num_samples);
176 network->mark_processing(false);
177 network->mark_processed(true);
178 }
179
180 const auto& net_buffer = network->get_audio_buffer();
181 if (net_buffer && network->get_output_mode() == Network::OutputMode::AUDIO_SINK) {
182 if (network->needs_channel_routing()) {
183 double scale = network->get_routing_state().amount[channel];
184 if (scale == 0.0)
185 continue;
186
187 if (scale == 1.0) {
188 all_network_outputs.push_back(*net_buffer);
189 } else {
190 std::vector<double> scaled_buffer = *net_buffer;
191 for (auto& sample : scaled_buffer)
192 sample *= scale;
193
194 all_network_outputs.push_back(std::move(scaled_buffer));
195 }
196 } else {
197 all_network_outputs.push_back(*net_buffer);
198 }
199 }
200 }
201 }
202
203 postprocess_networks(token, channel);
204 return all_network_outputs;
205}
206
207void NodeGraphManager::postprocess_networks(ProcessingToken token, std::optional<uint32_t> channel)
208{
209 if (token == ProcessingToken::AUDIO_RATE && channel.has_value()) {
210 auto ch = channel.value_or(0U);
211 reset_audio_network_state(token, ch);
212 } else if (auto it = m_token_networks.find(token); it != m_token_networks.end()) {
213 for (auto& network : it->second) {
214 if (network && network->is_enabled()) {
215 network->mark_processed(false);
216 }
217 }
218 }
219
220 if (auto it = m_token_network_processing.find(token); it != m_token_network_processing.end()) {
221 it->second->store(false, std::memory_order_release);
222 }
223}
224
226{
227 auto audio_it = m_audio_networks.find(token);
228 if (audio_it != m_audio_networks.end()) {
229 for (auto& network : audio_it->second) {
230 if (network) {
231 if (network->is_registered_on_channel(channel)) {
232 network->request_reset_from_channel(channel);
233 }
234 }
235 }
236 }
237}
238
244
246 TokenSampleProcessor processor)
247{
248 m_token_sample_processors[token] = std::move(processor);
249}
250
252 unsigned int channel, unsigned int num_samples)
253{
254 if (channel == 0) {
256 }
257
258 auto& root = get_root_node(token, channel);
259
260 if (auto it = m_token_channel_processors.find(token); it != m_token_channel_processors.end()) {
261 return it->second(&root, num_samples);
262 }
263
264 std::vector<double> samples = root.process_batch(num_samples);
265
266 uint32_t normalize_coef = root.get_node_size();
267 for (double& sample : samples) {
268 normalize_sample(sample, normalize_coef);
269 }
270 return samples;
271}
272
274{
275 if (m_terminate_requested.load())
276 return 0.0;
277
278 auto& root = get_root_node(token, channel);
279
280 if (auto it = m_token_sample_processors.find(token); it != m_token_sample_processors.end()) {
281 return it->second(&root, channel);
282 }
283
284 double sample = root.process_sample();
285 normalize_sample(sample, root.get_node_size());
286 return sample;
287}
288
289void NodeGraphManager::normalize_sample(double& sample, uint32_t num_nodes)
290{
291 if (num_nodes == 0)
292 return;
293
294 sample /= std::sqrt(static_cast<double>(num_nodes));
295
296 const double threshold = 0.95;
297 const double knee = 0.1;
298 const double abs_sample = std::abs(sample);
299
300 if (abs_sample > threshold) {
301 const double excess = abs_sample - threshold;
302 const double compressed_excess = std::tanh(excess / knee) * knee;
303 const double limited_abs = threshold + compressed_excess;
304 sample = std::copysign(limited_abs, sample);
305 }
306}
307
308std::unordered_map<unsigned int, std::vector<double>> NodeGraphManager::process_token_with_channel_data(
309 ProcessingToken token, unsigned int num_samples)
310{
311 std::unordered_map<unsigned int, std::vector<double>> channel_data;
312
313 auto channels = get_all_channels(token);
314
315 for (unsigned int channel : channels) {
316 channel_data[channel] = process_channel(token, channel, num_samples);
317 }
318
319 return channel_data;
320}
321
323{
324 auto channels = get_all_channels(token);
325 return static_cast<unsigned int>(channels.size());
326}
327
329{
330 std::vector<RootNode*> roots;
331
332 auto it = m_token_roots.find(token);
333 if (it != m_token_roots.end()) {
334 for (auto& [channel, root] : it->second) {
335 roots.push_back(root.get());
336 }
337 }
338
339 return roots;
340}
341
342void NodeGraphManager::process_all_tokens(unsigned int num_samples)
343{
344 for (auto token : get_active_tokens()) {
345 process_token(token, num_samples);
346 }
347}
348
350{
351 ensure_root_exists(token, channel);
352 return *m_token_roots[token][channel];
353}
354
356{
357 if (m_token_roots[token].find(channel) == m_token_roots[token].end()) {
358 m_token_roots[token][channel] = std::make_shared<RootNode>(token, channel);
359 }
360}
361
363{
364 for (uint32_t ch = 0; ch < num_channels; ++ch) {
365 ensure_root_exists(token, ch);
366 }
367}
368
369void NodeGraphManager::register_global(const std::shared_ptr<Node>& node)
370{
371 m_node_registry.insert(node);
372}
373
374void NodeGraphManager::set_channel_mask(const std::shared_ptr<Node>& node, uint32_t channel_id)
375{
376 register_global(node);
377 node->register_channel_usage(channel_id);
378}
379
380void NodeGraphManager::unregister_global(const std::shared_ptr<Node>& node)
381{
382 m_node_registry.erase(node);
383}
384
385void NodeGraphManager::unset_channel_mask(const std::shared_ptr<Node>& node, uint32_t channel_id)
386{
387 unregister_global(node);
388 node->unregister_channel_usage(channel_id);
389}
390
391std::vector<ProcessingToken> NodeGraphManager::get_active_tokens() const
392{
393 std::vector<ProcessingToken> tokens;
394 for (const auto& [token, channels] : m_token_roots) {
395 if (!channels.empty()) {
396 tokens.push_back(token);
397 }
398 }
399 return tokens;
400}
401
402std::vector<unsigned int> NodeGraphManager::get_all_channels(ProcessingToken token) const
403{
404 std::vector<unsigned int> channels;
405 auto it = m_token_roots.find(token);
406 if (it != m_token_roots.end()) {
407 for (const auto& [channel, root] : it->second) {
408 channels.push_back(channel);
409 }
410 }
411 return channels;
412}
413
415{
416 size_t count = 0;
417 auto it = m_token_roots.find(token);
418 if (it != m_token_roots.end()) {
419 for (const auto& [channel, root] : it->second) {
420 count += root->get_node_size();
421 }
422 }
423 return count;
424}
425
426bool NodeGraphManager::is_node_registered(const std::shared_ptr<Node>& node)
427{
428 return m_node_registry.contains(node);
429}
430
431//-----------------------------------------------------------------------------
432// NodeNetwork Management
433//-----------------------------------------------------------------------------
434
435void NodeGraphManager::add_network(const std::shared_ptr<Network::NodeNetwork>& network,
436 ProcessingToken token)
437{
438 if (!network) {
439 return;
440 }
441
443
444 network->set_enabled(true);
445
446 if (network->get_output_mode() == Network::OutputMode::AUDIO_SINK
447 || network->get_output_mode() == Network::OutputMode::AUDIO_COMPUTE) {
448 uint32_t channel_mask = network->get_channel_mask();
449
450 if (channel_mask == 0) {
451 channel_mask = 1;
452 network->add_channel_usage(0);
453 }
454
455 auto channels = network->get_registered_channels();
456 m_audio_networks[token].push_back(network);
457
458 for (auto ch : channels) {
459 ensure_root_exists(token, ch);
462 "Added audio network to token {} channel {}: {} nodes",
463 static_cast<int>(token), ch, network->get_node_count());
464 }
465
466 } else {
467 m_token_networks[token].push_back(network);
468
471 "Added network to token {}: {} nodes, mode={}",
472 static_cast<int>(token),
473 network->get_node_count(),
474 static_cast<int>(network->get_output_mode()));
475 }
476}
477
478void NodeGraphManager::remove_network(const std::shared_ptr<Network::NodeNetwork>& network,
479 ProcessingToken token)
480{
481 if (!network) {
482 return;
483 }
484
485 if (network->get_output_mode() == Network::OutputMode::AUDIO_SINK
486 || network->get_output_mode() == Network::OutputMode::AUDIO_COMPUTE) {
487 auto token_it = m_audio_networks.find(token);
488 if (token_it != m_audio_networks.end()) {
489 auto& networks = token_it->second;
490 std::erase_if(networks, [&](const auto& n) { return n == network; });
491 }
492 } else {
493 auto it = m_token_networks.find(token);
494 if (it != m_token_networks.end()) {
495 auto& networks = it->second;
496 std::erase_if(networks, [&](const auto& n) { return n == network; });
497 }
498 }
499
501}
502
503std::vector<std::shared_ptr<Network::NodeNetwork>>
505{
506 if (token == ProcessingToken::AUDIO_RATE) {
507 auto it = m_audio_networks.find(token);
508 if (it == m_audio_networks.end())
509 return {};
510
511 std::vector<std::shared_ptr<Network::NodeNetwork>> result;
512
513 for (const auto& n : it->second) {
514 if (n && n->is_registered_on_channel(channel))
515 result.push_back(n);
516 }
517 return result;
518 }
519
520 auto it = m_token_networks.find(token);
521 if (it == m_token_networks.end())
522 return {};
523 return it->second;
524}
525
526std::vector<std::shared_ptr<Network::NodeNetwork>>
528{
529 std::vector<std::shared_ptr<Network::NodeNetwork>> all_networks;
530
531 auto audio_it = m_audio_networks.find(token);
532 if (audio_it != m_audio_networks.end()) {
533 all_networks.insert(all_networks.end(),
534 audio_it->second.begin(),
535 audio_it->second.end());
536 }
537
538 auto token_it = m_token_networks.find(token);
539 if (token_it != m_token_networks.end()) {
540 all_networks.insert(all_networks.end(),
541 token_it->second.begin(),
542 token_it->second.end());
543 }
544
545 return all_networks;
546}
547
549{
550 size_t count = 0;
551
552 auto audio_it = m_audio_networks.find(token);
553 if (audio_it != m_audio_networks.end()) {
554 count += audio_it->second.size();
555 }
556
557 auto token_it = m_token_networks.find(token);
558 if (token_it != m_token_networks.end()) {
559 count += token_it->second.size();
560 }
561
562 return count;
563}
564
566{
567 m_audio_networks.erase(token);
568 m_token_networks.erase(token);
569}
570
571void NodeGraphManager::register_network_global(const std::shared_ptr<Network::NodeNetwork>& network)
572{
573 if (m_network_registry.insert(network).second) {
574 network->set_sample_rate(m_registered_sample_rate);
575 network->set_block_size(m_registered_block_size);
576 }
577}
578
579void NodeGraphManager::unregister_network_global(const std::shared_ptr<Network::NodeNetwork>& network)
580{
582}
583
584bool NodeGraphManager::is_network_registered(const std::shared_ptr<Network::NodeNetwork>& network)
585{
586 return m_network_registry.contains(network);
587}
588
590{
591 if (m_terminate_requested.load())
592 return;
593
594 for (auto& [token, networks] : m_audio_networks) {
595 for (auto& network : networks) {
596 if (network) {
598 }
599 }
600 }
601
602 for (auto& [token, networks] : m_token_networks) {
603 for (auto& network : networks) {
604 if (network) {
606 }
607 }
608 }
609
610 m_terminate_requested.store(true);
611
612 for (auto token : get_active_tokens()) {
613 auto roots = get_all_root_nodes(token);
614 for (auto* root : roots) {
615 root->terminate_all_nodes();
616 }
617 }
618}
619
630
632{
633 for (const auto& node : m_node_registry) {
634 if (!node->needs_channel_routing())
635 continue;
636 update_routing_state(node->get_routing_state());
637 }
638
639 for (const auto& network : get_all_networks(token)) {
640 if (!network || !network->needs_channel_routing())
641 continue;
642 update_routing_state(network->get_routing_state());
643 }
644}
645
647 const std::shared_ptr<Node>& node,
648 const std::vector<uint32_t>& target_channels,
649 uint32_t fade_cycles,
650 ProcessingToken token)
651{
652 uint32_t current_channels = node->get_channel_mask();
653
654 uint32_t target_bitmask = 0;
655 for (auto ch : target_channels) {
656 target_bitmask |= (1 << ch);
657 }
658
659 uint32_t fade_blocks = (fade_cycles + m_registered_block_size - 1) / m_registered_block_size;
660 fade_blocks = std::max(1U, fade_blocks);
661
662 RoutingState state;
663 state.from_channels = current_channels;
664 state.to_channels = target_bitmask;
665 state.fade_cycles = fade_blocks;
666 state.phase = RoutingState::ACTIVE;
667
668 for (uint32_t ch = 0; ch < 32; ch++) {
669 state.amount[ch] = (current_channels & (1 << ch)) ? 1.0 : 0.0;
670 }
671
672 node->get_routing_state() = state;
673
674 for (auto ch : target_channels) {
675 if (!(current_channels & (1 << ch))) {
676 add_to_root(node, token, ch);
677 }
678 }
679}
680
682 const std::shared_ptr<Network::NodeNetwork>& network,
683 const std::vector<uint32_t>& target_channels,
684 uint32_t fade_cycles,
685 ProcessingToken token)
686{
687 if (network->get_output_mode() != Network::OutputMode::AUDIO_SINK) {
690 "Attempted to route network that is not an audio sink. Operation ignored.");
691 return;
692 }
693
695 network->set_enabled(true);
696
697 auto& networks = m_audio_networks[token];
698 if (std::ranges::find(networks, network) == networks.end()) {
699 networks.push_back(network);
700 }
701
702 uint32_t current_channels = network->get_channel_mask();
703
704 uint32_t target_bitmask = 0;
705 for (auto ch : target_channels) {
706 target_bitmask |= (1 << ch);
707 }
708
709 uint32_t combined_mask = current_channels | target_bitmask;
710 network->set_channel_mask(combined_mask);
711 for (auto ch : target_channels) {
712 network->add_channel_usage(ch);
713 ensure_root_exists(token, ch);
714 }
715
716 uint32_t fade_blocks = (fade_cycles + m_registered_block_size - 1) / m_registered_block_size;
717 fade_blocks = std::max(1U, fade_blocks);
718
719 RoutingState state;
720 state.from_channels = current_channels;
721 state.to_channels = target_bitmask;
722 state.fade_cycles = fade_blocks;
723 state.phase = RoutingState::ACTIVE;
724
725 for (uint32_t ch = 0; ch < 32; ch++) {
726 state.amount[ch] = (current_channels & (1 << ch)) ? 1.0 : 0.0;
727 }
728
729 network->get_routing_state() = state;
730}
731
733{
734 std::vector<std::pair<std::shared_ptr<Node>, uint32_t>> nodes_to_remove;
735
736 for (const auto& node : m_node_registry) {
737 if (!node->needs_channel_routing())
738 continue;
739
740 auto& state = node->get_routing_state();
741
742 if (state.phase == RoutingState::COMPLETED) {
743 for (uint32_t ch = 0; ch < 32; ch++) {
744 if ((state.from_channels & (1 << ch)) && !(state.to_channels & (1 << ch))) {
745 nodes_to_remove.emplace_back(node, ch);
746 }
747 }
748 state = RoutingState {};
749 }
750 }
751
752 for (auto& [node, channel] : nodes_to_remove) {
753 remove_from_root(node, token, channel);
754 }
755
756 std::vector<std::pair<std::shared_ptr<Network::NodeNetwork>, uint32_t>> networks_to_cleanup;
757
758 for (const auto& network : get_all_networks(token)) {
759 if (!network || !network->needs_channel_routing())
760 continue;
761
762 auto& state = network->get_routing_state();
763
764 if (state.phase == RoutingState::COMPLETED) {
765 network->set_channel_mask(state.to_channels);
766
767 for (uint32_t ch = 0; ch < 32; ch++) {
768 if ((state.from_channels & (1 << ch)) && !(state.to_channels & (1 << ch))) {
769 networks_to_cleanup.emplace_back(network, ch);
770 }
771 }
772 state = RoutingState {};
773 }
774 }
775
776 for (auto& [network, channel] : networks_to_cleanup) {
777 network->remove_channel_usage(channel);
778
779 if (network->get_channel_mask() == 0) {
780 auto& networks = m_audio_networks[token];
781 std::erase_if(networks, [&](const auto& n) { return n == network; });
783 }
784 }
785}
786
787}
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
Core::GlobalNetworkConfig network
Definition Config.cpp:37
size_t 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.
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.
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_set< 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.
std::unordered_set< std::shared_ptr< Network::NodeNetwork > > m_network_registry
Global network registry (like m_Node_registry)
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.
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.
const std::vector< std::shared_ptr< Node > > & get_nodes(ProcessingToken token, uint32_t channel=0) const
Get all nodes from their respective root nodes for a specific token and/or channel.
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.
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:14
constexpr std::string_view enum_to_string(EnumType value) noexcept
Universal enum to string converter using magic_enum (original case)
@ 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