rill_patchbay/automaton/
sequencer.rs1use crate::engine::{Automaton, NoAction, Range, Time};
7use rill_core::traits::ParamValue;
8
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[derive(Debug, Clone)]
16pub struct Step {
17 pub duration: f64,
19}
20
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23#[derive(Debug, Clone, Copy, PartialEq)]
24pub enum PlayMode {
25 OneShot,
27 Loop,
29 PingPong,
31 Random,
33 Brownian,
35}
36
37#[derive(Debug, Clone)]
39pub struct SequencerAutomaton {
40 name: String,
42 steps: Vec<Step>,
44 mode: PlayMode,
46 tempo: f64,
48 duration_scale: f64,
50 interpolate: bool,
52 range: Range,
54}
55
56impl SequencerAutomaton {
57 pub fn new(name: &str, steps: Vec<Step>) -> Self {
59 Self {
60 name: name.to_string(),
61 steps,
62 mode: PlayMode::Loop,
63 tempo: 120.0,
64 duration_scale: 1.0,
65 interpolate: false,
66 range: Range::unipolar(),
67 }
68 }
69
70 pub fn with_mode(mut self, mode: PlayMode) -> Self {
72 self.mode = mode;
73 self
74 }
75
76 pub fn with_tempo(mut self, bpm: f64) -> Self {
78 self.tempo = bpm.max(1.0);
79 self
80 }
81
82 pub fn with_interpolation(mut self, interpolate: bool) -> Self {
84 self.interpolate = interpolate;
85 self
86 }
87
88 pub fn with_range(mut self, range: Range) -> Self {
90 self.range = range;
91 self
92 }
93
94 fn step_duration(&self, step: &Step) -> f64 {
99 step.duration * 60.0 / self.tempo * self.duration_scale
100 }
101
102 fn xorshift(&self, rng: &mut u64) -> u64 {
104 let mut x = *rng;
105 x ^= x << 13;
106 x ^= x >> 7;
107 x ^= x << 17;
108 *rng = x;
109 x
110 }
111
112 fn random_index(&self, rng: &mut u64) -> usize {
114 let x = self.xorshift(rng);
115 (x as usize) % self.steps.len()
116 }
117
118 fn next_step(&self, current_step: usize, direction: i8, rng_state: &mut u64) -> (usize, i8) {
120 match self.mode {
121 PlayMode::OneShot => {
122 if current_step < self.steps.len() - 1 {
123 (current_step + 1, direction)
124 } else {
125 (current_step, direction)
126 }
127 }
128
129 PlayMode::Loop => ((current_step + 1) % self.steps.len(), direction),
130
131 PlayMode::PingPong => {
132 let next = current_step as i32 + direction as i32;
133 if next < 0 {
134 (1, 1)
135 } else if next >= self.steps.len() as i32 {
136 (self.steps.len() - 2, -1)
137 } else {
138 (next as usize, direction)
139 }
140 }
141
142 PlayMode::Random => (self.random_index(rng_state), direction),
143
144 PlayMode::Brownian => {
145 let mut candidates = vec![current_step];
146 if current_step > 0 {
147 candidates.push(current_step - 1);
148 }
149 if current_step < self.steps.len() - 1 {
150 candidates.push(current_step + 1);
151 }
152 let idx = self.random_index(rng_state) % candidates.len();
153 (candidates[idx], direction)
154 }
155 }
156 }
157}
158
159impl Automaton for SequencerAutomaton {
160 type Internal = (usize, f64, i8, u64);
161 type Action = NoAction;
162
163 fn step(
164 &self,
165 internal: &mut Self::Internal,
166 _current: &ParamValue,
167 time: Time,
168 _action: &Self::Action,
169 ) -> ParamValue {
170 let (current_step, step_start_time, direction, mut rng_state) = *internal;
171
172 if self.steps.is_empty() {
173 return ParamValue::Int(0);
174 }
175
176 let current_step_data = &self.steps[current_step];
177 let step_dur = self.step_duration(current_step_data);
178 let elapsed = time - step_start_time;
179
180 if elapsed >= step_dur {
181 let (next, new_dir) = self.next_step(current_step, direction, &mut rng_state);
182 *internal = (next, time, new_dir, rng_state);
183 ParamValue::Int(next as i32)
184 } else {
185 ParamValue::Int(current_step as i32)
186 }
187 }
188
189 fn initial_internal(&self) -> Self::Internal {
190 (0, 0.0, 1, 123456789)
191 }
192
193 fn name(&self) -> &str {
194 &self.name
195 }
196}
197
198pub fn simple_sequence(count: usize, duration: f64) -> Vec<Step> {
200 (0..count).map(|_| Step { duration }).collect()
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206
207 #[test]
208 fn test_sequencer() {
209 let steps = simple_sequence(4, 1.0);
210 let seq = SequencerAutomaton::new("Test", steps);
211 let mut internal = seq.initial_internal();
212 let current = ParamValue::Float(0.0);
213
214 assert_eq!(internal.0, 0);
215
216 let _value = seq.step(&mut internal, ¤t, 0.6, &NoAction);
217 assert_eq!(internal.0, 1);
218 }
219}