Skip to main content

audio_engine_core/processor/
traits.rs

1//! Audio Processor Traits
2//!
3//! Defines the unified interface for all DSP processors in the audio pipeline.
4//! This abstraction enables a composable DSP chain with guaranteed continuity.
5
6/// Processing result status
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum ProcessResult {
9    /// Normal processing completed
10    Ok,
11    /// Processor is disabled, signal passed through unchanged
12    Bypassed,
13}
14
15/// Core audio processor trait
16///
17/// All DSP processors must implement this trait to be used in the DspChain.
18/// The trait provides a unified interface for:
19/// - Audio processing
20/// - State reset
21/// - Enable/disable control
22///
23/// # Thread Safety
24///
25/// Implementations must be `Send` because processors are owned by the audio thread.
26/// Parameters should be passed via the snapshot types in `lockfree_params`.
27///
28/// # Example
29///
30/// ```ignore
31/// use crate::processor::traits::{AudioProcessor, ProcessResult};
32///
33/// struct MyProcessor {
34///     enabled: bool,
35///     gain: f64,
36/// }
37///
38/// impl AudioProcessor for MyProcessor {
39///     fn name(&self) -> &'static str { "MyProcessor" }
40///     
41///     fn process(&mut self, buffer: &mut [f64], channels: usize) -> ProcessResult {
42///         if !self.enabled {
43///             return ProcessResult::Bypassed;
44///         }
45///         for sample in buffer.iter_mut() {
46///             *sample *= self.gain;
47///         }
48///         ProcessResult::Ok
49///     }
50///     
51///     fn reset(&mut self) {}
52///     fn is_enabled(&self) -> bool { self.enabled }
53///     fn set_enabled(&mut self, enabled: bool) { self.enabled = enabled; }
54/// }
55/// ```
56pub trait AudioProcessor: Send {
57    /// Processor name for debugging and logging
58    fn name(&self) -> &'static str;
59
60    /// Process audio samples in-place
61    ///
62    /// # Arguments
63    /// * `buffer` - Interleaved audio samples [L, R, L, R, ...]
64    /// * `channels` - Number of audio channels
65    ///
66    /// # Returns
67    /// Processing result status indicating what happened
68    fn process(&mut self, buffer: &mut [f64], channels: usize) -> ProcessResult;
69
70    /// Reset internal state (filter delay lines, etc.)
71    ///
72    /// Called when:
73    /// - Starting a new track
74    /// - Changing sample rate
75    /// - After gapless track switch
76    fn reset(&mut self);
77
78    /// Check if processor is enabled
79    fn is_enabled(&self) -> bool;
80
81    /// Enable or disable the processor
82    fn set_enabled(&mut self, enabled: bool);
83
84    /// Update sample rate and recalculate internal coefficients if needed.
85    ///
86    /// Default implementation is no-op for processors that are sample-rate agnostic.
87    fn set_sample_rate(&mut self, _sample_rate: f64) {}
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    struct TestProcessor {
95        enabled: bool,
96        gain: f64,
97    }
98
99    impl AudioProcessor for TestProcessor {
100        fn name(&self) -> &'static str {
101            "TestProcessor"
102        }
103
104        fn process(&mut self, buffer: &mut [f64], _channels: usize) -> ProcessResult {
105            if !self.enabled {
106                return ProcessResult::Bypassed;
107            }
108            for sample in buffer.iter_mut() {
109                *sample *= self.gain;
110            }
111            ProcessResult::Ok
112        }
113
114        fn reset(&mut self) {}
115
116        fn is_enabled(&self) -> bool {
117            self.enabled
118        }
119
120        fn set_enabled(&mut self, enabled: bool) {
121            self.enabled = enabled;
122        }
123    }
124
125    #[test]
126    fn test_processor_enabled() {
127        let mut proc = TestProcessor {
128            enabled: true,
129            gain: 0.5,
130        };
131        let mut buffer = vec![1.0, 1.0];
132        let result = proc.process(&mut buffer, 1);
133        assert_eq!(result, ProcessResult::Ok);
134        assert!((buffer[0] - 0.5).abs() < 1e-10);
135    }
136
137    #[test]
138    fn test_processor_bypassed() {
139        let mut proc = TestProcessor {
140            enabled: false,
141            gain: 0.5,
142        };
143        let mut buffer = vec![1.0, 1.0];
144        let result = proc.process(&mut buffer, 1);
145        assert_eq!(result, ProcessResult::Bypassed);
146        assert!((buffer[0] - 1.0).abs() < 1e-10);
147    }
148}