use crate::byte_iter::ByteIter;
use crate::core::vlq::Vlq;
use crate::core::Message;
use crate::error::LibResult;
use crate::file::{MetaEvent, SysexEvent};
use crate::scribe::Scribe;
use log::trace;
use snafu::ResultExt;
use std::io::{Read, Write};
const FILE_META_EVENT: u8 = 0b1111_1111;
const FILE_SYSEX_F0: u8 = 0b1111_0000;
const FILE_SYSEX_F7: u8 = 0b1111_0111;
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub enum Event {
Midi(Message),
Sysex(SysexEvent),
Meta(MetaEvent),
}
impl Default for Event {
fn default() -> Self {
Event::Midi(Message::default())
}
}
impl Event {
fn parse<R: Read>(iter: &mut ByteIter<R>) -> LibResult<Self> {
let status_byte = iter.peek_or_die().context(io!())?;
match status_byte {
FILE_SYSEX_F7 | FILE_SYSEX_F0 => {
Ok(Event::Sysex(SysexEvent::parse(status_byte, iter)?))
}
FILE_META_EVENT => {
trace!("I peeked at {:#x}, a MetaEvent!", status_byte);
Ok(Event::Meta(MetaEvent::parse(iter)?))
}
_ => {
trace!(
"I peeked at {:#x}, neither a SysEx nor a MetaEvent, it must be a MIDI Message!",
status_byte
);
Ok(Event::Midi(Message::parse(iter)?))
}
}
}
pub(crate) fn write<W: Write>(&self, w: &mut Scribe<W>) -> LibResult<()> {
match self {
Event::Midi(md) => md.write(w),
Event::Sysex(sx) => sx.write(w),
Event::Meta(mt) => mt.write(w),
}
}
}
#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub struct TrackEvent {
delta_time: u32,
event: Event,
}
impl TrackEvent {
pub fn new(delta_time: u32, event: Event) -> Self {
Self { delta_time, event }
}
pub fn delta_time(&self) -> u32 {
self.delta_time
}
pub fn event(&self) -> &Event {
&self.event
}
pub(crate) fn is_end(&self) -> bool {
matches!(&self.event, Event::Meta(meta) if matches!(meta, MetaEvent::EndOfTrack))
}
pub(crate) fn parse<R: Read>(iter: &mut ByteIter<R>) -> LibResult<Self> {
let delta_time = iter.read_vlq_u32().context(io!())?;
trace!("delta_time {}", delta_time);
let event = Event::parse(iter)?;
Ok(Self { delta_time, event })
}
pub(crate) fn write<W: Write>(&self, w: &mut Scribe<W>) -> LibResult<()> {
let delta = Vlq::new(self.delta_time).to_bytes();
w.write_all(&delta).context(wr!())?;
self.event.write(w)
}
}