Skip to main content

music21_rs/midi/
score.rs

1//! A MIDI file read as a score: music21's `midi` reader and
2//! `midi.translate.midiFileToStream`.
3//!
4//! Every track holding notes becomes a part; the tracks holding none are
5//! read together as the conductor, whose meters, keys and tempos each part
6//! after them takes a copy of. A part's notes are gathered into chords where
7//! they start together and end together, moved onto the nearest sixteenth or
8//! triplet eighth, cut into measures, put into voices where they overlap,
9//! tied across barlines and filled out with rests.
10
11use std::collections::HashMap;
12
13use crate::chord::Chord;
14use crate::defaults::{FloatType, IntegerType};
15use crate::duration::Duration;
16use crate::error::{Error, Result};
17use crate::instrument::{Instrument, SearchLanguage};
18use crate::key::KeySignature;
19use crate::makenotation::{
20    QUANTIZATION_DIVISORS, make_measures_by, make_rests, make_ties, make_voices, op_frac, quantize,
21    sorted_events,
22};
23use crate::meter::TimeSignature;
24use crate::note::Note;
25use crate::percussion::{PercussionChord, PercussionNote, Unpitched};
26use crate::pitch::Pitch;
27use crate::stream::{Stream, StreamElement, StreamEvent, StreamKind};
28use crate::tempo::MetronomeMark;
29use crate::volume::Volume;
30
31fn midi_error(message: impl Into<String>) -> Error {
32    Error::Midi(message.into())
33}
34
35/// What an event is, as far as a score cares.
36#[derive(Clone, Debug, PartialEq)]
37enum Kind {
38    NoteOn,
39    NoteOff,
40    ProgramChange,
41    /// Any other channel message.
42    Channel,
43    /// A meta event, with its type byte.
44    Meta(u8),
45    SysEx,
46    /// What is left when the data ran out mid-event.
47    Nothing,
48}
49
50/// One event of a track: music21's `MidiEvent`.
51#[derive(Clone, Debug)]
52struct Event {
53    kind: Kind,
54    /// Counted from one.
55    channel: u8,
56    /// The pitch of a note, or the program of a program change.
57    first: u8,
58    /// The velocity of a note.
59    second: u8,
60    data: Vec<u8>,
61}
62
63impl Event {
64    fn is_note_on(&self) -> bool {
65        self.kind == Kind::NoteOn && self.second != 0
66    }
67
68    fn is_note_off(&self) -> bool {
69        self.kind == Kind::NoteOff || (self.kind == Kind::NoteOn && self.second == 0)
70    }
71}
72
73const SEQUENCE_TRACK_NAME: u8 = 0x03;
74const INSTRUMENT_NAME: u8 = 0x04;
75const LYRIC: u8 = 0x05;
76const SET_TEMPO: u8 = 0x51;
77const TIME_SIGNATURE: u8 = 0x58;
78const KEY_SIGNATURE: u8 = 0x59;
79
80/// A number of so many bytes, high byte first, and what follows it.
81fn number(bytes: &[u8], length: usize) -> Result<(u64, &[u8])> {
82    if bytes.len() < length {
83        return Err(midi_error("the MIDI data ends inside a number"));
84    }
85    let value = bytes[..length]
86        .iter()
87        .fold(0_u64, |total, byte| (total << 8) | u64::from(*byte));
88    Ok((value, &bytes[length..]))
89}
90
91/// A number written seven bits to a byte, and what follows it.
92fn variable_length(bytes: &[u8]) -> (u64, &[u8]) {
93    let mut value: u64 = 0;
94    for (index, byte) in bytes.iter().enumerate() {
95        value = (value << 7) | u64::from(byte & 0x7F);
96        if byte & 0x80 == 0 {
97            return (value, &bytes[index + 1..]);
98        }
99    }
100    (value, &[])
101}
102
103/// One event read off the front of a track's data: music21's
104/// `MidiEvent.read`. `status` is the running status, carried from the event
105/// before. Nothing is answered for a byte that starts no event music21
106/// knows.
107fn read_event<'a>(bytes: &'a [u8], status: &mut Option<u8>) -> Option<(Event, &'a [u8])> {
108    let mut event = Event {
109        kind: Kind::Nothing,
110        channel: 0,
111        first: 0,
112        second: 0,
113        data: Vec::new(),
114    };
115    if bytes.len() < 2 {
116        return Some((event, &[]));
117    }
118    // A data byte where a status byte should be runs on under the last
119    // status.
120    let (first, rest): (u8, &[u8]) = if bytes[0] < 0x80 {
121        (status.unwrap_or(0x90), bytes)
122    } else {
123        if bytes[0] != 0xFF {
124            *status = Some(bytes[0]);
125        }
126        (bytes[0], &bytes[1..])
127    };
128    let message = first & 0xF0;
129    if (0x80..=0xE0).contains(&message) {
130        event.channel = (first & 0x0F) + 1;
131        let one = *rest.first()?;
132        let two = rest.get(1).copied().unwrap_or(0);
133        return match message {
134            0xC0 | 0xD0 => {
135                if one > 127 {
136                    return None;
137                }
138                event.kind = if message == 0xC0 {
139                    Kind::ProgramChange
140                } else {
141                    Kind::Channel
142                };
143                event.first = one;
144                Some((event, &rest[1..]))
145            }
146            0x80 | 0x90 => {
147                event.kind = if message == 0x90 {
148                    Kind::NoteOn
149                } else {
150                    Kind::NoteOff
151                };
152                event.first = one;
153                event.second = two;
154                Some((event, rest.get(2..).unwrap_or(&[])))
155            }
156            _ => {
157                event.kind = Kind::Channel;
158                Some((event, rest.get(2..).unwrap_or(&[])))
159            }
160        };
161    }
162    if first == 0xF0 || first == 0xF7 {
163        let (length, after) = variable_length(rest);
164        let length = (length as usize).min(after.len());
165        event.kind = Kind::SysEx;
166        event.data = after[..length].to_vec();
167        return Some((event, &after[length..]));
168    }
169    if first == 0xFF {
170        let kind = *rest.first()?;
171        let (length, after) = variable_length(&rest[1..]);
172        let length = (length as usize).min(after.len());
173        event.kind = Kind::Meta(kind);
174        event.data = after[..length].to_vec();
175        return Some((event, &after[length..]));
176    }
177    None
178}
179
180/// A track: its events, each with the tick it happens at.
181type Track = Vec<(u64, Event)>;
182
183/// A track's events, each with the tick it happens at: music21's
184/// `processDataToEvents` and `getTimeForEvents`.
185fn track_events(mut data: &[u8]) -> Track {
186    let mut events = Vec::new();
187    let mut time: u64 = 0;
188    let mut status: Option<u8> = None;
189    while !data.is_empty() {
190        let (delta, after) = variable_length(data);
191        match read_event(after, &mut status) {
192            Some((event, rest)) => {
193                time += delta;
194                events.push((time, event));
195                data = rest;
196            }
197            // What starts no event is passed over, its time with it.
198            None => data = after,
199        }
200    }
201    events
202}
203
204/// A file's tracks and how many ticks a quarter takes: music21's
205/// `MidiFile.readstr`.
206fn read_file(bytes: &[u8]) -> Result<(Vec<Track>, FloatType)> {
207    if bytes.get(..4) != Some(b"MThd") {
208        return Err(midi_error("badly formatted midi bytes: no MThd header"));
209    }
210    let (length, rest) = number(&bytes[4..], 4)?;
211    if length != 6 {
212        return Err(midi_error("badly formatted midi bytes"));
213    }
214    let (format, rest) = number(rest, 2)?;
215    if format > 1 {
216        return Err(midi_error(format!(
217            "cannot handle midi file format: {format}"
218        )));
219    }
220    let (count, rest) = number(rest, 2)?;
221    let (division, mut rest) = number(rest, 2)?;
222    if division & 0x8000 != 0 {
223        return Err(midi_error(
224            "a file timed in frames a second, not ticks a quarter, is not read",
225        ));
226    }
227    let ticks = (division & 0x7FFF) as FloatType;
228    if ticks == 0.0 {
229        return Err(midi_error("a quarter of no ticks"));
230    }
231    let mut tracks = Vec::new();
232    for _ in 0..count {
233        if rest.get(..4) != Some(b"MTrk") {
234            return Err(midi_error("badly formed midi string: missing leading MTrk"));
235        }
236        let (length, after) = number(&rest[4..], 4)?;
237        let length = (length as usize).min(after.len());
238        tracks.push(track_events(&after[..length]));
239        rest = &after[length..];
240    }
241    Ok((tracks, ticks))
242}
243
244/// A note as the file times it: when it starts, when it stops, and the
245/// event that started it.
246struct Timed<'a> {
247    on: u64,
248    off: u64,
249    event: &'a Event,
250}
251
252/// music21's `getNotesFromEvents`: each note-on with the note-off after it.
253/// Read backwards, so a note-on takes the nearest note-off of its pitch and
254/// channel after it, and one with none after it is dropped.
255fn notes_of(events: &[(u64, Event)]) -> Vec<Timed<'_>> {
256    let mut waiting: HashMap<(u8, u8), u64> = HashMap::new();
257    let mut notes = Vec::new();
258    for (time, event) in events.iter().rev() {
259        if event.is_note_off() {
260            waiting.insert((event.first, event.channel), *time);
261        } else if event.is_note_on()
262            && let Some(off) = waiting.get(&(event.first, event.channel))
263        {
264            notes.push(Timed {
265                on: *time,
266                off: *off,
267                event,
268            });
269        }
270    }
271    notes.reverse();
272    notes
273}
274
275/// The instrument a percussion key plays: music21's `PercussionMapper`,
276/// whose exception for a key it names no instrument for its reader answers
277/// with a bare unpitched percussion instrument.
278fn percussion_instrument(pitch: u8) -> Instrument {
279    crate::instrument::for_percussion_key(pitch)
280        .unwrap_or_else(|_| Instrument::of_kind("UnpitchedPercussion").unwrap_or_default())
281}
282
283/// music21's `midiEventToInstrument`.
284fn instrument_of(event: &Event) -> Instrument {
285    let mut decoded = String::new();
286    let mut instrument = match event.kind {
287        Kind::ProgramChange if event.channel == 10 => {
288            let mut made = Instrument::of_kind("UnpitchedPercussion").unwrap_or_default();
289            made.set_midi_program(Some(event.first));
290            made
291        }
292        Kind::ProgramChange => {
293            Instrument::from_midi_program(event.first).unwrap_or_else(|_| Instrument::new())
294        }
295        _ => match std::str::from_utf8(&event.data) {
296            Ok(text) => {
297                decoded = text.split('\0').next().unwrap_or("").trim().to_string();
298                Instrument::from_name(&decoded, SearchLanguage::All)
299                    .unwrap_or_else(|_| Instrument::new())
300            }
301            Err(_) => Instrument::new(),
302        },
303    };
304    // A meta event is on no channel, which music21 counts as the one before
305    // the first.
306    instrument.set_midi_channel(event.channel.checked_sub(1));
307    if !decoded.is_empty() {
308        let lower = decoded.to_lowercase();
309        let numbered = |prefix: &str| {
310            let rest = lower.replace(prefix, "");
311            !rest.is_empty() && rest.chars().all(|c| c.is_ascii_digit())
312        };
313        if lower == "instrument" || lower == "inst" || numbered("instrument ") || numbered("inst ")
314        {
315            return instrument;
316        }
317        match event.kind {
318            Kind::Meta(SEQUENCE_TRACK_NAME) => instrument.set_part_name(Some(decoded)),
319            Kind::Meta(INSTRUMENT_NAME) => instrument.set_name(Some(decoded)),
320            _ => {}
321        }
322    }
323    instrument
324}
325
326/// music21's `getMetaEvents`: the meters, keys, tempos and instruments a
327/// track states, each with its tick.
328fn meta_of(events: &[(u64, Event)]) -> Result<Vec<(u64, StreamElement)>> {
329    let mut found = Vec::new();
330    let mut last_program: Option<u8> = None;
331    for (time, event) in events {
332        let element: Option<StreamElement> = match event.kind {
333            Kind::Meta(TIME_SIGNATURE) if event.data.len() >= 2 => {
334                let denominator = 2_u32
335                    .checked_pow(u32::from(event.data[1]))
336                    .ok_or_else(|| midi_error("a time signature over too large a value"))?;
337                Some(TimeSignature::new(u32::from(event.data[0]), denominator)?.into())
338            }
339            Kind::Meta(KEY_SIGNATURE) if event.data.len() >= 2 => {
340                let sharps = if event.data[0] > 12 {
341                    IntegerType::from(event.data[0]) - 256
342                } else {
343                    IntegerType::from(event.data[0])
344                };
345                let mode = if event.data[1] == 1 { "minor" } else { "major" };
346                Some(StreamElement::Key(KeySignature::new(sharps).as_key(mode)))
347            }
348            Kind::Meta(SET_TEMPO) if event.data.len() >= 3 => {
349                let (micros, _) = number(&event.data, 3)?;
350                if micros == 0 {
351                    return Err(midi_error("a tempo of no time to the quarter"));
352                }
353                let bpm = (60_000_000.0 / micros as FloatType * 100.0).round_ties_even() / 100.0;
354                Some(MetronomeMark::new(bpm).into())
355            }
356            Kind::Meta(INSTRUMENT_NAME | SEQUENCE_TRACK_NAME) => {
357                let mut instrument = instrument_of(event);
358                if let Some(program) = last_program {
359                    instrument.set_midi_program(Some(program));
360                }
361                Some(instrument.into())
362            }
363            Kind::ProgramChange => {
364                last_program = Some(event.first);
365                Some(instrument_of(event).into())
366            }
367            _ => None,
368        };
369        if let Some(element) = element {
370            found.push((*time, element));
371        }
372    }
373    Ok(found)
374}
375
376/// music21's `instrument.deduplicate` over the events of one part: where
377/// every instrument standing at one offset is of one kind they are made one,
378/// the first, and a generic one among others of a kind goes.
379fn deduplicate(events: &mut Vec<StreamEvent>) {
380    let places: Vec<usize> = (0..events.len())
381        .filter(|index| matches!(events[*index].element(), StreamElement::Instrument(_)))
382        .collect();
383    let held: Vec<(FloatType, &Instrument)> = places
384        .iter()
385        .filter_map(|index| match events[*index].element() {
386            StreamElement::Instrument(instrument) => {
387                Some((events[*index].offset(), instrument.as_ref()))
388            }
389            _ => None,
390        })
391        .collect();
392    let settled = crate::instrument::settle_by_offset(&held);
393    for (place, becomes) in places.into_iter().zip(settled).rev() {
394        match becomes {
395            None => {}
396            Some(Some(named)) => {
397                events[place] = StreamEvent::new(events[place].offset(), named);
398            }
399            Some(None) => {
400                events.remove(place);
401            }
402        }
403    }
404}
405
406/// The length so many ticks last, or a grace note's where they are none.
407fn duration_of(ticks: u64, per_quarter: FloatType) -> Result<Duration> {
408    if ticks == 0 {
409        return Ok(Duration::quarter().grace_duration());
410    }
411    Duration::new(op_frac(ticks as FloatType / per_quarter))
412}
413
414fn volume_of(velocity: u8) -> Volume {
415    let mut volume = Volume::from_velocity(IntegerType::from(velocity));
416    volume.set_velocity_is_relative(false);
417    volume
418}
419
420/// A stroke of the instrument a percussion key plays.
421fn stroke_of(pitch: u8) -> Unpitched {
422    let mut stroke = Unpitched::new();
423    stroke
424        .written_mut()
425        .set_stored_instrument(Some(percussion_instrument(pitch)));
426    stroke
427}
428
429/// One track as a part, or as more of the conductor where it has no notes:
430/// music21's `midiTrackToStream`. The answer is whether the track had notes.
431fn track_to_part(
432    events: &[(u64, Event)],
433    per_quarter: FloatType,
434    conductor: &[StreamEvent],
435    is_first: bool,
436) -> Result<(Stream, bool)> {
437    let notes = notes_of(events);
438    let mut lyrics: HashMap<u64, String> = HashMap::new();
439    for (time, event) in events {
440        if event.kind == Kind::Meta(LYRIC)
441            && let Ok(text) = std::str::from_utf8(&event.data)
442        {
443            lyrics.insert(*time, text.to_string());
444        }
445    }
446
447    let mut held: Vec<StreamEvent> = Vec::new();
448    for (tick, element) in meta_of(events)? {
449        held.push(StreamEvent::new(
450            op_frac(tick as FloatType / per_quarter),
451            element,
452        ));
453    }
454    deduplicate(&mut held);
455
456    // Notes starting together and ending together are one chord; ones that
457    // start together and end apart need voices.
458    let tolerance =
459        per_quarter / FloatType::from(QUANTIZATION_DIVISORS.into_iter().max().unwrap_or(4));
460    let mut gathered = vec![false; notes.len()];
461    let mut voices_required = false;
462    for index in 0..notes.len() {
463        if gathered[index] {
464            continue;
465        }
466        let start = notes[index].on;
467        let stop = notes[index].off;
468        let mut members = vec![index];
469        for other in index + 1..notes.len() {
470            if (notes[other].on as FloatType - start as FloatType).abs() >= tolerance {
471                break;
472            }
473            if (notes[other].off as FloatType - stop as FloatType).abs() > tolerance {
474                voices_required = true;
475                continue;
476            }
477            members.push(other);
478            gathered[other] = true;
479        }
480        let lyric = lyrics.get(&start);
481        let element: StreamElement = if members.len() > 1 {
482            // The chord is as long as the last note gathered.
483            let last = &notes[members[members.len() - 1]];
484            let duration = duration_of(last.off - last.on, per_quarter)?;
485            let percussion = members
486                .iter()
487                .any(|member| notes[*member].event.channel == 10);
488            if percussion {
489                let strokes: Vec<PercussionNote> = members
490                    .iter()
491                    .map(|member| PercussionNote::Unpitched(stroke_of(notes[*member].event.first)))
492                    .collect();
493                let mut chord = PercussionChord::new(strokes)?.with_duration(duration);
494                let volumes: Vec<Volume> = members
495                    .iter()
496                    .map(|member| volume_of(notes[*member].event.second))
497                    .collect();
498                chord.written_mut().set_volumes(&volumes)?;
499                chord.into()
500            } else {
501                let mut pitched = Vec::new();
502                for member in &members {
503                    let event = notes[*member].event;
504                    let mut note =
505                        Note::from_pitch(Pitch::from_midi(IntegerType::from(event.first))?);
506                    note.set_volume(Some(volume_of(event.second)));
507                    pitched.push(note);
508                }
509                let mut chord = Chord::new(pitched)?.with_duration(duration);
510                // A chord's lyrics are kept on its first note.
511                if let (Some(lyric), Some(singer)) = (lyric, chord.notes_mut().first_mut()) {
512                    singer.set_lyric(Some(lyric))?;
513                }
514                chord.into()
515            }
516        } else {
517            let event = notes[index].event;
518            let duration = duration_of(stop - start, per_quarter)?;
519            if event.channel == 10 {
520                let mut stroke = stroke_of(event.first).with_duration(duration);
521                stroke
522                    .written_mut()
523                    .set_volume(Some(volume_of(event.second)));
524                if let Some(lyric) = lyric {
525                    stroke.written_mut().set_lyric(Some(lyric))?;
526                }
527                stroke.into()
528            } else {
529                let mut note = Note::from_pitch(Pitch::from_midi(IntegerType::from(event.first))?)
530                    .with_duration(duration);
531                note.set_volume(Some(volume_of(event.second)));
532                if let Some(lyric) = lyric {
533                    note.set_lyric(Some(lyric))?;
534                }
535                note.into()
536            }
537        };
538        held.push(StreamEvent::new(
539            op_frac(start as FloatType / per_quarter),
540            element,
541        ));
542    }
543
544    let mut part = Stream::with_kind(StreamKind::Part).with_events(sorted_events(held));
545    quantize(&mut part, &QUANTIZATION_DIVISORS)?;
546    if notes.is_empty() {
547        return Ok((part, false));
548    }
549
550    // The conductor's meters, keys and tempos, a copy for each part; only
551    // the first part shows the tempos.
552    let mut events = part.events().to_vec();
553    let mut meters: Vec<(FloatType, TimeSignature)> = Vec::new();
554    for event in conductor {
555        match event.element() {
556            StreamElement::TimeSignature(meter) => {
557                meters.push((event.offset(), meter.clone()));
558                events.push(event.clone());
559            }
560            StreamElement::Key(_) | StreamElement::KeySignature(_) => events.push(event.clone()),
561            StreamElement::MetronomeMark(mark) => {
562                let mut mark = mark.clone();
563                if !is_first {
564                    mark.set_number_implicit(true);
565                }
566                events.push(StreamEvent::new(event.offset(), mark));
567            }
568            _ => {}
569        }
570    }
571    if !meters.is_empty() && !meters.iter().any(|(offset, _)| *offset == 0.0) {
572        meters.push((0.0, TimeSignature::new(4, 4)?));
573    }
574    let part = part.with_events(sorted_events(events));
575
576    let mut part = make_measures_by(&part, &meters)?;
577    if voices_required {
578        let mut events = part.events().to_vec();
579        for event in &mut events {
580            if let StreamElement::Stream(measure) = event.element_mut()
581                && measure.kind() == StreamKind::Measure
582            {
583                make_voices(measure);
584            }
585        }
586        part = part.with_events(events);
587    }
588    make_ties(&mut part)?;
589    make_rests(&mut part)?;
590    Ok((part, true))
591}
592
593/// Reads a standard MIDI file into a score: music21's
594/// `converter.parse` of one.
595///
596/// Every track with notes is a part. Notes are moved onto the nearest
597/// sixteenth or triplet eighth, gathered into chords and voices, cut into
598/// measures by the meters the file states (`4/4` where it states none),
599/// tied across barlines and filled out with rests. Channel 10 is read as
600/// unpitched percussion, each key the instrument General MIDI gives it. A
601/// file timed in frames a second is refused, as is a format 2 file.
602///
603/// The bytes are the file's own; the library opens no file.
604pub fn from_midi(bytes: &[u8]) -> Result<Stream> {
605    let (tracks, per_quarter) = read_file(bytes)?;
606    if tracks.is_empty() {
607        return Err(midi_error("no tracks are defined in this MIDI file."));
608    }
609    let mut conductor: Vec<StreamEvent> = Vec::new();
610    let mut parts: Vec<StreamEvent> = Vec::new();
611    let mut seen_notes = false;
612    for track in &tracks {
613        let has_notes = track.iter().any(|(_, event)| event.is_note_on());
614        if has_notes {
615            let is_first = !seen_notes;
616            seen_notes = true;
617            let (part, _) = track_to_part(track, per_quarter, &conductor, is_first)?;
618            parts.push(StreamEvent::new(0.0, part));
619        } else {
620            // A track with no notes adds to the conductor, which is
621            // quantized again as a whole each time.
622            let (more, _) = track_to_part(track, per_quarter, &[], false)?;
623            conductor.extend(more.events().iter().cloned());
624            let mut all = Stream::new().with_events(sorted_events(conductor));
625            let mut events = all.events().to_vec();
626            deduplicate(&mut events);
627            all = all.with_events(events);
628            quantize(&mut all, &QUANTIZATION_DIVISORS)?;
629            conductor = all.events().to_vec();
630        }
631    }
632    Ok(Stream::with_kind(StreamKind::Score).with_events(parts))
633}
634
635#[cfg(test)]
636mod tests {
637    use super::*;
638
639    /// A one-track file: a tempo, a meter, then these notes as
640    /// (delta, status, key, velocity).
641    fn file(events: &[(u8, u8, u8, u8)]) -> Vec<u8> {
642        let mut track: Vec<u8> = vec![
643            0, 0xFF, 0x51, 3, 0x07, 0xA1, 0x20, // 120 to the minute
644            0, 0xFF, 0x58, 4, 3, 2, 24, 8, // 3/4
645        ];
646        for (delta, status, key, velocity) in events {
647            track.extend([*delta, *status, *key, *velocity]);
648        }
649        track.extend([0, 0xFF, 0x2F, 0]);
650        let mut bytes = b"MThd\0\0\0\x06\0\0\0\x01\0\x60MTrk".to_vec();
651        bytes.extend((track.len() as u32).to_be_bytes());
652        bytes.extend(track);
653        bytes
654    }
655
656    #[test]
657    fn a_track_is_a_part_of_measures() {
658        // Four quarters in 3/4, 96 ticks each: a bar and a bar filled out
659        // with a rest.
660        let mut events = Vec::new();
661        for key in [60, 62, 64, 65] {
662            events.push((0, 0x90, key, 80));
663            events.push((96, 0x80, key, 0));
664        }
665        let score = from_midi(&file(&events)).unwrap();
666        let part = score.parts()[0];
667        let measures = part.measures();
668        assert_eq!(measures.len(), 2);
669        assert_eq!(measures[0].pitches().len(), 3);
670        let last: Vec<FloatType> = measures[1]
671            .events()
672            .iter()
673            .filter(|event| matches!(event.element(), StreamElement::Rest(_)))
674            .map(|event| event.element().quarter_length())
675            .collect();
676        assert_eq!(last, [2.0]);
677    }
678
679    #[test]
680    fn notes_together_are_a_chord_and_a_long_note_is_tied() {
681        // A triad for a beat, then one note for a whole 3/4 bar and a beat.
682        let events = [
683            (0, 0x90, 60, 80),
684            (0, 0x90, 64, 80),
685            (0, 0x90, 67, 80),
686            (96, 0x80, 60, 0),
687            (0, 0x80, 64, 0),
688            (0, 0x80, 67, 0),
689            (0, 0x90, 72, 80),
690            (127, 0x80, 72, 0),
691        ];
692        let mut bytes = file(&events[..7]);
693        // The last note lasts 288 ticks, which takes two bytes to say.
694        let end = bytes.len() - 4;
695        bytes.splice(end..end, [0x82, 0x20, 0x80, 72, 0]);
696        let length = (bytes.len() - 22) as u32;
697        bytes[18..22].copy_from_slice(&length.to_be_bytes());
698        let score = from_midi(&bytes).unwrap();
699        let part = score.parts()[0];
700        let measures = part.measures();
701        assert!(matches!(
702            measures[0]
703                .events()
704                .iter()
705                .find(|event| event.element().is_note_or_chord())
706                .map(StreamEvent::element),
707            Some(StreamElement::Chord(_))
708        ));
709        let ties: Vec<_> = part
710            .notes()
711            .into_iter()
712            .filter_map(|(_, element)| match element {
713                StreamElement::Note(note) => note.tie().map(|tie| tie.tie_type()),
714                _ => None,
715            })
716            .collect();
717        assert_eq!(
718            ties,
719            [
720                crate::notation::TieType::Start,
721                crate::notation::TieType::Stop
722            ]
723        );
724    }
725
726    #[test]
727    fn what_is_no_midi_file_is_refused() {
728        assert!(from_midi(b"RIFF").is_err());
729    }
730}