knyst/graph/
node.rs

1use crate::{node_buffer::NodeBufferRef, Resources, Sample};
2
3use super::{CopyOrAdd, Gen, GenContext, GenState, NodeId, NodeKey, Task};
4
5/// Node is a very unsafe struct. Be very careful when changing it.
6///
7/// - The Gen is not allowed to be replaced. It is functionally Pinned until dropped.
8///   It must be kept as a raw pointer to the allocation not to break rust aliasing
9///   rules. `UnsafeCell` is not enough since an owned UnsafeCell implies unique access
10///   and can give a &mut reference in safe code.
11/// - The input_constants buffer mustn't be deallocated until the Node is dropped.
12/// - init must not be called after the Node has started being used on the audio thread.
13/// - the number of inputs/outputs of the Gen must not change.
14///
15/// It also must not be dropped while a Task exists with pointers to the buffers
16/// of the Node. Graph has a mechanism to ensure this using an atomic generation counter.
17pub(super) struct Node {
18    pub(super) name: &'static str,
19    /// index by input_channel
20    input_constants: *mut [Sample],
21    /// index by `output_channel * block_size + sample_index`
22    output_buffers: *mut [Sample],
23    output_buffers_first_ptr: *mut Sample,
24    pub block_size: usize,
25    num_outputs: usize,
26    gen: *mut (dyn Gen + Send),
27    start_node_at_sample: u64,
28}
29
30unsafe impl Send for Node {}
31
32impl Node {
33    pub fn new(name: &'static str, gen: Box<dyn Gen + Send>) -> Self {
34        let num_outputs = gen.num_outputs();
35        let block_size = 0;
36        let output_buffers =
37            Box::<[Sample]>::into_raw(vec![0.0; num_outputs * block_size].into_boxed_slice());
38
39        let output_buffers_first_ptr = std::ptr::null_mut();
40
41        Node {
42            name,
43            input_constants: Box::into_raw(
44                vec![0.0 as Sample; gen.num_inputs()].into_boxed_slice(),
45            ),
46            gen: Box::into_raw(gen),
47            output_buffers,
48            output_buffers_first_ptr,
49            num_outputs,
50            block_size,
51            start_node_at_sample: 0,
52        }
53    }
54    pub(super) fn start_at_sample(&mut self, sample_time: u64) {
55        self.start_node_at_sample = sample_time;
56    }
57    pub(super) fn to_task(
58        &self,
59        node_key: NodeKey,
60        inputs_to_copy: Vec<(*mut Sample, *mut Sample, usize, CopyOrAdd)>,
61        graph_inputs_to_copy: Vec<(usize, usize)>,
62        input_buffers: NodeBufferRef,
63    ) -> Task {
64        Task {
65            node_key,
66            inputs_to_copy,
67            graph_inputs_to_copy,
68            input_buffers,
69            input_constants: self.input_constants,
70            gen: self.gen,
71            output_buffers_first_ptr: self.output_buffers_first_ptr,
72            block_size: self.block_size,
73            num_outputs: self.num_outputs,
74            start_node_at_sample: self.start_node_at_sample,
75        }
76    }
77    // pub fn name(&self) -> &'static str {
78    //     self.name
79    // }
80    /// *Allocates memory*
81    /// Allocates enough memory for the given block size
82    pub fn init(&mut self, block_size: usize, sample_rate: Sample, node_id: NodeId) {
83        // Free the previous buffer
84        unsafe {
85            drop(Box::from_raw(self.output_buffers));
86        }
87        self.output_buffers =
88            Box::<[Sample]>::into_raw(vec![0.0; self.num_outputs * block_size].into_boxed_slice());
89        self.output_buffers_first_ptr = if block_size * self.num_outputs > 0 {
90            // Get the pointer to the first Sample in the block without limiting its scope or going through a reference
91            self.output_buffers.cast::<Sample>()
92        } else {
93            std::ptr::null_mut()
94        };
95        self.block_size = block_size;
96        unsafe {
97            (*self.gen).init(block_size, sample_rate, node_id);
98        }
99    }
100    /// Use the embedded Gen to generate values that are placed in the
101    /// output_buffer. The Graph will have already filled the input buffer with
102    /// the correct values.
103    #[inline]
104    pub(super) fn process(
105        &mut self,
106        input_buffers: &NodeBufferRef,
107        sample_rate: Sample,
108        resources: &mut Resources,
109    ) -> GenState {
110        let mut outputs = NodeBufferRef::new(
111            self.output_buffers_first_ptr,
112            self.num_outputs,
113            self.block_size,
114        );
115        let ctx = GenContext {
116            inputs: input_buffers,
117            outputs: &mut outputs,
118            sample_rate,
119        };
120        unsafe { (*self.gen).process(ctx, resources) }
121    }
122    pub fn set_constant(&mut self, value: Sample, input_index: usize) {
123        unsafe {
124            (*self.input_constants)[input_index] = value;
125        }
126    }
127    pub fn output_buffers(&self) -> NodeBufferRef {
128        NodeBufferRef::new(
129            self.output_buffers_first_ptr,
130            self.num_outputs,
131            self.block_size,
132        )
133    }
134    pub fn num_inputs(&self) -> usize {
135        // self.gen.num_inputs()
136        // Not dynamic dispatch, may be faster
137        unsafe { &*self.input_constants }.len()
138    }
139    pub fn num_outputs(&self) -> usize {
140        self.num_outputs
141    }
142    pub fn input_indices_to_names(&self) -> Vec<&'static str> {
143        let mut list = vec![];
144        for i in 0..self.num_inputs() {
145            list.push(unsafe { (*self.gen).input_desc(i) });
146        }
147        list
148    }
149    pub fn output_indices_to_names(&self) -> Vec<&'static str> {
150        let mut list = vec![];
151        for i in 0..self.num_outputs() {
152            list.push(unsafe { (*self.gen).output_desc(i) });
153        }
154        list
155    }
156    pub(super) fn input_desc(&self, input: usize) -> &'static str {
157        unsafe { (*self.gen).input_desc(input) }
158    }
159
160    pub(super) fn output_desc(&self, output: usize) -> &'static str {
161        unsafe { (*self.gen).output_desc(output) }
162    }
163}
164impl Drop for Node {
165    fn drop(&mut self) {
166        drop(unsafe { Box::from_raw(self.gen) });
167        drop(unsafe { Box::from_raw(self.input_constants) });
168        drop(unsafe { Box::from_raw(self.output_buffers) });
169    }
170}