use std::convert::Infallible;
use crate::{MidiEvent, PumpError, TickTime};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TrackedMidiEvent {
pub last_track: usize,
pub event: MidiEvent,
}
pub trait MidiSource {
type Err;
fn tpq(&self) -> u32;
fn next(&mut self) -> Result<Option<MidiEvent>, Self::Err>;
}
pub trait TrackedMidiSource: MidiSource {
fn last_track(&self) -> usize;
fn n_tracks(&self) -> usize;
fn next_tracked(&mut self) -> Result<Option<TrackedMidiEvent>, Self::Err>;
}
pub trait MidiSink {
type Err;
fn tpq(&self) -> u32;
fn write(&mut self, event: &MidiEvent) -> Result<(), Self::Err>;
fn flush(&mut self) -> Result<(), Self::Err>;
}
#[derive(Clone, Debug, Default)]
pub struct MemoryMidiSource {
tpq: u32,
events: Vec<MidiEvent>,
cursor: usize,
}
impl MemoryMidiSource {
pub fn new(tpq: u32, mut events: Vec<MidiEvent>) -> Self {
events.sort_by_key(|event| event.time.ticks);
Self {
tpq,
events,
cursor: 0,
}
}
}
#[derive(Clone, Debug, Default)]
pub struct MemoryTrackedMidiSource {
tpq: u32,
events: Vec<TrackedMidiEvent>,
cursor: usize,
last_track: usize,
n_tracks: usize,
}
impl MemoryTrackedMidiSource {
pub fn new(tpq: u32, mut events: Vec<TrackedMidiEvent>) -> Self {
events.sort_by_key(|item| item.event.time.ticks);
let n_tracks = events
.iter()
.map(|item| item.last_track + 1)
.max()
.unwrap_or(0);
Self {
tpq,
events,
cursor: 0,
last_track: 0,
n_tracks,
}
}
}
impl MidiSource for MemoryMidiSource {
type Err = Infallible;
fn tpq(&self) -> u32 {
self.tpq
}
fn next(&mut self) -> Result<Option<MidiEvent>, Self::Err> {
let event = self.events.get(self.cursor).cloned();
if event.is_some() {
self.cursor += 1;
}
Ok(event)
}
}
impl MidiSource for MemoryTrackedMidiSource {
type Err = Infallible;
fn tpq(&self) -> u32 {
self.tpq
}
fn next(&mut self) -> Result<Option<MidiEvent>, Self::Err> {
let event = self.events.get(self.cursor).cloned();
if let Some(event) = &event {
self.last_track = event.last_track;
self.cursor += 1;
}
Ok(event.map(|item| item.event))
}
}
impl TrackedMidiSource for MemoryTrackedMidiSource {
fn last_track(&self) -> usize {
self.last_track
}
fn n_tracks(&self) -> usize {
self.n_tracks
}
fn next_tracked(&mut self) -> Result<Option<TrackedMidiEvent>, Self::Err> {
let event = self.events.get(self.cursor).cloned();
if let Some(event) = &event {
self.last_track = event.last_track;
self.cursor += 1;
}
Ok(event)
}
}
#[derive(Clone, Debug, Default)]
pub struct MemoryMidiSink {
tpq: u32,
events: Vec<MidiEvent>,
}
impl MemoryMidiSink {
pub fn new(tpq: u32) -> Self {
Self {
tpq,
events: Vec::new(),
}
}
pub fn events(&self) -> &[MidiEvent] {
&self.events
}
}
impl MidiSink for MemoryMidiSink {
type Err = Infallible;
fn tpq(&self) -> u32 {
self.tpq
}
fn write(&mut self, event: &MidiEvent) -> Result<(), Self::Err> {
self.events.push(event.clone());
self.events.sort_by_key(|item| item.time.ticks);
Ok(())
}
fn flush(&mut self) -> Result<(), Self::Err> {
Ok(())
}
}
pub fn pump<S, T>(source: &mut S, sink: &mut T) -> Result<usize, PumpError<S::Err, T::Err>>
where
S: MidiSource,
T: MidiSink,
{
let mut count = 0usize;
let sink_tpq = sink.tpq();
let source_tpq = source.tpq();
while let Some(mut event) = source.next().map_err(PumpError::Source)? {
if source_tpq != sink_tpq {
event.time = event.time.quantize(sink_tpq);
} else if event.time.tpq != sink_tpq {
event.time = TickTime {
ticks: event.time.ticks,
tpq: sink_tpq,
};
}
sink.write(&event).map_err(PumpError::Sink)?;
count += 1;
}
sink.flush().map_err(PumpError::Sink)?;
Ok(count)
}