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