use super::step::SequenceStep;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum StepPlayMode {
OneShot,
Loop,
PingPong,
Random,
Brownian,
}
impl StepPlayMode {
pub fn next_index(&self, current: usize, len: usize) -> usize {
if len == 0 {
return 0;
}
match self {
StepPlayMode::OneShot => current.min(len.saturating_sub(1)),
StepPlayMode::Loop => (current + 1) % len,
StepPlayMode::PingPong => current,
StepPlayMode::Random => {
use rand::Rng;
let mut rng = rand::thread_rng();
rng.gen_range(0..len)
}
StepPlayMode::Brownian => {
use rand::Rng;
let mut rng = rand::thread_rng();
let offset: isize = rng.gen_range(-1..=1);
let next = current as isize + offset;
next.clamp(0, len.saturating_sub(1) as isize) as usize
}
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub struct Pattern {
pub id: String,
pub steps: Vec<SequenceStep>,
pub play_mode: StepPlayMode,
}
impl Pattern {
pub fn new(id: impl Into<String>, steps: Vec<SequenceStep>) -> Self {
Self {
id: id.into(),
steps,
play_mode: StepPlayMode::Loop,
}
}
pub fn with_mode(mut self, mode: StepPlayMode) -> Self {
self.play_mode = mode;
self
}
pub fn is_empty(&self) -> bool {
self.steps.is_empty()
}
pub fn len(&self) -> usize {
self.steps.len()
}
}