1pub mod duration;
2pub mod symbols;
3
4use duration::NoteDuration;
5use crate::Midi;
6use crate::parsing::duration::DurationType;
7use crate::parsing::duration::POSSIBLE_NOTE_LENGTHS;
8use crate::parsing::symbols::NoteModifier;
9use crate::parsing::symbols::NoteWrapper;
10use crate::parsing::symbols::TimeSignature;
11use std::collections::VecDeque;
12
13#[derive(Clone)]
15pub struct Track {
16 pub name: String,
18 pub notes: Vec<NoteWrapper>
20}
21
22#[derive(Clone, Copy)]
24struct RawNoteData {
25 key: u8,
26 onset: u32,
27 vel: u8,
28}
29
30pub fn get_ticks_per_beat(header: &midly::Header) -> f32 {
32 let midly::Header { format: _, timing } = header;
33 if let midly::Timing::Metrical(x) = timing {
34 let ticks_per_beat: u16 = (*x).into();
35 return ticks_per_beat as f32;
36 }
37 panic!("Timing format not supported");
38}
39
40pub fn get_bpm(track: &Vec<midly::TrackEvent>) -> u32 {
42 for event in track {
43 if let midly::TrackEventKind::Meta(midly::MetaMessage::Tempo(tempo)) = event.kind {
44 let microseconds_per_beat: u32 = tempo.into();
45 return microseconds_per_beat / 1000000 * 60;
46 }
47 }
48 return 0;
49}
50
51pub fn get_time_signature(track: &Vec<midly::TrackEvent>) -> Vec<TimeSignature> {
53 let mut time_signatures: Vec<TimeSignature> = Vec::new();
54 let mut cur_time: u32 = 0;
55 for event in track {
56 let delta_t: u32 = event.delta.into();
57 cur_time += delta_t;
58 if let midly::TrackEventKind::Meta(message) = event.kind {
59 if let midly::MetaMessage::TimeSignature(numerator, denominator, _, _) = message {
60 time_signatures.push(TimeSignature {
61 beat_count: numerator,
62 beat_type: denominator.into(),
63 time_of_occurance: cur_time,
64 });
65 }
66 }
67 }
68 return time_signatures;
69}
70
71pub fn load_tracks(midi: &mut Midi, smf: &midly::Smf, precision: &DurationType, triplet: bool) {
84 let tmp = midi.clone();
85 for track in &smf.tracks {
86 midi.tracks.push(parse_track(&tmp, track, precision, triplet));
87 }
88}
89
90fn parse_track(
92 midi: &Midi,
93 track: &Vec<midly::TrackEvent>,
94 precision: &DurationType,
95 triplet: bool
96) -> Track {
97 Track {
98 name: get_name(track),
99 notes: get_notes(midi, track, precision, triplet),
100 }
101}
102
103fn get_name(track: &Vec<midly::TrackEvent>) -> String {
105 for event in track {
106 if let midly::TrackEventKind::Meta(midly::MetaMessage::InstrumentName(s)) = event.kind {
107 let raw_string: Vec<u8> = s.to_vec();
108 return String::from_utf8(raw_string).unwrap();
109 }
110 }
111 return String::from("");
112}
113
114fn get_notes(
118 midi: &Midi,
119 track: &Vec<midly::TrackEvent>,
120 precision: &DurationType,
121 triplet: bool
122) -> Vec<NoteWrapper> {
123 let beat_type = midi.time_signatures[0].beat_type;
124 let precision_beat = precision.get_beat_count(beat_type);
125 let divisions = if triplet {
126 4.0 / precision_beat / 2.0 * 1.5
127 } else {
128 1.0 / precision_beat
129 };
130 let quantized_note_data = quantize(midi, track, divisions);
131
132 let mut possible_triplets = VecDeque::new();
133 if triplet {
134 possible_triplets = get_triplets(&quantized_note_data);
135 }
136
137 let mut complete_beat_grid = Vec::new();
138 for (mut beat_grid, _) in quantized_note_data {
139 complete_beat_grid.append(&mut beat_grid);
140 }
141
142 let mut notes = Vec::new();
143 let mut beat_count = 0;
144 let mut i = 0;
145 let mut length = 0;
146 let mut cur_note: &Vec<(u8, u8)> = &Vec::new();
147 while i < complete_beat_grid.len() {
148 if i % divisions as usize == 0 {
149 beat_count += 1;
150 if possible_triplets.len() != 0 && possible_triplets[0] == beat_count {
151 let x = i + divisions as usize;
152 let beat_data = &Vec::from(&complete_beat_grid[i..x]);
153 notes.push(gen_triplet(beat_data, beat_type));
154 possible_triplets.pop_front();
155 i += divisions as usize;
156 length = 0;
157 continue;
158 }
159 }
160 if complete_beat_grid[i].len() != 0 {
161 if length != 0 {
162 let beat_length = length as f32 / divisions;
163 println!("{} / {} = {}", length, divisions, beat_length);
164 notes.push(gen_wrapper(cur_note, beat_length, beat_type));
165 }
166 length = 0;
167 cur_note = &complete_beat_grid[i];
168 }
169 length += 1;
170 i += 1;
171 }
172
173 return notes;
174}
175
176fn get_triplets(quantized_note_data: &Vec<(Vec<Vec<(u8, u8)>>, u8)>) -> VecDeque<u32> {
181 let mut triplets = VecDeque::new();
182 for i in 0..quantized_note_data.len() {
183 if is_possible_triplet(&quantized_note_data[i]) {
184 triplets.push_back(i as u32 + 1);
185 }
186 }
187 return triplets;
188}
189
190fn is_possible_triplet(beat_data: &(Vec<Vec<(u8, u8)>>, u8)) -> bool {
195 let (beat_grid, note_count) = beat_data;
196 if *note_count != 3 {
197 return false;
198 }
199
200 let mut beat_length: [u8; 3]= [0, 0, 0];
201 let mut i = 0;
202 for data_point_index in 0..3 {
203 beat_length[data_point_index] += 1;
204 i +=1;
205 while i < beat_grid.len() && beat_grid[i].len() == 0 {
206 beat_length[data_point_index] += 1;
207 i += 1;
208 }
209 }
210 beat_length.sort();
211
212 return beat_length[2] - beat_length[0] <= 2 && beat_length[2] as usize > beat_grid.len() / 4;
213}
214
215fn gen_triplet(beat_data: &Vec<Vec<(u8, u8)>>, beat_type: u8) -> NoteWrapper {
219 let mut triplet = Vec::new();
220 for div in beat_data {
221 if div.len() > 0 {
222 triplet.push(gen_wrapper(div, 0.5, beat_type));
223 }
224 }
225 return NoteWrapper::ModifiedNote(NoteModifier::Triplet(triplet));
226}
227
228fn gen_wrapper(cur_note: &Vec<(u8, u8)>, beat_length: f32, beat_type: u8) -> NoteWrapper {
235 let mut chord = Vec::new();
236 for note_data in cur_note {
237 let value = note_data.0;
238 let velocity = note_data.1;
239 if value != 255 {
240 chord.push(parse_note_data((value, velocity), beat_length, beat_type));
241 }
242 }
243 if chord.len() == 0 {
244 let duration = DurationType::beat_type_map(beat_length, beat_type);
245 return NoteWrapper::build_note_wrapper(255, duration, 0);
246 } else if chord.len() == 1 {
247 return chord[0].clone();
248 }
249 return NoteWrapper::ModifiedNote(NoteModifier::Chord(chord));
250}
251
252fn parse_note_data((value, velocity): (u8, u8), beat_length: f32, beat_type: u8) -> NoteWrapper {
254 let duration = DurationType::beat_type_map(beat_length, beat_type);
255 if duration.duration == NoteDuration::NaN {
256 return NoteWrapper::ModifiedNote(get_tied_note((value, beat_length, velocity), beat_type));
257 } else {
258 return NoteWrapper::build_note_wrapper(value, duration, velocity);
259 }
260}
261
262fn quantize(
268 midi: &Midi,
269 track: &Vec<midly::TrackEvent>,
270 divisions: f32
271) -> Vec<(Vec<Vec<(u8, u8)>>, u8)> {
272 let mut notes = Vec::new();
273
274 let mut ticks_per_beat = midi.ticks_per_beat;
275 let mut scalar = 1;
276 if midi.ticks_per_beat % 12.0 != 0.0 {
277 scalar = 12;
278 ticks_per_beat *= 12.0;
279 }
280
281 let mut flag = true;
282 let mut raw_note_data = get_raw_note_data(track, ticks_per_beat, scalar);
283 if raw_note_data.len() == 0 {
284 return Vec::new();
285 }
286
287 let mut cur_beat = ticks_per_beat as u32;
288 let mut note = raw_note_data.pop_front().unwrap();
289 while flag {
290 let mut beat_container = vec![Vec::new(); divisions as usize];
291 let mut note_count = 0;
292 while note.onset < cur_beat {
293 let onset = note.onset - (cur_beat - ticks_per_beat as u32);
294 let position = (onset as f32 * (1.0 / ticks_per_beat) * divisions).floor() as usize;
295 beat_container[position].push((note.key, note.vel));
296 note_count += 1;
297 if raw_note_data.is_empty() {
298 flag = false;
299 break;
300 }
301 note = raw_note_data.pop_front().unwrap();
302 }
303 cur_beat += ticks_per_beat as u32;
304 notes.push((beat_container, note_count));
305 }
306
307 if notes[0].0[0].len() == 0 {
308 notes[0].0[0].push((255, 0));
309 notes[0].1 += 1;
310 }
311
312 return notes;
313}
314
315fn get_raw_note_data(
317 track: &Vec<midly::TrackEvent>,
318 ticks_per_beat: f32,
319 scalar: u32
320) -> VecDeque<RawNoteData> {
321 let mut cur_time: u32 = 0;
322 let mut cur_velocity: u8 = 0;
323 let mut note_on_time: u32 = 0;
324 let mut note_off_time: u32 = 0;
325 let mut data: VecDeque<RawNoteData> = VecDeque::new();
326
327 for event in track {
328 let delta_t: u32 = event.delta.into();
329 cur_time += delta_t * scalar;
330
331 if let midly::TrackEventKind::Midi { channel: _, message } = event.kind {
332 if let midly::MidiMessage::NoteOn {key: _, vel } = message {
333 cur_velocity = vel.into();
334 note_on_time = cur_time;
335 if note_on_time - note_off_time >= (ticks_per_beat * 0.125).ceil() as u32 {
336 data.push_back(RawNoteData {
337 key: 255,
338 onset: note_off_time,
339 vel: 0,
340 });
341 }
342 }
343 else if let midly::MidiMessage::NoteOff { key , vel: _ } = message {
344 data.push_back(RawNoteData {
345 key: key.into(),
346 onset: note_on_time,
347 vel: cur_velocity,
348 });
349 note_off_time = cur_time;
350 }
351 }
352 }
353
354 return data;
355}
356
357fn get_tied_note((value, duration, velocity): (u8, f32, u8), beat_type: u8) -> NoteModifier {
358 let mut notes: Vec<NoteWrapper> = Vec::new();
359 let mut remaining_beats: f32 = duration;
360 while remaining_beats > 0.0 {
361 let nested_beat_value = get_nested_beat_value(remaining_beats);
362 let new_duration = DurationType::beat_type_map(nested_beat_value, beat_type);
363 remaining_beats -= nested_beat_value;
364 notes.push(NoteWrapper::build_note_wrapper(value, new_duration, velocity));
365 }
366 return NoteModifier::TiedNote(notes);
367}
368
369fn get_nested_beat_value(beats: f32) -> f32 {
371 for i in 1..POSSIBLE_NOTE_LENGTHS.len() {
372 if POSSIBLE_NOTE_LENGTHS[i] > beats {
373 return POSSIBLE_NOTE_LENGTHS[i - 1];
374 }
375 }
376 return POSSIBLE_NOTE_LENGTHS[POSSIBLE_NOTE_LENGTHS.len() - 1];
377}