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