Skip to main content

rill_patchbay/sequencer/
pattern.rs

1use super::step::SequenceStep;
2
3/// Playback mode for a pattern.
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5#[derive(Debug, Clone, Copy, PartialEq)]
6pub enum StepPlayMode {
7    /// Play through once then stop.
8    OneShot,
9    /// Loop the pattern indefinitely.
10    Loop,
11    /// Forward then backward (ping-pong).
12    PingPong,
13    /// Pick steps at random.
14    Random,
15    /// Brownian motion — drift to neighbouring steps.
16    Brownian,
17}
18
19impl StepPlayMode {
20    /// Pick the next step index given the current one and the pattern length.
21    pub fn next_index(&self, current: usize, len: usize) -> usize {
22        if len == 0 {
23            return 0;
24        }
25        match self {
26            StepPlayMode::OneShot => current.min(len.saturating_sub(1)),
27            StepPlayMode::Loop => (current + 1) % len,
28            StepPlayMode::PingPong => current,
29            StepPlayMode::Random => {
30                use rand::Rng;
31                let mut rng = rand::thread_rng();
32                rng.gen_range(0..len)
33            }
34            StepPlayMode::Brownian => {
35                use rand::Rng;
36                let mut rng = rand::thread_rng();
37                let offset: isize = rng.gen_range(-1..=1);
38                let next = current as isize + offset;
39                next.clamp(0, len.saturating_sub(1) as isize) as usize
40            }
41        }
42    }
43}
44
45/// A sequence of steps forming a pattern.
46#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
47#[derive(Debug, Clone)]
48pub struct Pattern {
49    /// Unique pattern identifier.
50    pub id: String,
51    /// Ordered list of steps in this pattern.
52    pub steps: Vec<SequenceStep>,
53    /// Playback mode for the pattern.
54    pub play_mode: StepPlayMode,
55}
56
57impl Pattern {
58    /// Create a new pattern with the given ID and steps (defaults to `Loop` mode).
59    pub fn new(id: impl Into<String>, steps: Vec<SequenceStep>) -> Self {
60        Self {
61            id: id.into(),
62            steps,
63            play_mode: StepPlayMode::Loop,
64        }
65    }
66
67    /// Set the playback mode.
68    pub fn with_mode(mut self, mode: StepPlayMode) -> Self {
69        self.play_mode = mode;
70        self
71    }
72
73    /// Whether the pattern has zero steps.
74    pub fn is_empty(&self) -> bool {
75        self.steps.is_empty()
76    }
77
78    /// Number of steps in this pattern.
79    pub fn len(&self) -> usize {
80        self.steps.len()
81    }
82}