Skip to main content

rill_core_dsp/macros/
parameterized.rs

1//! Макрос для создания алгоритма с параметрами
2//!
3//! # Пример
4//! ```
5//! use rill_core_dsp::parameterized_algorithm;
6//! use rill_core::math::Transcendental;
7//!
8//! parameterized_algorithm! {
9//!     /// Фильтр с изменяемой частотой среза
10//!     #[derive(Debug, Clone, Copy)]
11//!     pub struct LowPass<T: Transcendental> {
12//!         params: {
13//!             /// Частота среза в Hz
14//!             cutoff: T = T::from_f32(1000.0),
15//!             /// Добротность
16//!             q: T = T::from_f32(0.707),
17//!         },
18//!         state: {
19//!             /// Внутреннее состояние фильтра
20//!             y1: T = T::ZERO,
21//!             y2: T = T::ZERO,
22//!         },
23//!         update: |this| {
24//!             // Обновление коэффициентов при изменении параметров
25//!         },
26//!         process: |this, input| {
27//!             // Процессинг с текущими параметрами
28//!             input
29//!         }
30//!     }
31//! }
32//! ```
33
34/// Макрос для создания алгоритма с параметрами
35///
36/// # Пример
37/// ```
38/// use rill_core_dsp::parameterized_algorithm;
39/// use rill_core::math::Transcendental;
40///
41/// parameterized_algorithm! {
42///     /// Фильтр с изменяемой частотой среза
43///     #[derive(Debug, Clone, Copy)]
44///     pub struct LowPass<T: Transcendental> {
45///         params: {
46///             /// Частота среза в Hz
47///             cutoff: T = T::from_f32(1000.0),
48///             /// Добротность
49///             q: T = T::from_f32(0.707),
50///         },
51///         state: {
52///             /// Внутреннее состояние фильтра
53///             y1: T = T::ZERO,
54///             y2: T = T::ZERO,
55///         },
56///         update: |this| {
57///             // Обновление коэффициентов при изменении параметров
58///         },
59///         process: |this, input| {
60///             // Процессинг с текущими параметрами
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            /// Частота дискретизации
100            pub sample_rate: f32,
101        }
102
103        impl<$($generic: $bound),+> $name<$($generic),+> {
104            /// Создать новый экземпляр алгоритма
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            /// Обновить внутренние коэффициенты
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),+> $crate::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                _ctx: &$crate::algorithm::ActionContext,
140            ) -> $crate::algorithm::ProcessResult<()> {
141                let input = input.unwrap_or(&[]);
142                let len = input.len().min(output.len());
143                let process_fn: fn(&mut Self, T) -> T = $process;
144                for i in 0..len {
145                    output[i] = process_fn(self, input[i]);
146                }
147                Ok(())
148            }
149
150            fn metadata(&self) -> $crate::algorithm::AlgorithmMetadata {
151                $crate::algorithm::AlgorithmMetadata {
152                    name: stringify!($name),
153                    category: $crate::algorithm::AlgorithmCategory::Utility,
154                    description: stringify!($name),
155                    author: "Rill",
156                    version: env!("CARGO_PKG_VERSION"),
157                }
158            }
159        }
160    };
161}