Skip to main content

adk_audio/traits/
processor.rs

1//! Audio processor trait and FxChain composition.
2
3use async_trait::async_trait;
4
5use crate::error::AudioResult;
6use crate::frame::AudioFrame;
7
8/// Trait for stateless or stateful DSP transforms on audio frames.
9///
10/// Implementors include normalizers, resamplers, noise suppressors,
11/// compressors, and the `FxChain` itself (enabling nested chains).
12#[async_trait]
13pub trait AudioProcessor: Send + Sync {
14    /// Process a single audio frame, returning the transformed result.
15    async fn process(&self, frame: &AudioFrame) -> AudioResult<AudioFrame>;
16}
17
18/// An ordered chain of `AudioProcessor` stages applied in series.
19///
20/// The output of stage N becomes the input to stage N+1.
21/// An empty chain returns the input frame unchanged.
22///
23/// # Example
24///
25/// ```ignore
26/// let chain = FxChain::new()
27///     .push(normalizer)
28///     .push(resampler);
29/// let output = chain.process(&input).await?;
30/// ```
31pub struct FxChain {
32    stages: Vec<Box<dyn AudioProcessor>>,
33}
34
35impl FxChain {
36    /// Create an empty FxChain.
37    pub fn new() -> Self {
38        Self { stages: Vec::new() }
39    }
40
41    /// Append a processing stage to the chain.
42    pub fn push(mut self, processor: impl AudioProcessor + 'static) -> Self {
43        self.stages.push(Box::new(processor));
44        self
45    }
46
47    /// Returns the number of stages in the chain.
48    pub fn len(&self) -> usize {
49        self.stages.len()
50    }
51
52    /// Returns true if the chain has no stages.
53    pub fn is_empty(&self) -> bool {
54        self.stages.is_empty()
55    }
56}
57
58impl Default for FxChain {
59    fn default() -> Self {
60        Self::new()
61    }
62}
63
64#[async_trait]
65impl AudioProcessor for FxChain {
66    async fn process(&self, frame: &AudioFrame) -> AudioResult<AudioFrame> {
67        let mut current = frame.clone();
68        for stage in &self.stages {
69            current = stage.process(&current).await?;
70        }
71        Ok(current)
72    }
73}