1use 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#[derive(Clone, Debug, PartialEq)]
38enum Kind {
39 NoteOn,
40 NoteOff,
41 ProgramChange,
42 Channel,
44 Meta(u8),
46 SysEx,
47 Nothing,
49}
50
51#[derive(Clone, Debug)]
53struct Event {
54 kind: Kind,
55 channel: u8,
57 first: u8,
59 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
81fn 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
92fn 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
104fn read_event<'a>(bytes: &'a [u8], status: &mut Option<u8>) -> Option<(Event, &'a [u8])> {
109 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 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
183type Track = Vec<(u64, Event)>;
185
186fn 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 time = time.saturating_add(delta);
199 events.push((time, event));
200 data = rest;
201 }
202 None => data = after,
204 }
205 }
206 events
207}
208
209fn 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
253struct Timed<'a> {
256 on: u64,
257 off: u64,
258 event: &'a Event,
259}
260
261fn 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
284fn 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
299fn 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 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
341fn 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
392fn 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
422fn 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
436fn 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
445fn 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 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 let last = ¬es[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 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 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
612pub 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 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 fn file(events: &[(u8, u8, u8, u8)]) -> Vec<u8> {
663 let mut track: Vec<u8> = vec![
664 0, 0xFF, 0x51, 3, 0x07, 0xA1, 0x20, 0, 0xFF, 0x58, 4, 3, 2, 24, 8, ];
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 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 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 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 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 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 #[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 #[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 #[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}