MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Node.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "GpuContext.hpp"
5
6/**
7 * @namespace MayaFlux::Nodes
8 * @brief Contains the node-based computational processing system components
9 *
10 * The Nodes namespace provides a flexible, composable processing architecture
11 * based on the concept of interconnected computational nodes. Each node represents a
12 * discrete transformation unit that can be connected to other nodes to form
13 * complex processing networks and computational graphs.
14 */
15namespace MayaFlux::Nodes {
16
17/**
18 * @class NodeContext
19 * @brief Base context class for node callbacks
20 *
21 * Provides basic context information for callbacks and can be
22 * extended by specific node types to include additional context.
23 * The NodeContext serves as a container for node state information
24 * that is passed to callback functions, allowing callbacks to
25 * access relevant node data during execution.
26 *
27 * Node implementations can extend this class to provide type-specific
28 * context information, which can be safely accessed using the as<T>() method.
29 */
30class MAYAFLUX_API NodeContext {
31public:
32 virtual ~NodeContext() = default;
33
34 /**
35 * @brief Current sample value
36 *
37 * The most recent output value produced by the node.
38 * This is the primary data point that callbacks will typically use.
39 */
40 double value;
41
42 /**
43 * @brief Type identifier for runtime type checking
44 *
45 * String identifier that represents the concrete type of the context.
46 * Used for safe type casting with the as<T>() method.
47 */
48 std::string type_id;
49
50 /**
51 * @brief Safely cast to a derived context type
52 * @tparam T The derived context type to cast to
53 * @return Pointer to the derived context or nullptr if types don't match
54 *
55 * Provides type-safe access to derived context classes. If the requested
56 * type matches the actual type of this context, returns a properly cast
57 * pointer. Otherwise, returns nullptr to prevent unsafe access.
58 *
59 * Example:
60 * ```cpp
61 * if (auto filter_ctx = ctx.as<FilterContext>()) {
62 * // Access filter-specific context members
63 * double gain = filter_ctx->gain;
64 * }
65 * ```
66 */
67 template <typename T>
68 T* as()
69 {
70 if (typeid(T).name() == type_id) {
71 return static_cast<T*>(this);
72 }
73 return nullptr;
74 }
75
76 template <typename T>
77 const T* as() const
78 {
79 if (typeid(T).name() == type_id) {
80 return static_cast<const T*>(this);
81 }
82 return nullptr;
83 }
84
85protected:
86 /**
87 * @brief Protected constructor for NodeContext
88 * @param value The current sample value
89 * @param type String identifier for the context type
90 *
91 * This constructor is protected to ensure that only derived classes
92 * can create context objects, with proper type identification.
93 */
94 NodeContext(double value, std::string type)
95 : value(value)
96 , type_id(std::move(type))
97 {
98 }
99};
100
101/**
102 * @class Node
103 * @brief Base interface for all computational processing nodes
104 *
105 * The Node class defines the fundamental interface for all processing components
106 * in the MayaFlux engine. Nodes are the basic building blocks of transformation chains
107 * and can be connected together to create complex computational graphs.
108 *
109 * Each node processes data on a sample-by-sample basis, allowing for flexible
110 * real-time processing. Nodes can be:
111 * - Connected in series (output of one feeding into input of another)
112 * - Combined in parallel (outputs mixed together)
113 * - Multiplied (outputs multiplied together)
114 *
115 * The node system supports both single-sample processing for real-time applications
116 * and batch processing for more efficient offline processing.
117 */
118class MAYAFLUX_API Node {
119
120public:
121 /**
122 * @brief Virtual destructor for proper cleanup of derived classes
123 */
124 virtual ~Node() = default;
125
126 /**
127 * @brief Processes a single data sample
128 * @param input The input sample value
129 * @return The processed output sample value
130 *
131 * This is the core processing method that all nodes must implement.
132 * It takes a single input value, applies the node's transformation algorithm,
133 * and returns the resulting output value.
134 *
135 * For generator nodes that don't require input (like oscillators or stochastic generators),
136 * the input parameter may be ignored.
137 * Note: This method does NOT mark the node as processed. That responsibility
138 * belongs to the caller, typically a chained parent node or the root node.
139 */
140 virtual double process_sample(double input = 0.) = 0;
141
142 /**
143 * @brief Processes multiple samples at once
144 * @param num_samples Number of samples to process
145 * @return Vector containing the processed samples
146 *
147 * This method provides batch processing capability for more efficient
148 * processing of multiple samples. The default implementation typically
149 * calls process_sample() for each sample, but specialized nodes can
150 * override this with more optimized batch processing algorithms.
151 */
152 virtual std::vector<double> process_batch(unsigned int num_samples) = 0;
153
154 /**
155 * @brief Registers a callback to be called on each tick
156 * @param callback Function to call with the current node context
157 *
158 * Registers a callback function that will be called each time the node
159 * produces a new output value. The callback receives a NodeContext object
160 * containing information about the node's current state.
161 *
162 * This mechanism enables external components to monitor and react to
163 * the node's activity without interrupting the processing flow.
164 *
165 * Example:
166 * ```cpp
167 * node->on_tick([](NodeContext& ctx) {
168 * std::cout << "Node produced value: " << ctx.value << std::endl;
169 * });
170 * ```
171 */
172 virtual void on_tick(const NodeHook& callback);
173
174 /**
175 * @brief Registers a conditional callback
176 * @param condition Predicate that determines when callback should be triggered
177 * @param callback Function to call when condition is met
178 *
179 * Registers a callback function that will be called only when the specified
180 * condition is met. The condition is evaluated each time the node produces
181 * a new output value, and the callback is triggered only if the condition
182 * returns true.
183 *
184 * This mechanism enables selective monitoring and reaction to specific
185 * node states or events, such as threshold crossings or pattern detection.
186 *
187 * Example:
188 * ```cpp
189 * node->on_tick_if(
190 * [](NodeContext& ctx) { return ctx.value > 0.8; },
191 * [](NodeContext& ctx) { std::cout << "Threshold exceeded!" << std::endl; }
192 * );
193 * ```
194 */
195 virtual void on_tick_if(const NodeCondition& condition, const NodeHook& callback);
196
197 /**
198 * @brief Removes a previously registered callback
199 * @param callback The callback to remove
200 * @return True if the callback was found and removed, false otherwise
201 *
202 * Unregisters a callback that was previously registered with on_tick().
203 * After removal, the callback will no longer be triggered when the node
204 * produces new output values.
205 *
206 * This method is useful for cleaning up callbacks when they are no longer
207 * needed, preventing memory leaks and unnecessary processing.
208 */
209 virtual bool remove_hook(const NodeHook& callback);
210
211 /**
212 * @brief Removes a previously registered conditional callback
213 * @param callback The callback part of the conditional callback to remove
214 * @return True if the callback was found and removed, false otherwise
215 *
216 * Unregisters a conditional callback that was previously registered with
217 * on_tick_if(). After removal, the callback will no longer be triggered
218 * even when its condition is met.
219 *
220 * This method is useful for cleaning up conditional callbacks when they
221 * are no longer needed, preventing memory leaks and unnecessary processing.
222 */
223 virtual bool remove_conditional_hook(const NodeCondition& callback);
224
225 /**
226 * @brief Removes all registered callbacks
227 *
228 * Unregisters all callbacks that were previously registered with on_tick()
229 * and on_tick_if(). After calling this method, no callbacks will be triggered
230 * when the node produces new output values.
231 *
232 * This method is useful for completely resetting the node's callback system,
233 * such as when repurposing a node or preparing for cleanup.
234 */
235 virtual void remove_all_hooks();
236
237 /**
238 * @brief Resets the processed state of the node and any attached input nodes
239 *
240 * This method is used by the processing system to reset the processed state
241 * of the node at the end of each processing cycle. This ensures that
242 * all nodes are marked as unprocessed before the cycle next begins, allowing
243 * the system to correctly identify which nodes need to be processed.
244 */
245 virtual void reset_processed_state();
246
247 /**
248 * @brief Retrieves the most recent output value produced by the node
249 * @return The last output sample value
250 *
251 * This method provides access to the node's most recent output without
252 * triggering additional processing. It's useful for monitoring node state,
253 * debugging, and for implementing feedback loops where a node needs to
254 * access its previous output.
255 *
256 * The returned value represents the last sample that was produced by
257 * the node's process_sample() method.
258 */
259 inline virtual double get_last_output() { return m_last_output; }
260
261 /**
262 * @brief Mark the specificed channel as a processor/user
263 * @param channel_id The ID of the channel to register
264 *
265 * This method uses a bitmask to track which channels are currently using this node.
266 * It allows the node to manage its state based on channel usage, which is important
267 * for the audio engine's processing lifecycle. When a channel registers usage,
268 * the node can adjust its processing state accordingly, such as preventing state resets
269 * within the same cycle, or use the same output for multiple channels
270 */
271 void register_channel_usage(uint32_t channel_id);
272
273 /**
274 * @brief Removes the specified channel from the usage tracking
275 * @param channel_id The ID of the channel to unregister
276 */
277 void unregister_channel_usage(uint32_t channel_id);
278
279 /**
280 * @brief Checks if the node is currently used by a specific channel
281 * @param channel_id The ID of the channel to check
282 */
283 [[nodiscard]] bool is_used_by_channel(uint32_t channel_id) const;
284
285 /**
286 * @brief Requests a reset of the processed state from a specific channel
287 * @param channel_id The ID of the channel requesting the reset
288 *
289 * This method is called by channels to signal that they have completed their
290 * processing and that the node's processed state should be reset. It uses a bitmask
291 * to track pending resets and ensures that all channels have completed before
292 * actually resetting the node's state.
293 */
294 void request_reset_from_channel(uint32_t channel_id);
295
296 /**
297 * @brief Retrieves the current bitmask of active channels using this node
298 * @return Bitmask where each bit represents an active channel
299 *
300 * This method returns the current bitmask that tracks which channels
301 * are actively using this node. Each bit in the mask corresponds to a
302 * specific channel ID, allowing the node to manage its state based on
303 * channel usage.
304 */
305 [[nodiscard]] const inline std::atomic<uint32_t>& get_channel_mask() const { return m_active_channels_mask; }
306
307 /**
308 * @brief Updates the context object with the current node state
309 * @param value The current sample value
310 *
311 * This method is responsible for updating the NodeContext object
312 * with the latest state information from the node. It is called
313 * internally whenever a new output value is produced, ensuring that
314 * the context reflects the current state of the node for use in callbacks.
315 */
316 virtual void update_context(double value) = 0;
317
318 /**
319 * @brief Retrieves the last created context object
320 * @return Reference to the last NodeContext object
321 *
322 * This method provides access to the most recent NodeContext object
323 * created by the node. This context contains information about the
324 * node's state at the time of the last output generation.
325 */
327
328 /**
329 * @brief Sets whether the node is compatible with GPU processing
330 * @param compatible True if the node supports GPU processing, false otherwise
331 */
332 virtual void set_gpu_compatible(bool compatible)
333 {
334 m_gpu_compatible = compatible;
335 if (compatible) {
336 m_timing_rate = m_frame_rate; // Use frame rate for timing calculations if GPU compatible
337 } else {
338 m_timing_rate = m_sample_rate; // Use sample rate for timing calculations if not GPU compatible
339 }
340 }
341
342 /**
343 * @brief Checks if the node supports GPU processing
344 * @return True if the node is GPU compatible, false otherwise
345 */
346 [[nodiscard]] bool is_gpu_compatible() const { return m_gpu_compatible; }
347
348 /**
349 * @brief Provides access to the GPU data buffer
350 * @return Span of floats representing the GPU data buffer
351 * This method returns a span of floats that represents the GPU data buffer
352 * associated with this node. The buffer contains data that can be uploaded to the GPU
353 * for processing, enabling efficient execution in GPU-accelerated pipelines.
354 */
355 [[nodiscard]] std::span<const float> get_gpu_data_buffer() const;
356
357 void set_sample_rate(uint32_t sample_rate) { m_sample_rate = sample_rate; }
358 [[nodiscard]] uint32_t get_sample_rate() const { return m_sample_rate; }
359
360 void set_frame_rate(uint32_t frame_rate) { m_frame_rate = frame_rate; }
361 [[nodiscard]] uint32_t get_frame_rate() const { return m_frame_rate; }
362
363protected:
364 /**
365 * @brief Notifies all registered callbacks with the current context
366 * @param value The current sample value
367 *
368 * This method is called by the node implementation when a new output value
369 * is produced. It creates a context object using create_context(), then
370 * calls all registered callbacks with that context.
371 *
372 * For unconditional callbacks (registered with on_tick()), the callback
373 * is always called. For conditional callbacks (registered with on_tick_if()),
374 * the callback is called only if its condition returns true.
375 *
376 * Node implementations should call this method at appropriate points in their
377 * processing flow to trigger callbacks.
378 */
379 virtual void notify_tick(double value) = 0;
380
381 /**
382 * @brief Resets the processed state of the node directly
383 *
384 * Unlike reset_processed_state(), this method is called internally
385 * and does not perform any checks or state transitions.
386 */
387 virtual void reset_processed_state_internal();
388
389 /**
390 * @brief The most recent sample value generated by this oscillator
391 *
392 * This value is updated each time process_sample() is called and can be
393 * accessed via get_last_output() without triggering additional processing.
394 * It's useful for monitoring the oscillator's state and for implementing
395 * feedback loops.
396 */
397 double m_last_output { 0 };
398
399 /**
400 * @brief Flag indicating if the node supports GPU processing
401 * This flag is set by derived classes to indicate whether
402 * the node can be processed on the GPU. Nodes that support GPU
403 * processing can provide GPU-compatible context data for
404 * efficient execution in GPU-accelerated pipelines.
405 */
406 bool m_gpu_compatible {};
407
408 /**
409 * @brief GPU data buffer for context objects
410 *
411 * This buffer is used to store float data that can be uploaded
412 * to the GPU for nodes that support GPU processing. It provides
413 * a contiguous array of floats that can be bound to GPU descriptors,
414 * enabling efficient data transfer and processing on the GPU.
415 */
416 std::vector<float> m_gpu_data_buffer;
417
418 /**
419 * @brief Collection of standard callback functions
420 *
421 * Stores the registered callback functions that will be notified
422 * whenever the binary operation produces a new output value. These callbacks
423 * enable external components to monitor and react to the combined output
424 * without interrupting the processing flow.
425 */
426 std::vector<NodeHook> m_callbacks;
427
428 /**
429 * @brief Collection of conditional callback functions with their predicates
430 *
431 * Stores pairs of callback functions and their associated condition predicates.
432 * These callbacks are only invoked when their condition evaluates to true
433 * for a combined output value, enabling selective monitoring of specific
434 * conditions or patterns in the combined signal.
435 */
436 std::vector<std::pair<NodeHook, NodeCondition>> m_conditional_callbacks;
437
438 /**
439 * @brief Flag indicating if the node is part of a NodeNetwork
440 * This flag is used to disable event firing when the node is
441 * managed within a NodeNetwork, preventing redundant or conflicting
442 * event notifications.
443 */
444 bool m_networked_node {};
445
446 /**
447 @brief tracks if the node's state has been saved by a snapshot operation
448 */
449 bool m_state_saved {};
450
451 uint32_t m_sample_rate { 48000 }; ///< Sample rate for audio processing, used for normalization
452
453 uint32_t m_frame_rate { 60 }; ///< Frame rate for time-based processing, used for normalization
454
455 uint32_t m_timing_rate { m_sample_rate }; ///< Current timing rate for the node, used for timing calculations (can be sample rate or frame rate)
456
457 uint8_t m_node_capability { NodeCapability::SCALAR }; ///< Bitmask of capabilities declared by this node
458
459public:
460 /**
461 * @brief Saves the node's current state for later restoration
462 * Recursively cascades through all connected modulator nodes
463 * Protected - only NodeSourceProcessor and NodeBuffer can call
464 */
465 virtual void save_state() = 0;
466
467 /**
468 * @brief Restores the node's state from the last save
469 * Recursively cascades through all connected modulator nodes
470 * Protected - only NodeSourceProcessor and NodeBuffer can call
471 */
472 virtual void restore_state() = 0;
473
474 /**
475 * @brief Internal flag controlling whether notify_tick fires during state snapshots
476 * Default: false (events don't fire during isolated buffer processing)
477 * Can be exposed in future if needed via concrete implementation in parent
478 */
479 bool m_fire_events_during_snapshot = false;
480
481 /**
482 * @brief Atomic state flag tracking the node's processing status
483 *
484 * This atomic state variable tracks the node's current operational status using
485 * bit flags defined in NodeState. It indicates whether the node is:
486 * - ACTIVE: Currently part of the processing graph
487 * - PROCESSED: Has been processed in the current cycle
488 * - PENDING_REMOVAL: Marked for removal from the processing graph
489 * - MOCK_PROCESS: Should be processed but output ignored
490 *
491 * The atomic nature ensures thread-safe state transitions, allowing the audio
492 * engine to safely coordinate processing across multiple threads without data races.
493 */
494 std::atomic<NodeState> m_state { NodeState::INACTIVE };
495
496 /**
497 * @brief Counter tracking how many other nodes are using this node as a modulator
498 *
499 * This counter is incremented when another node begins using this node as a
500 * modulation source, and decremented when that relationship ends. It's critical
501 * for the node lifecycle management system, as it prevents premature state resets
502 * when a node's output is still needed by downstream nodes.
503 *
504 * When this counter is non-zero, the node's processed state will not be reset
505 * automatically after processing, ensuring that all dependent nodes can access
506 * its output before it's cleared.
507 */
508 std::atomic<uint32_t> m_modulator_count { 0 };
509
510 /**
511 * @brief Attempt to claim snapshot context for this processing cycle
512 * @param context_id Unique context identifier for this buffer processing
513 * @return true if this caller claimed the context (should call save_state)
514 *
515 * This method enables multiple NodeBuffers referencing the same node to
516 * coordinate save/restore state operations. Only the first caller per
517 * processing context will claim the snapshot, preventing nested state saves.
518 */
519 bool try_claim_snapshot_context(uint64_t context_id);
520
521 /**
522 * @brief Check if currently in a snapshot context
523 * @param context_id Context to check
524 * @return true if this context is active
525 *
526 * Used by secondary callers to detect when the primary snapshot holder
527 * has completed processing and released the context.
528 */
529 [[nodiscard]] bool is_in_snapshot_context(uint64_t context_id) const;
530
531 /**
532 * @brief Release snapshot context
533 * @param context_id Context to release
534 *
535 * Called by the snapshot owner after restore_state() completes,
536 * allowing other buffers to proceed with their own snapshots.
537 */
538 void release_snapshot_context(uint64_t context_id);
539
540 /**
541 * @brief Check if node is currently being snapshotted by any context
542 * @return true if a snapshot is in progress
543 */
544 [[nodiscard]] bool has_active_snapshot() const;
545
546 /**
547 * @brief Get the active snapshot context ID
548 * @return The current active snapshot context ID, or 0 if none
549 */
550 [[nodiscard]] inline uint64_t get_active_snapshot_context() const
551 {
552 return m_snapshot_context_id.load(std::memory_order_acquire);
553 }
554
555 /**
556 * @brief Increments the buffer reference count
557 * This method is called when a new buffer starts using this node
558 * to ensure proper lifecycle management.
559 */
560 void add_buffer_reference();
561
562 /**
563 * @brief Decrements the buffer reference count
564 * This method is called when a buffer stops using this node
565 * to ensure proper lifecycle management.
566 */
567 void remove_buffer_reference();
568
569 /**
570 * @brief Marks the node as having been processed by a buffer
571 * @return true if the buffer was successfully marked as processed
572 *
573 * This method checks if the node can be marked as processed based on
574 * the current buffer count and node state. If conditions are met,
575 * it updates the processed flag and increments the reset counter.
576 */
577 bool mark_buffer_processed();
578
579 /**
580 * @brief Requests a reset of the buffer state
581 *
582 * This method is called to signal that the buffer's processed state
583 * should be reset. It increments the reset counter, which is used to
584 * determine when it's safe to clear the processed state.
585 */
586 void request_buffer_reset();
587
588 /**
589 * @brief Checks if the buffer has been processed
590 * @return true if the buffer is marked as processed
591 */
592 [[nodiscard]] inline bool is_buffer_processed() const
593 {
594 return m_buffer_processed.load(std::memory_order_acquire);
595 }
596
597 /**
598 * @brief Sets whether the node is part of a NodeNetwork
599 * @param networked True if the node is managed within a NodeNetwork
600 *
601 * This method sets a flag indicating whether the node is part of a
602 * NodeNetwork. When set, certain behaviors such as event firing
603 * may be disabled to prevent redundant or conflicting notifications.
604 */
605 [[nodiscard]] inline bool is_in_network() const { return m_networked_node; }
606
607 /**
608 * @brief Marks the node as being part of a NodeNetwork
609 * @param networked True if the node is managed within a NodeNetwork
610 *
611 * This method sets a flag indicating whether the node is part of a
612 * NodeNetwork. When set, certain behaviors such as event firing
613 * may be disabled to prevent redundant or conflicting notifications.
614 */
615 void set_in_network(bool networked) { m_networked_node = networked; }
616
617 /**
618 * @brief Retrieves the current routing state of the network
619 * @return Reference to the current RoutingState structure
620 *
621 * This method provides access to the network's current routing state, which
622 * includes information about fade-in/out (Active) phases, channel counts, and elapsed cycles.
623 * The routing state is used to manage smooth transitions when routing changes occur,
624 * ensuring seamless audio output during dynamic reconfigurations of the processing graph.
625 */
626 [[nodiscard]] const RoutingState& get_routing_state() const { return m_routing_state; }
627
628 /**
629 * @brief Retrieves the current routing state of the network (non-const)
630 * @return Reference to the current RoutingState structure
631 */
632 RoutingState& get_routing_state() { return m_routing_state; }
633
634 /**
635 * @brief Checks if the network is currently in a routing transition phase
636 * @return true if the network is in a fade-in or fade-out (Active) phase
637 *
638 * This method checks the network's routing state to determine if it is currently
639 * undergoing a routing transition, such as fading in or out. This information
640 * can be used by processing algorithms to adjust their behavior during transitions,
641 * ensuring smooth audio output without artifacts.
642 */
643 [[nodiscard]] bool needs_channel_routing() const
644 {
645 return m_routing_state.phase & (RoutingState::ACTIVE | RoutingState::COMPLETED);
646 }
647
648 /**
649 * @brief Declare which data shapes this node's context can produce.
650 *
651 * Override to advertise capabilities beyond SCALAR. The default reflects
652 * the Node interface guarantee: every node produces a scalar.
653 * Combine flags with bitwise OR for nodes whose context implements
654 * multiple GpuContext mixins.
655 *
656 * @return Bitmask of NodeCapability flags.
657 */
658 [[nodiscard]] virtual uint8_t node_capabilities() const { return m_node_capability; }
659
660 /**
661 * @brief Query a single capability.
662 * @param cap Capability flag to test.
663 * @return true if this node supports the requested data shape.
664 */
665 [[nodiscard]] bool has_capability(NodeCapability cap) const
666 {
667 return (m_node_capability & cap) != 0U;
668 }
669
670private:
671 /**
672 * @brief Bitmask tracking which channels are currently using this node
673 */
674 std::atomic<uint32_t> m_active_channels_mask { 0 };
675
676 /**
677 * @brief Bitmask tracking which channels have requested a reset
678 *
679 * This mask is used to track which channels have requested the node's processed
680 * state to be reset. When all channels that are currently using the node have
681 * requested a reset, the node can safely clear its processed state.
682 */
683 std::atomic<uint32_t> m_pending_reset_mask { 0 };
684
685 /**
686 * @brief Unique identifier for the current snapshot context
687 *
688 * This atomic variable holds the unique identifier of the current
689 * snapshot context that has claimed ownership of this node's state.
690 * It ensures that only one processing context can perform save/restore
691 * operations at a time, preventing nested snapshots and ensuring
692 * consistent state management.
693 */
694 std::atomic<uint64_t> m_snapshot_context_id { 0 };
695
696 /**
697 * @brief Counter tracking how many buffers are using this node
698 * This counter is incremented when a buffer starts using this node
699 * and decremented when the buffer stops using it. It helps manage
700 * the node's lifecycle in relation to buffer usage.
701 */
702 std::atomic<uint32_t> m_buffer_count { 0 };
703
704 /**
705 * @brief Flag indicating whether the buffer has been processed
706 * This atomic flag is set when the buffer has been successfully
707 * processed and is used to prevent redundant processing.
708 */
709 std::atomic<bool> m_buffer_processed { false };
710
711 /**
712 * @brief Counter tracking how many buffers have requested a reset
713 *
714 * When all buffers using this node have requested a reset, the node's
715 * processed state can be safely cleared. This counter helps coordinate
716 * that process.
717 */
718 std::atomic<uint32_t> m_buffer_reset_count { 0 };
719
720 /**
721 * @brief Internal state tracking for routing transitions
722 *
723 * This structure tracks the state of routing transitions,
724 * such as fade-in and fade-out phases, channel counts, and elapsed cycles.
725 * It's used to manage smooth transitions when routing changes occur, ensuring
726 * that audio output remains seamless during dynamic reconfigurations of the processing graph.
727 */
729};
730}
std::string type_id
Type identifier for runtime type checking.
Definition Node.hpp:48
virtual ~NodeContext()=default
NodeContext(double value, std::string type)
Protected constructor for NodeContext.
Definition Node.hpp:94
double value
Current sample value.
Definition Node.hpp:40
T * as()
Safely cast to a derived context type.
Definition Node.hpp:68
const T * as() const
Definition Node.hpp:77
Base context class for node callbacks.
Definition Node.hpp:30
virtual double process_sample(double input=0.)=0
Processes a single data sample.
virtual double get_last_output()
Retrieves the most recent output value produced by the node.
Definition Node.hpp:259
virtual std::vector< double > process_batch(unsigned int num_samples)=0
Processes multiple samples at once.
bool is_buffer_processed() const
Checks if the buffer has been processed.
Definition Node.hpp:592
virtual void save_state()=0
Saves the node's current state for later restoration Recursively cascades through all connected modul...
bool is_in_network() const
Sets whether the node is part of a NodeNetwork.
Definition Node.hpp:605
uint32_t get_frame_rate() const
Definition Node.hpp:361
std::vector< NodeHook > m_callbacks
Collection of standard callback functions.
Definition Node.hpp:426
void set_in_network(bool networked)
Marks the node as being part of a NodeNetwork.
Definition Node.hpp:615
virtual void restore_state()=0
Restores the node's state from the last save Recursively cascades through all connected modulator nod...
uint64_t get_active_snapshot_context() const
Get the active snapshot context ID.
Definition Node.hpp:550
const std::atomic< uint32_t > & get_channel_mask() const
Retrieves the current bitmask of active channels using this node.
Definition Node.hpp:305
bool needs_channel_routing() const
Checks if the network is currently in a routing transition phase.
Definition Node.hpp:643
virtual NodeContext & get_last_context()=0
Retrieves the last created context object.
virtual void notify_tick(double value)=0
Notifies all registered callbacks with the current context.
virtual void update_context(double value)=0
Updates the context object with the current node state.
virtual void set_gpu_compatible(bool compatible)
Sets whether the node is compatible with GPU processing.
Definition Node.hpp:332
void set_sample_rate(uint32_t sample_rate)
Definition Node.hpp:357
bool is_gpu_compatible() const
Checks if the node supports GPU processing.
Definition Node.hpp:346
std::vector< std::pair< NodeHook, NodeCondition > > m_conditional_callbacks
Collection of conditional callback functions with their predicates.
Definition Node.hpp:436
virtual ~Node()=default
Virtual destructor for proper cleanup of derived classes.
uint32_t get_sample_rate() const
Definition Node.hpp:358
RoutingState & get_routing_state()
Retrieves the current routing state of the network (non-const)
Definition Node.hpp:632
bool has_capability(NodeCapability cap) const
Query a single capability.
Definition Node.hpp:665
void set_frame_rate(uint32_t frame_rate)
Definition Node.hpp:360
std::vector< float > m_gpu_data_buffer
GPU data buffer for context objects.
Definition Node.hpp:416
RoutingState m_routing_state
Internal state tracking for routing transitions.
Definition Node.hpp:728
virtual uint8_t node_capabilities() const
Declare which data shapes this node's context can produce.
Definition Node.hpp:658
const RoutingState & get_routing_state() const
Retrieves the current routing state of the network.
Definition Node.hpp:626
Base interface for all computational processing nodes.
Definition Node.hpp:118
TypedHook<> NodeHook
Alias for TypedHook<NodeContext>.
Definition NodeUtils.hpp:38
NodeCapability
Bitmask flags declaring what data shapes a node's context can produce.
Definition NodeSpec.hpp:104
std::function< bool(NodeContext &)> NodeCondition
Predicate function type for conditional callbacks.
Definition NodeUtils.hpp:54
Contains the node-based computational processing system components.
Definition Chronie.hpp:13
Represents the state of routing transitions for a node.
Definition NodeSpec.hpp:64