Skip to main content

rill_core/traits/
processable.rs

1//! Processable trait for unified audio node processing.
2//!
3//! This module defines the `Processable` trait that unifies `generate`, `process`, and `consume`
4//! into a single `process_block` method, making it easier to build generic signal graphs.
5
6use crate::math::Transcendental;
7use crate::time::ClockTick;
8use crate::traits::ProcessResult;
9
10// ============================================================================
11// ProcessContext
12// ============================================================================
13
14/// Convenience structure that gathers all input buffers for a node.
15///
16/// Nodes write their output directly into their own output port buffers
17/// (accessible via `SignalNode::output_port_mut`), so only input data
18/// is passed through this context.
19pub struct ProcessContext<'a, T: Transcendental, const BUF_SIZE: usize> {
20    /// Current clock tick
21    pub clock: &'a ClockTick,
22    /// Audio input buffers (slice of references to [T; BUF_SIZE])
23    pub signal_inputs: &'a [&'a [T; BUF_SIZE]],
24    /// Control input values (slice of T)
25    pub control_inputs: &'a [T],
26    /// Clock input ticks
27    pub clock_inputs: &'a [ClockTick],
28    /// Feedback input buffers (slice of references to [T; BUF_SIZE])
29    pub feedback_inputs: &'a [&'a [T; BUF_SIZE]],
30}
31
32// ============================================================================
33// Processable Trait
34// ============================================================================
35
36/// Unified trait for processing audio nodes.
37///
38/// This trait is implemented for all `Source`, `Processor`, and `Sink` types,
39/// providing a single method that dispatches to the appropriate underlying
40/// method (`generate`, `process`, or `consume`).
41pub trait Processable<T: Transcendental, const BUF_SIZE: usize> {
42    /// Process a single block of audio.
43    ///
44    /// The default implementation uses the node's category to call the
45    /// appropriate subtrait method. Implementors can override this if they
46    /// need custom behavior.
47    fn process_block(&mut self, ctx: &mut ProcessContext<T, BUF_SIZE>) -> ProcessResult<()>;
48}
49
50// ============================================================================
51// Blanket Implementations for Trait Objects
52// ============================================================================
53
54impl<T, const BUF_SIZE: usize> Processable<T, BUF_SIZE>
55    for Box<dyn crate::traits::Source<T, BUF_SIZE>>
56where
57    T: Transcendental,
58{
59    fn process_block(&mut self, ctx: &mut ProcessContext<T, BUF_SIZE>) -> ProcessResult<()> {
60        self.as_mut()
61            .generate(ctx.clock, ctx.control_inputs, ctx.clock_inputs)
62    }
63}
64
65impl<T, const BUF_SIZE: usize> Processable<T, BUF_SIZE>
66    for Box<dyn crate::traits::Processor<T, BUF_SIZE>>
67where
68    T: Transcendental,
69{
70    fn process_block(&mut self, ctx: &mut ProcessContext<T, BUF_SIZE>) -> ProcessResult<()> {
71        self.as_mut().process(
72            ctx.clock,
73            ctx.signal_inputs,
74            ctx.control_inputs,
75            ctx.clock_inputs,
76            ctx.feedback_inputs,
77        )
78    }
79}
80
81impl<T, const BUF_SIZE: usize> Processable<T, BUF_SIZE>
82    for Box<dyn crate::traits::Sink<T, BUF_SIZE>>
83where
84    T: Transcendental,
85{
86    fn process_block(&mut self, ctx: &mut ProcessContext<T, BUF_SIZE>) -> ProcessResult<()> {
87        self.as_mut().consume(
88            ctx.clock,
89            ctx.signal_inputs,
90            ctx.control_inputs,
91            ctx.clock_inputs,
92            ctx.feedback_inputs,
93        )
94    }
95}
96
97// ============================================================================
98// NodeVariant Enum
99// ============================================================================
100
101/// Enum that holds any kind of audio node.
102pub enum NodeVariant<T: Transcendental, const BUF_SIZE: usize> {
103    Source(Box<dyn crate::traits::Source<T, BUF_SIZE>>),
104    Processor(Box<dyn crate::traits::Processor<T, BUF_SIZE>>),
105    Sink(Box<dyn crate::traits::Sink<T, BUF_SIZE>>),
106}
107
108impl<T: Transcendental, const BUF_SIZE: usize> Processable<T, BUF_SIZE> for NodeVariant<T, BUF_SIZE> {
109    fn process_block(&mut self, ctx: &mut ProcessContext<T, BUF_SIZE>) -> ProcessResult<()> {
110        match self {
111            NodeVariant::Source(src) => src.process_block(ctx),
112            NodeVariant::Processor(proc) => proc.process_block(ctx),
113            NodeVariant::Sink(sink) => sink.process_block(ctx),
114        }
115    }
116}
117
118impl<T: Transcendental, const BUF_SIZE: usize> crate::traits::SignalNode<T, BUF_SIZE>
119    for NodeVariant<T, BUF_SIZE>
120{
121    fn metadata(&self) -> crate::traits::NodeMetadata {
122        match self {
123            NodeVariant::Source(src) => src.metadata(),
124            NodeVariant::Processor(proc) => proc.metadata(),
125            NodeVariant::Sink(sink) => sink.metadata(),
126        }
127    }
128
129    fn init(&mut self, sample_rate: f32) {
130        match self {
131            NodeVariant::Source(src) => src.init(sample_rate),
132            NodeVariant::Processor(proc) => proc.init(sample_rate),
133            NodeVariant::Sink(sink) => sink.init(sample_rate),
134        }
135    }
136
137    fn reset(&mut self) {
138        match self {
139            NodeVariant::Source(src) => src.reset(),
140            NodeVariant::Processor(proc) => proc.reset(),
141            NodeVariant::Sink(sink) => sink.reset(),
142        }
143    }
144
145    fn get_parameter(&self, id: &crate::traits::ParameterId) -> Option<crate::traits::ParamValue> {
146        match self {
147            NodeVariant::Source(src) => src.get_parameter(id),
148            NodeVariant::Processor(proc) => proc.get_parameter(id),
149            NodeVariant::Sink(sink) => sink.get_parameter(id),
150        }
151    }
152
153    fn set_parameter(
154        &mut self,
155        id: &crate::traits::ParameterId,
156        value: crate::traits::ParamValue,
157    ) -> ProcessResult<()> {
158        match self {
159            NodeVariant::Source(src) => src.set_parameter(id, value),
160            NodeVariant::Processor(proc) => proc.set_parameter(id, value),
161            NodeVariant::Sink(sink) => sink.set_parameter(id, value),
162        }
163    }
164
165    fn id(&self) -> crate::traits::NodeId {
166        match self {
167            NodeVariant::Source(src) => src.id(),
168            NodeVariant::Processor(proc) => proc.id(),
169            NodeVariant::Sink(sink) => sink.id(),
170        }
171    }
172
173    fn set_id(&mut self, id: crate::traits::NodeId) {
174        match self {
175            NodeVariant::Source(src) => src.set_id(id),
176            NodeVariant::Processor(proc) => proc.set_id(id),
177            NodeVariant::Sink(sink) => sink.set_id(id),
178        }
179    }
180
181    fn num_signal_inputs(&self) -> usize {
182        match self {
183            NodeVariant::Source(src) => {
184                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**src;
185                n.num_signal_inputs()
186            }
187            NodeVariant::Processor(proc) => {
188                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**proc;
189                n.num_signal_inputs()
190            }
191            NodeVariant::Sink(sink) => {
192                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**sink;
193                n.num_signal_inputs()
194            }
195        }
196    }
197
198    fn num_signal_outputs(&self) -> usize {
199        match self {
200            NodeVariant::Source(src) => {
201                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**src;
202                n.num_signal_outputs()
203            }
204            NodeVariant::Processor(proc) => {
205                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**proc;
206                n.num_signal_outputs()
207            }
208            NodeVariant::Sink(sink) => {
209                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**sink;
210                n.num_signal_outputs()
211            }
212        }
213    }
214
215    fn num_control_inputs(&self) -> usize {
216        match self {
217            NodeVariant::Source(src) => {
218                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**src;
219                n.num_control_inputs()
220            }
221            NodeVariant::Processor(proc) => {
222                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**proc;
223                n.num_control_inputs()
224            }
225            NodeVariant::Sink(sink) => {
226                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**sink;
227                n.num_control_inputs()
228            }
229        }
230    }
231
232    fn num_control_outputs(&self) -> usize {
233        match self {
234            NodeVariant::Source(src) => {
235                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**src;
236                n.num_control_outputs()
237            }
238            NodeVariant::Processor(proc) => {
239                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**proc;
240                n.num_control_outputs()
241            }
242            NodeVariant::Sink(sink) => {
243                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**sink;
244                n.num_control_outputs()
245            }
246        }
247    }
248
249    fn num_clock_inputs(&self) -> usize {
250        match self {
251            NodeVariant::Source(src) => {
252                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**src;
253                n.num_clock_inputs()
254            }
255            NodeVariant::Processor(proc) => {
256                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**proc;
257                n.num_clock_inputs()
258            }
259            NodeVariant::Sink(sink) => {
260                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**sink;
261                n.num_clock_inputs()
262            }
263        }
264    }
265
266    fn num_clock_outputs(&self) -> usize {
267        match self {
268            NodeVariant::Source(src) => {
269                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**src;
270                n.num_clock_outputs()
271            }
272            NodeVariant::Processor(proc) => {
273                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**proc;
274                n.num_clock_outputs()
275            }
276            NodeVariant::Sink(sink) => {
277                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**sink;
278                n.num_clock_outputs()
279            }
280        }
281    }
282
283    fn num_feedback_ports(&self) -> usize {
284        match self {
285            NodeVariant::Source(src) => {
286                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**src;
287                n.num_feedback_ports()
288            }
289            NodeVariant::Processor(proc) => {
290                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**proc;
291                n.num_feedback_ports()
292            }
293            NodeVariant::Sink(sink) => {
294                let n: &dyn crate::traits::SignalNode<T, BUF_SIZE> = &**sink;
295                n.num_feedback_ports()
296            }
297        }
298    }
299
300    fn input_port(&self, index: usize) -> Option<&crate::traits::port::Port<T, BUF_SIZE>> {
301        match self {
302            NodeVariant::Source(src) => src.input_port(index),
303            NodeVariant::Processor(proc) => proc.input_port(index),
304            NodeVariant::Sink(sink) => sink.input_port(index),
305        }
306    }
307
308    fn input_port_mut(
309        &mut self,
310        index: usize,
311    ) -> Option<&mut crate::traits::port::Port<T, BUF_SIZE>> {
312        match self {
313            NodeVariant::Source(src) => src.input_port_mut(index),
314            NodeVariant::Processor(proc) => proc.input_port_mut(index),
315            NodeVariant::Sink(sink) => sink.input_port_mut(index),
316        }
317    }
318
319    fn output_port(&self, index: usize) -> Option<&crate::traits::port::Port<T, BUF_SIZE>> {
320        match self {
321            NodeVariant::Source(src) => src.output_port(index),
322            NodeVariant::Processor(proc) => proc.output_port(index),
323            NodeVariant::Sink(sink) => sink.output_port(index),
324        }
325    }
326
327    fn output_port_mut(
328        &mut self,
329        index: usize,
330    ) -> Option<&mut crate::traits::port::Port<T, BUF_SIZE>> {
331        match self {
332            NodeVariant::Source(src) => src.output_port_mut(index),
333            NodeVariant::Processor(proc) => proc.output_port_mut(index),
334            NodeVariant::Sink(sink) => sink.output_port_mut(index),
335        }
336    }
337
338    fn control_port(&self, index: usize) -> Option<&crate::traits::port::Port<T, BUF_SIZE>> {
339        match self {
340            NodeVariant::Source(src) => src.control_port(index),
341            NodeVariant::Processor(proc) => proc.control_port(index),
342            NodeVariant::Sink(sink) => sink.control_port(index),
343        }
344    }
345
346    fn control_port_mut(
347        &mut self,
348        index: usize,
349    ) -> Option<&mut crate::traits::port::Port<T, BUF_SIZE>> {
350        match self {
351            NodeVariant::Source(src) => src.control_port_mut(index),
352            NodeVariant::Processor(proc) => proc.control_port_mut(index),
353            NodeVariant::Sink(sink) => sink.control_port_mut(index),
354        }
355    }
356
357    fn state(&self) -> &crate::traits::NodeState<T, BUF_SIZE> {
358        match self {
359            NodeVariant::Source(src) => src.state(),
360            NodeVariant::Processor(proc) => proc.state(),
361            NodeVariant::Sink(sink) => sink.state(),
362        }
363    }
364
365    fn state_mut(&mut self) -> &mut crate::traits::NodeState<T, BUF_SIZE> {
366        match self {
367            NodeVariant::Source(src) => src.state_mut(),
368            NodeVariant::Processor(proc) => proc.state_mut(),
369            NodeVariant::Sink(sink) => sink.state_mut(),
370        }
371    }
372}