Skip to main content

sim_lib_music_core/
objects.rs

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}