1use 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#[derive(Clone, Debug, PartialEq)]
37enum Kind {
38 NoteOn,
39 NoteOff,
40 ProgramChange,
41 Channel,
43 Meta(u8),
45 SysEx,
46 Nothing,
48}
49
50#[derive(Clone, Debug)]
52struct Event {
53 kind: Kind,
54 channel: u8,
56 first: u8,
58 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
80fn 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
91fn 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
103fn 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 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
180type Track = Vec<(u64, Event)>;
182
183fn 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 None => data = after,
199 }
200 }
201 events
202}
203
204fn 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
244struct Timed<'a> {
247 on: u64,
248 off: u64,
249 event: &'a Event,
250}
251
252fn 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
275fn 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
283fn 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 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
326fn 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
376fn 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
406fn 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
420fn 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
429fn 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 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 let last = ¬es[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 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 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
593pub 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 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 fn file(events: &[(u8, u8, u8, u8)]) -> Vec<u8> {
642 let mut track: Vec<u8> = vec![
643 0, 0xFF, 0x51, 3, 0x07, 0xA1, 0x20, 0, 0xFF, 0x58, 4, 3, 2, 24, 8, ];
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 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 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 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}