1use std::any::Any;
2use std::collections::BTreeMap;
3
4use crate::arranger::Arranger;
5use crate::model::*;
6use crate::piano_roll::PianoRoll;
7
8impl MusicObject for Note {
9 fn kind(&self) -> &'static str {
10 "Note"
11 }
12
13 fn duration(&self) -> Time {
14 self.duration
15 }
16
17 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
18 out.push(TimedAtom {
19 onset: offset,
20 atom: AtomRef::Note(self.clone()),
21 });
22 }
23
24 fn clone_box(&self) -> Box<dyn MusicObject> {
25 Box::new(self.clone())
26 }
27
28 fn as_any(&self) -> &dyn Any {
29 self
30 }
31}
32
33impl MusicObject for Rest {
34 fn kind(&self) -> &'static str {
35 "Rest"
36 }
37
38 fn duration(&self) -> Time {
39 self.duration
40 }
41
42 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
43 out.push(TimedAtom {
44 onset: offset,
45 atom: AtomRef::Rest(self.clone()),
46 });
47 }
48
49 fn clone_box(&self) -> Box<dyn MusicObject> {
50 Box::new(self.clone())
51 }
52
53 fn as_any(&self) -> &dyn Any {
54 self
55 }
56}
57
58impl MusicObject for Par {
59 fn kind(&self) -> &'static str {
60 "Par"
61 }
62
63 fn duration(&self) -> Time {
64 self.children
65 .iter()
66 .map(|child| child.duration())
67 .max()
68 .unwrap_or_else(|| Time::from_integer(0))
69 }
70
71 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
72 for child in &self.children {
73 child.voices(offset, out);
74 }
75 }
76
77 fn clone_box(&self) -> Box<dyn MusicObject> {
78 Box::new(self.clone())
79 }
80
81 fn as_any(&self) -> &dyn Any {
82 self
83 }
84}
85
86impl MusicObject for Seq {
87 fn kind(&self) -> &'static str {
88 "Seq"
89 }
90
91 fn duration(&self) -> Time {
92 self.children
93 .iter()
94 .fold(Time::from_integer(0), |sum, child| sum + child.duration())
95 }
96
97 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
98 let mut cursor = offset;
99 for child in &self.children {
100 child.voices(cursor, out);
101 cursor += child.duration();
102 }
103 }
104
105 fn clone_box(&self) -> Box<dyn MusicObject> {
106 Box::new(self.clone())
107 }
108
109 fn as_any(&self) -> &dyn Any {
110 self
111 }
112}
113
114impl MusicObject for Chord {
115 fn kind(&self) -> &'static str {
116 "Chord"
117 }
118
119 fn duration(&self) -> Time {
120 self.duration
121 }
122
123 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
124 for pitch in &self.pitches {
125 out.push(TimedAtom {
126 onset: offset,
127 atom: AtomRef::Note(Note {
128 duration: self.duration,
129 pitch: *pitch,
130 velocity: self.velocity,
131 channel: self.channel,
132 articulation: Articulation::Normal,
133 }),
134 });
135 }
136 }
137
138 fn clone_box(&self) -> Box<dyn MusicObject> {
139 Box::new(self.clone())
140 }
141
142 fn as_any(&self) -> &dyn Any {
143 self
144 }
145}
146
147impl MusicObject for Melody {
148 fn kind(&self) -> &'static str {
149 "Melody"
150 }
151
152 fn duration(&self) -> Time {
153 self.total_duration()
154 }
155
156 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
157 let mut cursor = offset;
158 for item in &self.items {
159 match item {
160 MelodyItem::Note(note) => note.voices(cursor, out),
161 MelodyItem::Rest(rest) => rest.voices(cursor, out),
162 }
163 cursor += item.duration();
164 }
165 }
166
167 fn clone_box(&self) -> Box<dyn MusicObject> {
168 Box::new(self.clone())
169 }
170
171 fn as_any(&self) -> &dyn Any {
172 self
173 }
174}
175
176impl MusicObject for Progression {
177 fn kind(&self) -> &'static str {
178 "Progression"
179 }
180
181 fn duration(&self) -> Time {
182 self.chords
183 .iter()
184 .fold(Time::from_integer(0), |sum, chord| sum + chord.duration)
185 }
186
187 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
188 let mut cursor = offset;
189 for chord in &self.chords {
190 chord.voices(cursor, out);
191 cursor += chord.duration;
192 }
193 }
194
195 fn clone_box(&self) -> Box<dyn MusicObject> {
196 Box::new(self.clone())
197 }
198
199 fn as_any(&self) -> &dyn Any {
200 self
201 }
202}
203
204impl MusicObject for Counterpoint {
205 fn kind(&self) -> &'static str {
206 "Counterpoint"
207 }
208
209 fn duration(&self) -> Time {
210 self.voices
211 .iter()
212 .map(Melody::total_duration)
213 .max()
214 .unwrap_or_else(|| Time::from_integer(0))
215 }
216
217 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
218 for voice in &self.voices {
219 voice.voices(offset, out);
220 }
221 }
222
223 fn clone_box(&self) -> Box<dyn MusicObject> {
224 Box::new(self.clone())
225 }
226
227 fn as_any(&self) -> &dyn Any {
228 self
229 }
230}
231
232impl MusicObject for PianoRoll {
233 fn kind(&self) -> &'static str {
234 "PianoRoll"
235 }
236
237 fn duration(&self) -> Time {
238 self.items
239 .iter()
240 .map(|item| item.onset + item.note.duration)
241 .max()
242 .unwrap_or_else(|| Time::from_integer(0))
243 }
244
245 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
246 for item in &self.items {
247 out.push(TimedAtom {
248 onset: offset + item.onset,
249 atom: AtomRef::Note(item.note.clone()),
250 });
251 }
252 }
253
254 fn clone_box(&self) -> Box<dyn MusicObject> {
255 Box::new(self.clone())
256 }
257
258 fn as_any(&self) -> &dyn Any {
259 self
260 }
261}
262
263impl MusicObject for Arranger {
264 fn kind(&self) -> &'static str {
265 "Arranger"
266 }
267
268 fn duration(&self) -> Time {
269 self.rendered_notes()
270 .into_iter()
271 .map(|item| item.onset + item.note.duration)
272 .max()
273 .unwrap_or_else(|| Time::from_integer(0))
274 }
275
276 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
277 for item in self.rendered_notes() {
278 out.push(TimedAtom {
279 onset: offset + item.onset,
280 atom: AtomRef::Note(item.note),
281 });
282 }
283 }
284
285 fn clone_box(&self) -> Box<dyn MusicObject> {
286 Box::new(self.clone())
287 }
288
289 fn as_any(&self) -> &dyn Any {
290 self
291 }
292}
293
294impl MusicObject for MidiTrackObj {
295 fn kind(&self) -> &'static str {
296 "MidiTrackObj"
297 }
298
299 fn duration(&self) -> Time {
300 self.events
301 .iter()
302 .map(|event| tick_time_to_time(event.time))
303 .max()
304 .unwrap_or_else(|| Time::from_integer(0))
305 }
306
307 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
308 emit_midi_track_voices(&self.events, offset, out);
309 }
310
311 fn clone_box(&self) -> Box<dyn MusicObject> {
312 Box::new(self.clone())
313 }
314
315 fn as_any(&self) -> &dyn Any {
316 self
317 }
318}
319
320impl MusicObject for MidiFileObj {
321 fn kind(&self) -> &'static str {
322 "MidiFileObj"
323 }
324
325 fn duration(&self) -> Time {
326 self.file
327 .tracks
328 .iter()
329 .flat_map(|track| track.events.iter())
330 .map(|event| tick_time_to_time(event.time))
331 .max()
332 .unwrap_or_else(|| Time::from_integer(0))
333 }
334
335 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
336 for track in &self.file.tracks {
337 emit_midi_track_voices(&track.events, offset, out);
338 }
339 }
340
341 fn clone_box(&self) -> Box<dyn MusicObject> {
342 Box::new(self.clone())
343 }
344
345 fn as_any(&self) -> &dyn Any {
346 self
347 }
348}
349
350impl MusicObject for Score {
351 fn kind(&self) -> &'static str {
352 "Score"
353 }
354
355 fn duration(&self) -> Time {
356 self.body.duration()
357 }
358
359 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
360 self.body.voices(offset, out);
361 }
362
363 fn clone_box(&self) -> Box<dyn MusicObject> {
364 Box::new(self.clone())
365 }
366
367 fn as_any(&self) -> &dyn Any {
368 self
369 }
370}
371
372impl MusicObject for Music {
373 fn kind(&self) -> &'static str {
374 match self {
375 Self::Note(note) => note.kind(),
376 Self::Rest(rest) => rest.kind(),
377 Self::Par(par) => par.kind(),
378 Self::Seq(seq) => seq.kind(),
379 Self::Chord(chord) => chord.kind(),
380 Self::Melody(melody) => melody.kind(),
381 Self::Progression(progression) => progression.kind(),
382 Self::Counterpoint(counterpoint) => counterpoint.kind(),
383 Self::PianoRoll(roll) => roll.kind(),
384 Self::Arranger(arranger) => arranger.kind(),
385 Self::MidiTrack(track) => track.kind(),
386 Self::MidiFile(file) => file.kind(),
387 }
388 }
389
390 fn duration(&self) -> Time {
391 match self {
392 Self::Note(note) => note.duration(),
393 Self::Rest(rest) => rest.duration(),
394 Self::Par(par) => par.duration(),
395 Self::Seq(seq) => seq.duration(),
396 Self::Chord(chord) => chord.duration(),
397 Self::Melody(melody) => melody.duration(),
398 Self::Progression(progression) => progression.duration(),
399 Self::Counterpoint(counterpoint) => counterpoint.duration(),
400 Self::PianoRoll(roll) => roll.duration(),
401 Self::Arranger(arranger) => arranger.duration(),
402 Self::MidiTrack(track) => track.duration(),
403 Self::MidiFile(file) => file.duration(),
404 }
405 }
406
407 fn voices<'a>(&'a self, offset: Time, out: &mut Vec<TimedAtom<'a>>) {
408 match self {
409 Self::Note(note) => note.voices(offset, out),
410 Self::Rest(rest) => rest.voices(offset, out),
411 Self::Par(par) => par.voices(offset, out),
412 Self::Seq(seq) => seq.voices(offset, out),
413 Self::Chord(chord) => chord.voices(offset, out),
414 Self::Melody(melody) => melody.voices(offset, out),
415 Self::Progression(progression) => progression.voices(offset, out),
416 Self::Counterpoint(counterpoint) => counterpoint.voices(offset, out),
417 Self::PianoRoll(roll) => roll.voices(offset, out),
418 Self::Arranger(arranger) => arranger.voices(offset, out),
419 Self::MidiTrack(track) => track.voices(offset, out),
420 Self::MidiFile(file) => file.voices(offset, out),
421 }
422 }
423
424 fn clone_box(&self) -> Box<dyn MusicObject> {
425 Box::new(self.clone())
426 }
427
428 fn as_any(&self) -> &dyn Any {
429 self
430 }
431}
432
433fn tick_time_to_time(time: TickTime) -> Time {
434 Time::new(time.ticks, i64::from(time.tpq) * 4)
435}
436
437fn emit_midi_track_voices<'a>(events: &[MidiEvent], offset: Time, out: &mut Vec<TimedAtom<'a>>) {
438 let mut active: BTreeMap<(u8, u8), Vec<(Time, u8)>> = BTreeMap::new();
439 let mut sorted = events.to_vec();
440 sorted.sort_by_key(|event| event.time);
441 for event in sorted {
442 match event.payload {
443 MidiPayload::Channel(ChannelMessage::NoteOn { ch, key, vel }) if vel.0 > 0 => {
444 active
445 .entry((ch.0, key.0))
446 .or_default()
447 .push((tick_time_to_time(event.time), vel.0));
448 }
449 MidiPayload::Channel(ChannelMessage::NoteOff { ch, key, .. })
450 | MidiPayload::Channel(ChannelMessage::NoteOn {
451 ch,
452 key,
453 vel: sim_lib_midi_core::U7(0),
454 }) => {
455 if let Some(entries) = active.get_mut(&(ch.0, key.0)) {
456 if let Some((start, velocity)) = entries.pop() {
457 let duration = tick_time_to_time(event.time) - start;
458 out.push(TimedAtom {
459 onset: offset + start,
460 atom: AtomRef::Note(Note {
461 duration,
462 pitch: Pitch::from_midi(key.0),
463 velocity,
464 channel: ch,
465 articulation: Articulation::Normal,
466 }),
467 });
468 }
469 if entries.is_empty() {
470 active.remove(&(ch.0, key.0));
471 }
472 }
473 }
474 _ => {}
475 }
476 }
477}