Skip to main content

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