use std::iter::{self, Peekable};
pub mod player;
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Pattern<M>(PatternInner<M>);
#[derive(Debug, Clone, PartialEq, PartialOrd)]
enum PatternInner<M> {
Event(Event<M>),
Parallel(Vec<Pattern<M>>),
Sequence(Vec<Pattern<M>>),
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Event<M> {
pub delta: f64,
pub event: EventOrRest<M>,
}
impl<M> Event<M> {
pub fn new(delta: f64, event: impl Into<M>) -> Event<M> {
Event {
delta,
event: EventOrRest::Event(event.into()),
}
}
pub fn rest(delta: f64) -> Event<M> {
Event {
delta,
event: EventOrRest::Rest,
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum EventOrRest<M> {
Event(M),
Rest,
}
pub fn sequence<M>(f: impl FnOnce(&mut Sequence<M>)) -> Pattern<M> {
let mut seq = Sequence(Patterns::new());
f(&mut seq);
let Sequence(Patterns(patterns)) = seq;
Pattern(PatternInner::Sequence(patterns))
}
#[derive(Debug)]
pub struct Sequence<M>(Patterns<M>);
impl<M> Sequence<M> {
pub fn play(&mut self, delta: f64, event: impl Into<M>) {
self.0.play(delta, event.into())
}
pub fn rest(&mut self, delta: f64) {
self.0.rest(delta)
}
pub fn embed(&mut self, pattern: Pattern<M>) {
self.0.embed(pattern)
}
pub fn parallel(&mut self, f: impl FnOnce(&mut Parallel<M>)) {
self.0.embed(parallel(f))
}
}
pub fn parallel<M>(f: impl FnOnce(&mut Parallel<M>)) -> Pattern<M> {
let mut seq = Parallel(Patterns::new());
f(&mut seq);
let Parallel(Patterns(patterns)) = seq;
Pattern(PatternInner::Parallel(patterns))
}
#[derive(Debug)]
pub struct Parallel<M>(Patterns<M>);
impl<M> Parallel<M> {
pub fn play(&mut self, delta: f64, event: impl Into<M>) {
self.0.play(delta, event.into())
}
pub fn embed(&mut self, pattern: Pattern<M>) {
self.0.embed(pattern)
}
pub fn sequence(&mut self, f: impl FnOnce(&mut Sequence<M>)) {
self.0.embed(sequence(f));
}
}
#[derive(Debug)]
struct Patterns<M>(Vec<Pattern<M>>);
impl<M> Patterns<M> {
fn new() -> Patterns<M> {
Patterns(Vec::new())
}
fn play(&mut self, delta: f64, event: M) {
self.0.push(Pattern(PatternInner::Event(Event {
delta,
event: EventOrRest::Event(event),
})));
}
fn rest(&mut self, delta: f64) {
self.0.push(Pattern(PatternInner::Event(Event {
delta,
event: EventOrRest::Rest,
})));
}
fn embed(&mut self, pattern: Pattern<M>) {
self.0.push(pattern);
}
}
#[must_use]
#[derive(Debug)]
pub struct IntoIter<M>(IntoIterInner<M>);
#[derive(Debug)]
enum IntoIterInner<M> {
Event(iter::Once<Event<M>>),
Parallel(ParallelIter<M>),
Sequence(Box<SequenceIntoIter<M>>),
}
type SequenceIntoIter<M> =
iter::FlatMap<std::vec::IntoIter<Pattern<M>>, IntoIter<M>, fn(Pattern<M>) -> IntoIter<M>>;
impl<M> IntoIterator for Pattern<M> {
type Item = Event<M>;
type IntoIter = IntoIter<M>;
fn into_iter(self) -> Self::IntoIter {
IntoIter(match self.0 {
PatternInner::Event(event) => IntoIterInner::Event(iter::once(event)),
PatternInner::Parallel(patterns) => {
IntoIterInner::Parallel(ParallelIter::new(patterns))
}
PatternInner::Sequence(patterns) => {
IntoIterInner::Sequence(Box::new(patterns.into_iter().flat_map(Pattern::into_iter)))
}
})
}
}
impl<M> Iterator for IntoIter<M> {
type Item = Event<M>;
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
IntoIterInner::Event(ref mut iter) => iter.next(),
IntoIterInner::Parallel(ref mut iter) => iter.next(),
IntoIterInner::Sequence(ref mut iter) => iter.next(),
}
}
}
#[must_use]
#[derive(Debug)]
struct ParallelIter<M> {
merged: Peekable<Merged<M>>,
}
impl<M> ParallelIter<M> {
fn new(patterns: Vec<Pattern<M>>) -> Self {
Self {
merged: Merged::new(patterns).peekable(),
}
}
}
impl<M> Iterator for ParallelIter<M> {
type Item = Event<M>;
fn next(&mut self) -> Option<Self::Item> {
let (position, mut event) = self.merged.next()?;
if let Some((next_position, _)) = self.merged.peek() {
event.delta = next_position - position;
}
Some(event)
}
}
#[must_use]
#[derive(Debug)]
struct Merged<M> {
iters: Vec<Peekable<Position<M>>>,
}
impl<M> Merged<M> {
fn new(patterns: Vec<Pattern<M>>) -> Self {
Self {
iters: patterns
.into_iter()
.map(|pattern| Position::new(pattern.into_iter()).peekable())
.collect(),
}
}
}
impl<M> Iterator for Merged<M> {
type Item = (f64, Event<M>);
fn next(&mut self) -> Option<Self::Item> {
self.iters
.iter_mut()
.flat_map(|iter| {
let (position, _) = iter.peek()?;
Some((*position, iter))
})
.min_by(|(position1, _), (position2, _)| position1.partial_cmp(position2).unwrap())
.and_then(|(_, iter)| iter.next())
}
}
#[must_use]
#[derive(Debug)]
struct Position<M> {
position: f64,
iter: IntoIter<M>,
}
impl<M> Position<M> {
fn new(iter: IntoIter<M>) -> Self {
Self {
position: 0.0,
iter,
}
}
}
impl<M> Iterator for Position<M> {
type Item = (f64, Event<M>);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|event| {
let position = self.position;
self.position += event.delta;
(position, event)
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parallel_test_empty_seq() {
assert!(stream_pattern(sequence(|_| {})).is_empty());
}
#[test]
fn parallel_test_left_identity() {
let a: Pattern<i32> = sequence(|s| {
s.play(1.0, 0);
s.play(1.0, 0);
});
let b: Pattern<i32> = sequence(|_| {});
assert_eq!(
stream_pattern(a.clone()),
stream_pattern(parallel(|p| {
p.embed(a);
p.embed(b);
})),
);
}
#[test]
fn parallel_test_right_identity() {
let a: Pattern<i32> = sequence(|_| {});
let b: Pattern<i32> = sequence(|s| {
s.play(1.0, 0);
s.play(1.0, 0);
});
assert_eq!(
stream_pattern(b.clone()),
stream_pattern(parallel(|p| {
p.embed(a);
p.embed(b);
})),
);
}
#[test]
fn parallel_test_delta_adjustment() {
let a: Pattern<i32> = sequence(|s| {
s.play(1.0, 1);
s.play(1.0, 2);
});
let b: Pattern<i32> = sequence(|s| {
s.play(1.0, 3);
s.play(1.0, 4);
});
assert_eq!(
vec![
Event::new(0.0, 1),
Event::new(1.0, 3),
Event::new(0.0, 2),
Event::new(1.0, 4)
],
stream_pattern(parallel(|p| {
p.embed(a);
p.embed(b);
})),
);
}
#[test]
fn parallel_test_uneven_lengths() {
let a: Pattern<i32> = sequence(|s| s.play(1.0, 1));
let b: Pattern<i32> = sequence(|s| {
s.play(1.0, 2);
s.play(1.0, 3);
});
assert_eq!(
vec![Event::new(0.0, 1), Event::new(1.0, 2), Event::new(1.0, 3),],
stream_pattern(parallel(|p| {
p.embed(a);
p.embed(b)
})),
);
}
fn stream_pattern(pattern: Pattern<i32>) -> Vec<Event<i32>> {
pattern.into_iter().collect()
}
}