rill_core_dsp/macros/generator.rs
1//! Macro for creating a generator
2//!
3//! # Example
4//! use rill_core_dsp::generator_algorithm;
5//! use rill_core::math::Transcendental;
6//!
7//! generator_algorithm! {
8//! /// Sine generator
9//! #[derive(Debug, Clone, Copy)]
10//! pub struct SineGen<T: Transcendental> {
11//! params: {
12//! freq: T = T::from_f32(440.0),
13//! amp: T = T::from_f32(0.5),
14//! },
15//! state: {
16//! phase: T = T::ZERO,
17//! },
18//! generate: |this| {
19//! let output = (this.phase * T::from_f32(2.0 * std::f32::consts::PI)).sin() * this.amp;
20//! let phase_inc = this.freq / T::from_f32(this.sample_rate);
21//! this.phase = (this.phase + phase_inc) % T::from_f32(1.0);
22//! output
23//! }
24//! }
25//! }
26
27/// Macro for creating a generator
28///
29/// # Example
30/// use rill_core_dsp::generator_algorithm;
31/// use rill_core::math::Transcendental;
32///
33/// generator_algorithm! {
34/// /// Sine generator
35/// #[derive(Debug, Clone, Copy)]
36/// pub struct SineGen<T: Transcendental> {
37/// params: {
38/// freq: T = T::from_f32(440.0),
39/// amp: T = T::from_f32(0.5),
40/// },
41/// state: {
42/// phase: T = T::ZERO,
43/// },
44/// generate: |this| {
45/// let output = (this.phase * T::from_f32(2.0 * std::f32::consts::PI)).sin() * this.amp;
46/// let phase_inc = this.freq / T::from_f32(this.sample_rate);
47/// this.phase = (this.phase + phase_inc) % T::from_f32(1.0);
48/// output
49/// }
50/// }
51/// }
52#[macro_export]
53macro_rules! generator_algorithm {
54 (
55 $(#[$struct_meta:meta])*
56 $vis:vis struct $name:ident<$($generic:ident: $bound:path),+> {
57 params: {
58 $(
59 $(#[$param_meta:meta])*
60 $param_name:ident : $param_type:ty = $param_default:expr
61 ),* $(,)?
62 },
63 state: {
64 $(
65 $(#[$state_meta:meta])*
66 $state_name:ident : $state_type:ty = $state_default:expr
67 ),* $(,)?
68 },
69 generate: $generate:expr
70 }
71 ) => {
72 $(#[$struct_meta])*
73 $vis struct $name<$($generic: $bound),+> {
74 $(
75 $(#[$param_meta])*
76 pub $param_name: $param_type,
77 )*
78
79 $(
80 $(#[$state_meta])*
81 pub $state_name: $state_type,
82 )*
83
84 /// Sample rate
85 pub sample_rate: f32,
86 }
87
88 impl<$($generic: $bound),+> $name<$($generic),+> {
89 /// Create a new generator instance
90 pub fn new($($param_name: $param_type),*) -> Self {
91 Self {
92 $($param_name),*,
93 $($state_name: $state_default),*,
94 sample_rate: 44100.0,
95 }
96 }
97 }
98
99 impl<$($generic: $bound),+> rill_core::traits::algorithm::Algorithm<T> for $name<$($generic),+>
100 where
101 T: rill_core::math::Transcendental,
102 {
103 fn init(&mut self, sample_rate: f32) {
104 self.sample_rate = sample_rate;
105 }
106
107 fn reset(&mut self) {
108 $(
109 self.$state_name = $state_default;
110 )*
111 }
112
113 fn process(
114 &mut self,
115 _input: Option<&[T]>,
116 output: &mut [T],
117 ) -> rill_core::traits::ProcessResult<()> {
118 let generate_fn: fn(&mut Self) -> T = $generate;
119 for out in output.iter_mut() {
120 *out = generate_fn(self);
121 }
122 Ok(())
123 }
124
125 fn metadata(&self) -> rill_core::traits::algorithm::AlgorithmMetadata {
126 rill_core::traits::algorithm::AlgorithmMetadata {
127 name: stringify!($name),
128 category: rill_core::traits::algorithm::AlgorithmCategory::Generator,
129 description: stringify!($name),
130 author: "Rill",
131 version: env!("CARGO_PKG_VERSION"),
132 }
133 }
134 }
135 };
136}