use std::string::FromUtf8Error;
use event::{IteratorWrapper, MidiEvent, UnsupportedStatusCode};
use meta::MetaEvent;
use sysex::SysexEvent;
use thiserror::Error;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub mod event;
pub mod meta;
pub mod sysex;
#[derive(Error, Debug, Clone, PartialEq)]
pub enum TrackError {
#[error("Reached end of line at end of parsing")]
EOF,
#[error("Reached end of chunk before done parsing")]
OutOfSpace,
#[error("Invalid Track Format")]
InvalidFormat,
#[error("Invalid Status Code for MIDI Channel Event {0}")]
UnsupportedStatusCode(#[from] UnsupportedStatusCode),
#[error("Meta Event data is in an invalid format")]
InvalidMetaEventData,
#[error("Invalid SysEx Message Start")]
InvalidSysExMessage,
#[error("Missing end of System Exclusive Message 0xF7 byte")]
MissingEndOfExclusive,
#[error("Failed to parse utf-8 encoded string in the meta track event")]
UtfParseError(#[from] FromUtf8Error),
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TrackChunk {
mtrk_events: Vec<MTrkEvent>,
}
impl TryFrom<Vec<u8>> for TrackChunk {
type Error = TrackError;
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
let mut value = value.into_iter();
let mut mtrk_events = vec![];
loop {
match MTrkEvent::try_from(IteratorWrapper(&mut value)) {
Ok(new_track) => mtrk_events.push(new_track),
Err(TrackError::EOF) => break,
Err(e) => return Err(e),
}
}
Ok(Self { mtrk_events })
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MTrkEvent {
delta_time: u32,
event: Event,
}
impl<ITER> TryFrom<IteratorWrapper<&mut ITER>> for MTrkEvent
where
ITER: Iterator<Item = u8>,
{
type Error = TrackError;
fn try_from(value: IteratorWrapper<&mut ITER>) -> Result<Self, Self::Error> {
let value = value.0;
if let Some(dt) = MTrkEvent::try_get_delta_time(value) {
Ok(MTrkEvent {
delta_time: dt,
event: Event::try_from(IteratorWrapper(value))?,
})
} else {
Err(TrackError::EOF)
}
}
}
impl MTrkEvent {
pub fn try_get_delta_time<ITER: Iterator<Item = u8>>(iter: &mut ITER) -> Option<u32> {
let mut time_bytes = vec![];
for byte in iter.by_ref() {
let msb_one = MTrkEvent::msb_is_one(byte);
time_bytes.push(byte);
if !msb_one {
break;
}
}
const MASK: u8 = 0x7F;
if time_bytes.is_empty() {
return None;
}
let mut result: u32 = 0;
for byte in time_bytes {
result <<= 7;
result |= (byte & MASK) as u32;
}
Some(result)
}
fn msb_is_one(byte: u8) -> bool {
byte >> 7 == 1
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Event {
MidiEvent(MidiEvent),
SysexEvent(SysexEvent),
MetaEvent(MetaEvent),
}
impl<ITER> TryFrom<IteratorWrapper<&mut ITER>> for Event
where
ITER: Iterator<Item = u8>,
{
type Error = TrackError;
fn try_from(value: IteratorWrapper<&mut ITER>) -> Result<Self, Self::Error> {
let mut peek = value.0.peekable();
let prefix = peek.peek().ok_or(TrackError::OutOfSpace)?;
match prefix {
status if (0x80..=0xEF).contains(status) => Ok(Event::MidiEvent(MidiEvent::try_from(
IteratorWrapper(&mut peek),
)?)),
system if (0xF0..0xFF).contains(system) => Ok(Event::SysexEvent(SysexEvent::try_from(
IteratorWrapper(&mut peek),
)?)),
0xFF => Ok(Event::MetaEvent(MetaEvent::try_from(IteratorWrapper(
&mut peek,
))?)),
_ => Err(TrackError::InvalidFormat),
}
}
}
#[cfg(test)]
mod tests {
use super::MTrkEvent;
#[test]
fn delta_time_parsed() {
let bytes = vec![0x81, 0x40];
let mut bytes = bytes.into_iter();
let result = MTrkEvent::try_get_delta_time(&mut bytes);
assert_eq!(result, Some(192))
}
}