Skip to main content

rill_core/traits/
algorithm.rs

1//! Algorithm trait — the unified per-port and DSP processing primitive.
2//!
3//! All processing in the Rill graph is defined by `Algorithm` implementations.
4//! Every port's `run_action()` delegates to its `Algorithm::process()`.
5//! Low-level DSP primitives (filters, generators) also implement `Algorithm`.
6
7use crate::math::Transcendental;
8use crate::time::ClockTick;
9use crate::traits::ParamValue;
10use crate::traits::ProcessResult;
11
12// ============================================================================
13// ActionContext
14// ============================================================================
15
16/// Context provided to an [`Algorithm`] during processing.
17pub struct ActionContext<'a> {
18    /// Current clock tick providing sample-accurate timing.
19    pub tick: &'a ClockTick,
20}
21
22impl<'a> ActionContext<'a> {
23    /// Create a new action context from a clock tick reference.
24    pub fn new(tick: &'a ClockTick) -> Self {
25        Self { tick }
26    }
27}
28
29// ============================================================================
30// Algorithm Metadata
31// ============================================================================
32
33/// Functional category of an algorithm (for introspection / UI).
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
35pub enum AlgorithmCategory {
36    /// Signal generator (oscillator, noise, etc.).
37    Generator,
38    /// Signal filter (biquad, SVF, etc.).
39    Filter,
40    /// Signal effect (delay, distortion, etc.).
41    Effect,
42    /// Signal analyzer (meter, scope, etc.).
43    Analyzer,
44    /// Utility / helper (smoother, mapper, etc.).
45    Utility,
46}
47
48impl AlgorithmCategory {
49    /// Human-readable name
50    pub const fn name(&self) -> &'static str {
51        match self {
52            Self::Generator => "generator",
53            Self::Filter => "filter",
54            Self::Effect => "effect",
55            Self::Analyzer => "analyzer",
56            Self::Utility => "utility",
57        }
58    }
59}
60
61/// Descriptive metadata for an [`Algorithm`] implementation.
62#[derive(Debug, Clone)]
63pub struct AlgorithmMetadata {
64    /// Short name (e.g. "Biquad", "OnePole", "ParamSmoother").
65    pub name: &'static str,
66    /// Functional category.
67    pub category: AlgorithmCategory,
68    /// One-line description.
69    pub description: &'static str,
70    /// Author name.
71    pub author: &'static str,
72    /// Version string.
73    pub version: &'static str,
74}
75
76impl AlgorithmMetadata {
77    /// Minimal default metadata with `Utility` category and empty fields.
78    pub const fn empty() -> Self {
79        Self {
80            name: "",
81            category: AlgorithmCategory::Utility,
82            description: "",
83            author: "",
84            version: "",
85        }
86    }
87}
88
89// ============================================================================
90// Algorithm Trait
91// ============================================================================
92
93/// Unified processing primitive for ports and DSP blocks.
94///
95/// Every port in the graph owns an optional `Box<dyn Algorithm>`. When present,
96/// the port's `run_action()` calls `Algorithm::process()` to fill its buffer.
97///
98/// Low-level DSP components (filters, generators, effects) also implement this
99/// trait directly, making them usable both inside the graph and standalone.
100///
101/// # Required methods
102/// - `process()` — the main per-block processing entry point.
103/// - `reset()` — restore initial state.
104///
105/// # Optional methods
106/// - `init()` — configure sample rate.
107/// - `apply_command()` — receive a real-time parameter value from the control
108///   path (called between samples by the graph driver).
109/// - `metadata()` — return descriptive info (defaults to empty).
110pub trait Algorithm<T: Transcendental>: Send + Sync {
111    /// Process one block of signal.
112    ///
113    /// # Arguments
114    /// * `input`  — Signal data from upstream (empty when the port is
115    ///   unconnected, or `None` for source ports / control output ports).
116    /// * `output` — Buffer to fill with processed data.
117    fn process(&mut self, input: Option<&[T]>, output: &mut [T]) -> ProcessResult<()>;
118
119    /// Receive a real-time command value from the control path.
120    ///
121    /// Called by the graph driver between `process()` calls when a
122    /// `SetParameter` targets this port. The algorithm should store the
123    /// value and apply it (possibly smoothed) on the next `process()`.
124    ///
125    /// Default: no-op.
126    fn apply_command(&mut self, _value: T) {}
127
128    /// Initialise the algorithm with a sample rate.
129    ///
130    /// Called once when the node is added to the graph. Available for
131    /// coefficient pre-computation.
132    ///
133    /// Default: no-op.
134    fn init(&mut self, _sample_rate: f32) {}
135
136    /// Reset the algorithm to its initial state.
137    ///
138    /// Called when the owning node is reset, or when feedback delay lines
139    /// need clearing.
140    fn reset(&mut self);
141
142    /// Descriptive metadata (defaults to empty).
143    fn metadata(&self) -> AlgorithmMetadata {
144        AlgorithmMetadata::empty()
145    }
146}
147
148// ============================================================================
149// ParameterizedAlgorithm Trait
150// ============================================================================
151
152/// An `Algorithm` with typed, settable parameters.
153///
154/// Extends the base [`Algorithm`] trait with the ability to get and set
155/// a typed parameter struct (`Params`) and to update individual parameters
156/// by name (for automation integration).
157///
158/// # Type parameter
159///
160/// `Params` — the concrete parameter type. Must be `Clone + Send + Sync`.
161/// Different algorithm families use different structs (e.g. `FilterParams`
162/// for DSP filters, `StringParams` for string models).
163pub trait ParameterizedAlgorithm<T: Transcendental>: Algorithm<T> {
164    /// The concrete parameter type for this algorithm.
165    type Params: Clone + Send + Sync;
166
167    /// Get a reference to the current parameters.
168    fn params(&self) -> &Self::Params;
169
170    /// Replace all parameters atomically.
171    ///
172    /// The implementation should recompute any derived coefficients.
173    fn set_params(&mut self, params: Self::Params);
174
175    /// Set a single parameter by name (for automation / scripting).
176    ///
177    /// Default: returns an error for any unrecognised name.
178    fn set_parameter(&mut self, _name: &str, _value: ParamValue) -> Result<(), &'static str> {
179        Err(format!("Parameter '{}' not supported", _name).leak())
180    }
181}