Skip to main content

rill_core_dsp/macros/
parameterized.rs

1//! Macro for creating a parameterized algorithm
2//!
3//! # Example
4//! ```
5//! use rill_core_dsp::parameterized_algorithm;
6//! use rill_core::math::Transcendental;
7//!
8//! parameterized_algorithm! {
9//!     /// Filter with variable cutoff frequency
10//!     #[derive(Debug, Clone, Copy)]
11//!     pub struct LowPass<T: Transcendental> {
12//!         params: {
13//!             /// Cutoff frequency in Hz
14//!             cutoff: T = T::from_f32(1000.0),
15//!             /// Quality factor
16//!             q: T = T::from_f32(0.707),
17//!         },
18//!         state: {
19//!             /// Internal filter state
20//!             y1: T = T::ZERO,
21//!             y2: T = T::ZERO,
22//!         },
23//!         update: |this| {
24//!             // Update coefficients when parameters change
25//!         },
26//!         process: |this, input| {
27//!             // Process with current parameters
28//!             input
29//!         }
30//!     }
31//! }
32//! ```
33
34/// Macro for creating a parameterized algorithm
35///
36/// # Example
37/// ```
38/// use rill_core_dsp::parameterized_algorithm;
39/// use rill_core::math::Transcendental;
40///
41/// parameterized_algorithm! {
42///     /// Filter with variable cutoff frequency
43///     #[derive(Debug, Clone, Copy)]
44///     pub struct LowPass<T: Transcendental> {
45///         params: {
46///             /// Cutoff frequency in Hz
47///             cutoff: T = T::from_f32(1000.0),
48///             /// Quality factor
49///             q: T = T::from_f32(0.707),
50///         },
51///         state: {
52///             /// Internal filter state
53///             y1: T = T::ZERO,
54///             y2: T = T::ZERO,
55///         },
56///         update: |this| {
57///             // Update coefficients when parameters change
58///         },
59///         process: |this, input| {
60///             // Process with current parameters
61///             input
62///         }
63///     }
64/// }
65/// ```
66#[macro_export]
67macro_rules! parameterized_algorithm {
68    (
69        $(#[$struct_meta:meta])*
70        $vis:vis struct $name:ident<$($generic:ident: $bound:path),+> {
71            params: {
72                $(
73                    $(#[$param_meta:meta])*
74                    $param_name:ident : $param_type:ty = $param_default:expr
75                ),* $(,)?
76            },
77            state: {
78                $(
79                    $(#[$state_meta:meta])*
80                    $state_name:ident : $state_type:ty = $state_default:expr
81                ),* $(,)?
82            },
83            update: $update:expr,
84            process: $process:expr
85        }
86    ) => {
87        $(#[$struct_meta])*
88        $vis struct $name<$($generic: $bound),+> {
89            $(
90                $(#[$param_meta])*
91                pub $param_name: $param_type,
92            )*
93
94            $(
95                $(#[$state_meta])*
96                pub $state_name: $state_type,
97            )*
98
99            /// Sample rate
100            pub sample_rate: f32,
101        }
102
103        impl<$($generic: $bound),+> $name<$($generic),+> {
104            /// Create a new algorithm instance
105            pub fn new($($param_name: $param_type),*) -> Self {
106                Self {
107                    $($param_name),*,
108                    $($state_name: $state_default),*,
109                    sample_rate: 44100.0,
110                }
111            }
112
113            /// Update internal coefficients
114            pub fn update_coeffs(&mut self) {
115                let update_fn: fn(&mut Self) = $update;
116                update_fn(self);
117            }
118        }
119
120        impl<$($generic: $bound),+> rill_core::traits::algorithm::Algorithm<T> for $name<$($generic),+>
121        where
122            T: rill_core::math::Transcendental,
123        {
124            fn init(&mut self, sample_rate: f32) {
125                self.sample_rate = sample_rate;
126                self.update_coeffs();
127            }
128
129            fn reset(&mut self) {
130                $(
131                    self.$state_name = $state_default;
132                )*
133            }
134
135            fn process(
136                &mut self,
137                input: Option<&[T]>,
138                output: &mut [T],
139            ) -> rill_core::traits::ProcessResult<()> {
140                let input = input.unwrap_or(&[]);
141                let len = input.len().min(output.len());
142                let process_fn: fn(&mut Self, T) -> T = $process;
143                for i in 0..len {
144                    output[i] = process_fn(self, input[i]);
145                }
146                Ok(())
147            }
148
149            fn metadata(&self) -> rill_core::traits::algorithm::AlgorithmMetadata {
150                rill_core::traits::algorithm::AlgorithmMetadata {
151                    name: stringify!($name),
152                    category: rill_core::traits::algorithm::AlgorithmCategory::Utility,
153                    description: stringify!($name),
154                    author: "Rill",
155                    version: env!("CARGO_PKG_VERSION"),
156                }
157            }
158        }
159    };
160}