use crate::pattern::{self, EventOrRest, Pattern};
use crate::scheduler::{Job, JobDef};
use serde::{Deserialize, Serialize};
use std::time::{Duration, SystemTime};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub struct Tempo {
beat_duration: Duration,
}
impl Default for Tempo {
fn default() -> Tempo {
Tempo::from_bpm(120.0)
}
}
impl Tempo {
pub fn from_bpm(bpm: f64) -> Tempo {
let beat_duration = Duration::from_secs_f64(1.0 / bpm * 60.0);
Tempo { beat_duration }
}
}
impl From<Duration> for Tempo {
fn from(beat_duration: Duration) -> Tempo {
Tempo { beat_duration }
}
}
pub trait EventHandler<T> {
fn handle(&mut self, time: SystemTime, event: T);
}
impl<T, F> EventHandler<T> for F
where
F: FnMut(SystemTime, T),
{
fn handle(&mut self, time: SystemTime, event: T) {
self(time, event)
}
}
#[derive(Debug)]
pub struct Player<T, E> {
event_handler: E,
pattern: Pattern<T>,
tempo: Tempo,
}
impl<T, E> Player<T, E>
where
E: EventHandler<T>,
{
pub fn new(pattern: Pattern<T>, event_handler: E) -> Player<T, E> {
Player {
event_handler,
pattern,
tempo: Tempo::default(),
}
}
pub fn tempo(mut self, tempo: Tempo) -> Self {
self.tempo = tempo;
self
}
}
impl<T, E> JobDef for Player<T, E>
where
E: EventHandler<T>,
{
type Job = PlayerJob<T, E>;
fn init(self, logical_time: SystemTime) -> Option<Self::Job> {
self.restore(logical_time, PlayerSnapshot { position: 0.0 })
}
fn restore(self, logical_time: SystemTime, snapshot: PlayerSnapshot) -> Option<Self::Job> {
PlayerJob {
event_handler: self.event_handler,
iter: self.pattern.into_iter(),
next_event_time: logical_time,
position: snapshot.position,
tempo: self.tempo,
}
.fast_forward_to_now()
}
}
#[derive(Debug)]
pub struct PlayerJob<T, E> {
event_handler: E,
iter: pattern::IntoIter<T>,
next_event_time: SystemTime,
position: f64,
tempo: Tempo,
}
impl<T, E> PlayerJob<T, E> {
fn fast_forward_to_now(mut self) -> Option<Self> {
let mut position = 0.0;
while position < self.position {
position += self.iter.next()?.delta;
}
self.fast_forward_position(position);
Some(self)
}
fn fast_forward_position(&mut self, position: f64) {
let position_adjustment = position - self.position;
self.next_event_time += self.tempo.beat_duration.mul_f64(position_adjustment);
self.position = position;
}
}
impl<T, E> Job for PlayerJob<T, E>
where
E: EventHandler<T>,
{
type Snapshot = PlayerSnapshot;
fn run(&mut self, this_beat_time: SystemTime) -> Option<Duration> {
let next_beat_time = this_beat_time + self.tempo.beat_duration;
while self.next_event_time < next_beat_time {
let pattern::Event { event, delta } = self.iter.next()?;
if let EventOrRest::Event(event) = event {
self.event_handler.handle(self.next_event_time, event);
}
self.next_event_time += self.tempo.beat_duration.mul_f64(delta);
self.position += delta;
}
Some(self.tempo.beat_duration)
}
fn snapshot(self) -> PlayerSnapshot {
PlayerSnapshot {
position: self.position,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct PlayerSnapshot {
position: f64,
}