rill_patchbay/automaton/
function.rs1use crate::control::{Automaton, NoAction, Range, Time};
7use std::fmt;
8use std::sync::Arc;
9
10#[derive(Debug, Clone)]
12pub struct FunctionState {
13 pub value: f64,
15 pub last_time: Time,
17 pub user_state: Arc<dyn std::any::Any + Send + Sync>,
19}
20
21#[derive(Clone)]
23pub struct FunctionAutomaton {
24 name: String,
26 generator: Arc<dyn Fn(Time) -> f64 + Send + Sync>,
28 range: Range,
30}
31
32impl fmt::Debug for FunctionAutomaton {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 f.debug_struct("FunctionAutomaton")
35 .field("name", &self.name)
36 .field("range", &self.range)
37 .finish()
38 }
39}
40
41impl FunctionAutomaton {
42 pub fn new<F>(name: &str, generator: F) -> Self
44 where
45 F: Fn(Time) -> f64 + Send + Sync + 'static,
46 {
47 Self {
48 name: name.to_string(),
49 generator: Arc::new(generator),
50 range: Range::bipolar(),
51 }
52 }
53
54 pub fn with_range(mut self, range: Range) -> Self {
56 self.range = range;
57 self
58 }
59}
60
61impl Automaton for FunctionAutomaton {
62 type State = f64;
63 type Action = NoAction;
64
65 fn step(
66 &self,
67 time: Time,
68 _action: &Self::Action,
69 _state: &Self::State,
70 ) -> (Self::State, Option<f64>) {
71 let value = (self.generator)(time);
72 let clamped = self.range.clamp(value);
73
74 (clamped, Some(clamped))
75 }
76
77 fn initial_state(&self) -> Self::State {
78 0.0
79 }
80
81 fn name(&self) -> &str {
82 &self.name
83 }
84
85 fn extract_value(&self, state: &Self::State) -> f64 {
86 *state
87 }
88}
89
90#[derive(Clone)]
92pub struct StatefulFunctionAutomaton<S> {
93 name: String,
95 generator: Arc<dyn Fn(Time, &mut S) -> f64 + Send + Sync>,
97 initial_state: S,
99 range: Range,
101}
102
103impl<S: fmt::Debug + Send + Sync + Clone + 'static> fmt::Debug for StatefulFunctionAutomaton<S> {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 f.debug_struct("StatefulFunctionAutomaton")
106 .field("name", &self.name)
107 .field("initial_state", &self.initial_state)
108 .field("range", &self.range)
109 .finish()
110 }
111}
112
113impl<S: Send + Sync + Clone + 'static> StatefulFunctionAutomaton<S> {
114 pub fn new<F>(name: &str, generator: F, initial_state: S) -> Self
116 where
117 F: Fn(Time, &mut S) -> f64 + Send + Sync + 'static,
118 {
119 Self {
120 name: name.to_string(),
121 generator: Arc::new(generator),
122 initial_state,
123 range: Range::bipolar(),
124 }
125 }
126
127 pub fn with_range(mut self, range: Range) -> Self {
129 self.range = range;
130 self
131 }
132}
133
134impl<S: fmt::Debug + Send + Sync + Clone + 'static> Automaton for StatefulFunctionAutomaton<S> {
135 type State = (f64, S);
136 type Action = NoAction;
137
138 fn step(
139 &self,
140 time: Time,
141 _action: &Self::Action,
142 state: &Self::State,
143 ) -> (Self::State, Option<f64>) {
144 let mut user_state = state.1.clone();
145 let value = (self.generator)(time, &mut user_state);
146 let clamped = self.range.clamp(value);
147
148 ((clamped, user_state), Some(clamped))
149 }
150
151 fn initial_state(&self) -> Self::State {
152 let mut init = self.initial_state.clone();
153 let value = (self.generator)(0.0, &mut init);
154 (self.range.clamp(value), init)
155 }
156
157 fn name(&self) -> &str {
158 &self.name
159 }
160
161 fn extract_value(&self, state: &Self::State) -> f64 {
162 state.0
163 }
164}
165
166pub fn lfo_function(freq: f64, phase: f64, waveform: &'static str) -> impl Fn(Time) -> f64 {
168 move |t| {
169 let p = (t * freq + phase).fract();
170 match waveform {
171 "sine" => (p * 2.0 * std::f64::consts::PI).sin(),
172 "saw" => 2.0 * p - 1.0,
173 "square" => {
174 if p < 0.5 {
175 1.0
176 } else {
177 -1.0
178 }
179 }
180 _ => 0.0,
181 }
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn test_function_automaton() {
191 let automaton = FunctionAutomaton::new("Test", |t| (t * 2.0).sin());
192 let state = automaton.initial_state();
193
194 let (_state, value) = automaton.step(1.0, &NoAction, &state);
195 assert!(value.is_some());
196 }
197
198 #[test]
199 fn test_stateful_automaton() {
200 let automaton = StatefulFunctionAutomaton::new(
201 "Counter",
202 |_t, counter: &mut i32| {
203 *counter += 1;
204 *counter as f64
205 },
206 0,
207 )
208 .with_range(Range::new(0.0, 100.0));
209
210 let state = automaton.initial_state();
211 assert_eq!(state.0, 1.0);
212
213 let (new_state, _) = automaton.step(1.0, &NoAction, &state);
214 assert_eq!(new_state.0, 2.0);
215 }
216}