use std::{ops::Deref, sync::Arc, time::Duration};
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
use crate::{
events::{Event, MIDIDelta, MIDIEventEnum, TempoEvent},
num::MIDINum,
prelude::*,
};
use super::Delta;
struct ElementCountDebug(&'static str, usize);
impl std::fmt::Debug for ElementCountDebug {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}; {}]", self.0, self.1)
}
}
#[derive(Clone)]
pub struct ChannelStatistics<D: MIDINum> {
note_on_count: u64,
note_off_count: u64,
total_event_count: u64,
total_length_ticks: D,
tempo_events: Arc<[Delta<D, TempoEvent>]>,
}
impl<T: MIDINum> ChannelStatistics<T> {
pub fn note_on_count(&self) -> u64 {
self.note_on_count
}
pub fn note_count(&self) -> u64 {
self.note_on_count()
}
pub fn note_off_count(&self) -> u64 {
self.note_off_count
}
pub fn other_event_count(&self) -> u64 {
self.total_event_count - self.note_on_count - self.note_off_count
}
pub fn total_event_count(&self) -> u64 {
self.total_event_count
}
pub fn total_length_ticks(&self) -> T {
self.total_length_ticks
}
pub fn calculate_total_duration(&self, ppq: u16) -> Duration {
tempo_sequence_get_duration(&self.tempo_events, ppq, self.total_length_ticks)
}
}
impl<T: MIDINum> std::fmt::Debug for ChannelStatistics<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("ChannelStatistics")
.field("note_on_count", &self.note_on_count)
.field("note_off_count", &self.note_off_count)
.field("total_event_count", &self.total_event_count)
.field("other_event_count", &self.other_event_count())
.field("total_length_ticks", &self.total_length_ticks)
.field(
"tempo_events",
&ElementCountDebug("TempoEvent", self.tempo_events.len()),
)
.finish()
}
}
pub struct ChannelGroupStatistics<T: MIDINum> {
group: ChannelStatistics<T>,
channels: Vec<ChannelStatistics<T>>,
}
impl<T: MIDINum> ChannelGroupStatistics<T> {
pub fn channels(&self) -> &[ChannelStatistics<T>] {
&self.channels
}
}
impl<T: MIDINum> Deref for ChannelGroupStatistics<T> {
type Target = ChannelStatistics<T>;
fn deref(&self) -> &Self::Target {
&self.group
}
}
impl<T: MIDINum> std::fmt::Debug for ChannelGroupStatistics<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("ChannelGroupStatistics")
.field("group", &self.group)
.field(
"channels",
&ElementCountDebug("ChannelStatistics", self.channels.len()),
)
.finish()
}
}
pub fn tempo_sequence_get_duration<T: MIDINum>(
tempos: &[Delta<T, TempoEvent>],
ppq: u16,
ticks: T,
) -> Duration {
let mut ticks = ticks;
let mut time = 0.0;
let mut multiplier = (500000.0 / ppq as f64) / 1000000.0;
for t in tempos {
let offset = t.delta();
if offset > ticks {
break;
}
ticks -= offset;
let offset: f64 = offset.midi_num_into();
time += multiplier * offset;
multiplier = (t.tempo as f64 / ppq as f64) / 1000000.0;
}
let ticks: f64 = ticks.midi_num_into();
time += multiplier * ticks;
Duration::from_secs_f64(time)
}
pub fn get_channel_statistics<D: MIDINum, E: MIDIEventEnum + MIDIDelta<D>, Err>(
iter: impl Iterator<Item = Result<E, Err>>,
) -> Result<ChannelStatistics<D>, Err> {
let mut note_on_count = 0;
let mut note_off_count = 0;
let mut total_event_count = 0;
let mut total_length_ticks = D::zero();
let mut ticks_since_last_tempo = D::zero();
let mut tempo_events = Vec::new();
for event in iter {
let event = event?;
total_event_count += 1;
total_length_ticks += event.delta();
ticks_since_last_tempo += event.delta();
match event.as_event() {
Event::NoteOn(_) => note_on_count += 1,
Event::NoteOff(_) => note_off_count += 1,
Event::Tempo(t) => {
let ev = *t.clone();
let tempo_delta = Delta::new(ticks_since_last_tempo, ev);
tempo_events.push(tempo_delta);
ticks_since_last_tempo = D::zero();
}
_ => (),
}
}
Ok(ChannelStatistics {
note_on_count,
note_off_count,
total_event_count,
total_length_ticks,
tempo_events: tempo_events.into(),
})
}
pub fn get_channels_array_statistics<
D: MIDINum,
E: MIDIEventEnum + MIDIDelta<D>,
Err: Send,
I: Iterator<Item = Result<E, Err>> + Sized + Send,
>(
iters: Vec<I>,
) -> Result<ChannelGroupStatistics<D>, Err> {
let pool = iters
.into_par_iter()
.map(|iter| get_channel_statistics(iter));
let mut result = Vec::new();
pool.collect_into_vec(&mut result);
let mut channels = result.into_iter().collect_vec_result()?;
let tempo_vecs: Vec<_> = channels.iter().map(|c| c.tempo_events.clone()).collect();
let tempo_iterators: Vec<_> = tempo_vecs
.into_iter()
.map(|tempos| {
tempos
.iter()
.cloned()
.into_ok()
.collect::<Vec<_>>()
.into_iter()
})
.collect();
let merge = tempo_iterators
.into_iter()
.merge_all()
.collect_vec_result()
.unwrap();
let tempo_events: Arc<[Delta<D, TempoEvent>]> = merge.into();
for c in channels.iter_mut() {
c.tempo_events = tempo_events.clone();
}
let mut max_tick_length = D::zero();
for c in channels.iter() {
if c.total_length_ticks > max_tick_length {
max_tick_length = c.total_length_ticks;
}
}
let group = ChannelStatistics {
note_on_count: channels.iter().map(|c| c.note_on_count).sum(),
note_off_count: channels.iter().map(|c| c.note_off_count).sum(),
total_event_count: channels.iter().map(|c| c.total_event_count).sum(),
total_length_ticks: max_tick_length,
tempo_events,
};
Ok(ChannelGroupStatistics { group, channels })
}