midi_toolkit/sequence/event/
stats.rs1use std::{ops::Deref, sync::Arc, time::Duration};
2
3use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
4
5use crate::{
6 events::{Event, MIDIDelta, MIDIEventEnum, TempoEvent},
7 num::MIDINum,
8 prelude::*,
9};
10
11use super::Delta;
12
13struct ElementCountDebug(&'static str, usize);
14
15impl std::fmt::Debug for ElementCountDebug {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 write!(f, "[{}; {}]", self.0, self.1)
18 }
19}
20
21#[derive(Clone)]
23pub struct ChannelStatistics<D: MIDINum> {
24 note_on_count: u64,
25 note_off_count: u64,
26 total_event_count: u64,
27 total_length_ticks: D,
28 tempo_events: Arc<[Delta<D, TempoEvent>]>,
29}
30
31impl<T: MIDINum> ChannelStatistics<T> {
32 pub fn note_on_count(&self) -> u64 {
34 self.note_on_count
35 }
36
37 pub fn note_count(&self) -> u64 {
39 self.note_on_count()
40 }
41
42 pub fn note_off_count(&self) -> u64 {
44 self.note_off_count
45 }
46
47 pub fn other_event_count(&self) -> u64 {
51 self.total_event_count - self.note_on_count - self.note_off_count
52 }
53
54 pub fn total_event_count(&self) -> u64 {
56 self.total_event_count
57 }
58
59 pub fn total_length_ticks(&self) -> T {
61 self.total_length_ticks
62 }
63
64 pub fn calculate_total_duration(&self, ppq: u16) -> Duration {
67 tempo_sequence_get_duration(&self.tempo_events, ppq, self.total_length_ticks)
68 }
69}
70
71impl<T: MIDINum> std::fmt::Debug for ChannelStatistics<T> {
72 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
73 f.debug_struct("ChannelStatistics")
74 .field("note_on_count", &self.note_on_count)
75 .field("note_off_count", &self.note_off_count)
76 .field("total_event_count", &self.total_event_count)
77 .field("other_event_count", &self.other_event_count())
78 .field("total_length_ticks", &self.total_length_ticks)
79 .field(
80 "tempo_events",
81 &ElementCountDebug("TempoEvent", self.tempo_events.len()),
82 )
83 .finish()
84 }
85}
86
87pub struct ChannelGroupStatistics<T: MIDINum> {
89 group: ChannelStatistics<T>,
90 channels: Vec<ChannelStatistics<T>>,
91}
92
93impl<T: MIDINum> ChannelGroupStatistics<T> {
94 pub fn channels(&self) -> &[ChannelStatistics<T>] {
96 &self.channels
97 }
98}
99
100impl<T: MIDINum> Deref for ChannelGroupStatistics<T> {
101 type Target = ChannelStatistics<T>;
102
103 fn deref(&self) -> &Self::Target {
104 &self.group
105 }
106}
107
108impl<T: MIDINum> std::fmt::Debug for ChannelGroupStatistics<T> {
109 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
110 f.debug_struct("ChannelGroupStatistics")
111 .field("group", &self.group)
112 .field(
113 "channels",
114 &ElementCountDebug("ChannelStatistics", self.channels.len()),
115 )
116 .finish()
117 }
118}
119
120pub fn tempo_sequence_get_duration<T: MIDINum>(
121 tempos: &[Delta<T, TempoEvent>],
122 ppq: u16,
123 ticks: T,
124) -> Duration {
125 let mut ticks = ticks;
126 let mut time = 0.0;
127 let mut multiplier = (500000.0 / ppq as f64) / 1000000.0;
128 for t in tempos {
129 let offset = t.delta();
130 if offset > ticks {
131 break;
132 }
133 ticks -= offset;
134
135 let offset: f64 = offset.midi_num_into();
136 time += multiplier * offset;
137 multiplier = (t.tempo as f64 / ppq as f64) / 1000000.0;
138 }
139 let ticks: f64 = ticks.midi_num_into();
140 time += multiplier * ticks;
141 Duration::from_secs_f64(time)
142}
143
144pub fn get_channel_statistics<D: MIDINum, E: MIDIEventEnum + MIDIDelta<D>, Err>(
149 iter: impl Iterator<Item = Result<E, Err>>,
150) -> Result<ChannelStatistics<D>, Err> {
151 let mut note_on_count = 0;
152 let mut note_off_count = 0;
153 let mut total_event_count = 0;
154 let mut total_length_ticks = D::zero();
155 let mut ticks_since_last_tempo = D::zero();
156
157 let mut tempo_events = Vec::new();
158
159 for event in iter {
160 let event = event?;
161 total_event_count += 1;
162 total_length_ticks += event.delta();
163 ticks_since_last_tempo += event.delta();
164 match event.as_event() {
165 Event::NoteOn(_) => note_on_count += 1,
166 Event::NoteOff(_) => note_off_count += 1,
167 Event::Tempo(t) => {
168 let ev = *t.clone();
169 let tempo_delta = Delta::new(ticks_since_last_tempo, ev);
170 tempo_events.push(tempo_delta);
171 ticks_since_last_tempo = D::zero();
172 }
173 _ => (),
174 }
175 }
176
177 Ok(ChannelStatistics {
178 note_on_count,
179 note_off_count,
180 total_event_count,
181 total_length_ticks,
182 tempo_events: tempo_events.into(),
183 })
184}
185
186pub fn get_channels_array_statistics<
192 D: MIDINum,
193 E: MIDIEventEnum + MIDIDelta<D>,
194 Err: Send,
195 I: Iterator<Item = Result<E, Err>> + Sized + Send,
196>(
197 iters: Vec<I>,
198) -> Result<ChannelGroupStatistics<D>, Err> {
199 let pool = iters
200 .into_par_iter()
201 .map(|iter| get_channel_statistics(iter));
202 let mut result = Vec::new();
203 pool.collect_into_vec(&mut result);
204 let mut channels = result.into_iter().collect_vec_result()?;
205
206 let tempo_vecs: Vec<_> = channels.iter().map(|c| c.tempo_events.clone()).collect();
207 let tempo_iterators: Vec<_> = tempo_vecs
208 .into_iter()
209 .map(|tempos| {
210 tempos
211 .iter()
212 .cloned()
213 .into_ok()
214 .collect::<Vec<_>>()
215 .into_iter()
216 })
217 .collect();
218
219 let merge = tempo_iterators
220 .into_iter()
221 .merge_all()
222 .collect_vec_result()
223 .unwrap();
224
225 let tempo_events: Arc<[Delta<D, TempoEvent>]> = merge.into();
226
227 for c in channels.iter_mut() {
228 c.tempo_events = tempo_events.clone();
229 }
230
231 let mut max_tick_length = D::zero();
232 for c in channels.iter() {
233 if c.total_length_ticks > max_tick_length {
234 max_tick_length = c.total_length_ticks;
235 }
236 }
237
238 let group = ChannelStatistics {
239 note_on_count: channels.iter().map(|c| c.note_on_count).sum(),
240 note_off_count: channels.iter().map(|c| c.note_off_count).sum(),
241 total_event_count: channels.iter().map(|c| c.total_event_count).sum(),
242 total_length_ticks: max_tick_length,
243 tempo_events,
244 };
245
246 Ok(ChannelGroupStatistics { group, channels })
247}