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}