Skip to main content

aether_core/
node.rs

1//! Node abstraction for the DSP graph.
2//!
3//! Each node is a self-contained DSP unit. The `DspNode` trait is the only
4//! interface the graph scheduler calls — keeping the hot path minimal.
5
6use crate::{
7    arena::NodeId, buffer_pool::BufferId, param::ParamBlock, state::StateBlob, BUFFER_SIZE,
8    MAX_INPUTS,
9};
10
11/// The core DSP processing trait.
12/// Implementations MUST be real-time safe:
13///   - No allocation
14///   - No locks
15///   - No I/O
16///   - Bounded execution time
17pub trait DspNode: Send {
18    /// Process one buffer of audio.
19    ///
20    /// `inputs`: resolved input buffer slices (None = silence).
21    /// `output`: the node's output buffer to fill.
22    /// `params`: the node's parameter block (pre-ticked by scheduler).
23    /// `sample_rate`: current sample rate in Hz.
24    fn process(
25        &mut self,
26        inputs: &[Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS],
27        output: &mut [f32; BUFFER_SIZE],
28        params: &mut ParamBlock,
29        sample_rate: f32,
30    );
31
32    /// Capture internal state for continuity transfer.
33    fn capture_state(&self) -> StateBlob {
34        StateBlob::EMPTY
35    }
36
37    /// Restore internal state after a graph mutation.
38    fn restore_state(&mut self, _state: StateBlob) {}
39
40    /// Human-readable node type name (for serialization/UI).
41    fn type_name(&self) -> &'static str;
42}
43
44/// Graph-level node record. Stored in the arena.
45pub struct NodeRecord {
46    /// The DSP implementation (boxed, allocated at node creation time — not in RT).
47    pub processor: Box<dyn DspNode>,
48    /// Input connections: each slot holds the NodeId of the upstream node.
49    pub inputs: [Option<NodeId>; MAX_INPUTS],
50    /// The buffer this node writes its output into.
51    pub output_buffer: BufferId,
52    /// Parameter block for this node.
53    pub params: ParamBlock,
54}
55
56impl NodeRecord {
57    pub fn new(processor: Box<dyn DspNode>, output_buffer: BufferId) -> Self {
58        Self {
59            processor,
60            inputs: [None; MAX_INPUTS],
61            output_buffer,
62            params: ParamBlock::new(),
63        }
64    }
65}