use crate::byte_iter::ByteIter;
use crate::core::vlq::Vlq;
use crate::core::{Channel, Clocks, DurationName, PortValue};
use crate::error::{Context, Result};
use crate::scribe::Scribe;
use crate::Text;
use std::convert::TryFrom;
use std::io::{Read, Write};
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, Default)]
pub enum MetaEvent {
SequenceNumber(u16),
OtherText(Text),
Copyright(Text),
TrackName(Text),
InstrumentName(Text),
Lyric(Text),
Marker(Text),
CuePoint(Text),
ProgramName(Text),
DeviceName(Text),
MidiChannelPrefix(Channel),
#[default]
EndOfTrack,
SetTempo(MicrosecondsPerQuarter),
SmpteOffset(SmpteOffsetValue),
TimeSignature(TimeSignatureValue),
KeySignature(KeySignatureValue),
Sequencer(Vec<u8>),
Port(PortValue),
Unknown(UnknownMetaEvent),
}
impl MetaEvent {
pub(crate) fn parse<R: Read>(iter: &mut ByteIter<R>) -> Result<Self> {
iter.read_expect(0xff).context(io!())?;
let meta_type = iter.read_or_die().context(io!())?;
if meta_type >= 0x80 {
invalid_file!("meta event type {:#04X} is not less than 128", meta_type);
}
let length = iter.read_vlq_u32().context(io!())?;
match (meta_type, length) {
(META_SEQUENCE_NUM, len) if len == LEN_META_SEQUENCE_NUM as u32 => {
Ok(MetaEvent::SequenceNumber(iter.read_u16().context(io!())?))
}
(META_TEXT..=META_DEVICE_NAME, _) => MetaEvent::parse_text(iter, meta_type, length),
(META_CHAN_PREFIX, len) if len == LEN_META_CHAN_PREFIX as u32 => Ok(
MetaEvent::MidiChannelPrefix(Channel::new(iter.read_or_die().context(io!())?)),
),
(META_END_OF_TRACK, 0) => Ok(MetaEvent::EndOfTrack),
(META_SET_TEMPO, len) if len == LEN_META_SET_TEMPO as u32 => {
Ok(MetaEvent::SetTempo(MicrosecondsPerQuarter::parse(iter)?))
}
(META_SMTPE_OFFSET, len) if len == LEN_META_SMTPE_OFFSET as u32 => {
Ok(MetaEvent::SmpteOffset(SmpteOffsetValue::parse(iter)?))
}
(META_TIME_SIG, len) if len == LEN_META_TIME_SIG as u32 => {
Ok(MetaEvent::TimeSignature(TimeSignatureValue::parse(iter)?))
}
(META_KEY_SIG, len) if len == LEN_META_KEY_SIG as u32 => {
Ok(MetaEvent::KeySignature(KeySignatureValue::parse(iter)?))
}
(META_SEQ_SPECIFIC, _) => Ok(MetaEvent::Sequencer(
iter.read_n(length as usize).context(io!())?,
)),
(META_PORT, 1) => Ok(MetaEvent::Port(PortValue::new(
iter.read_or_die().context(io!())?,
))),
_ => {
let data = iter.read_n(length as usize).context(io!())?;
Ok(MetaEvent::Unknown(UnknownMetaEvent { meta_type, data }))
}
}
}
pub(crate) fn write<W: Write>(&self, w: &mut Scribe<W>) -> Result<()> {
w.write_all(&[0xff]).context(wr!())?;
match self {
MetaEvent::SequenceNumber(value) => {
write_u8!(w, META_SEQUENCE_NUM)?;
write_u8!(w, LEN_META_SEQUENCE_NUM)?;
w.write_all(&value.to_be_bytes()).context(wr!())
}
MetaEvent::OtherText(s) => write_text(w, 0x01, s),
MetaEvent::Copyright(s) => write_text(w, 0x02, s),
MetaEvent::TrackName(s) => write_text(w, 0x03, s),
MetaEvent::InstrumentName(s) => write_text(w, 0x04, s),
MetaEvent::Lyric(s) => write_text(w, 0x05, s),
MetaEvent::Marker(s) => write_text(w, 0x06, s),
MetaEvent::CuePoint(s) => write_text(w, 0x07, s),
MetaEvent::ProgramName(s) => write_text(w, 0x08, s),
MetaEvent::DeviceName(s) => write_text(w, 0x09, s),
MetaEvent::MidiChannelPrefix(channel) => {
write_u8!(w, META_CHAN_PREFIX)?;
write_u8!(w, LEN_META_CHAN_PREFIX)?;
write_u8!(w, channel.get())
}
MetaEvent::EndOfTrack => {
write_u8!(w, META_END_OF_TRACK)?;
write_u8!(w, LEN_META_END_OF_TRACK)?;
Ok(())
}
MetaEvent::SetTempo(value) => {
write_u8!(w, META_SET_TEMPO)?;
write_u8!(w, LEN_META_SET_TEMPO)?;
let bytes = u32::to_be_bytes(value.get());
debug_assert_eq!(bytes.len(), 4);
w.write_all(&bytes[1..]).context(wr!())
}
MetaEvent::SmpteOffset(value) => value.write(w),
MetaEvent::TimeSignature(value) => value.write(w),
MetaEvent::KeySignature(value) => value.write(w),
MetaEvent::Sequencer(data) => {
write_u8!(w, META_SEQ_SPECIFIC)?;
let length = u32::try_from(data.len())
.context(ctx!(crate::error::ErrorType::StringTooLong))?;
w.write_all(&Vlq::new(length).to_bytes()).context(wr!())?;
w.write_all(data).context(wr!())
}
MetaEvent::Port(value) => {
write_u8!(w, META_PORT)?;
write_u8!(w, 1)?;
write_u8!(w, value.get())
}
MetaEvent::Unknown(value) => value.write(w),
}
}
pub(crate) fn parse_text<R: Read>(
iter: &mut ByteIter<R>,
text_type: u8,
length: u32,
) -> Result<Self> {
let bytes = iter.read_n(length as usize).context(io!())?;
let s: Text = bytes.into();
match text_type {
META_TEXT => Ok(MetaEvent::OtherText(s)),
META_COPYRIGHT => Ok(MetaEvent::Copyright(s)),
META_TRACK_NAME => Ok(MetaEvent::TrackName(s)),
META_INSTR_NAME => Ok(MetaEvent::InstrumentName(s)),
META_LYRIC => Ok(MetaEvent::Lyric(s)),
META_MARKER => Ok(MetaEvent::Marker(s)),
META_CUE_POINT => Ok(MetaEvent::CuePoint(s)),
META_PROG_NAME => Ok(MetaEvent::ProgramName(s)),
META_DEVICE_NAME => Ok(MetaEvent::DeviceName(s)),
_ => invalid_file!("unrecognized byte {:#04X}", text_type),
}
}
}
#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub struct UnknownMetaEvent {
pub(crate) meta_type: u8,
pub(crate) data: Vec<u8>,
}
impl UnknownMetaEvent {
pub fn new(meta_type: u8, data: Vec<u8>) -> Result<Self> {
ensure!(meta_type < 0x80, ctx!(crate::error::ErrorType::Other));
Ok(Self { meta_type, data })
}
pub fn meta_type(&self) -> u8 {
self.meta_type
}
pub fn data(&self) -> &[u8] {
&self.data
}
pub(crate) fn write<W: Write>(&self, w: &mut Scribe<W>) -> Result<()> {
write_u8!(w, self.meta_type)?;
let length =
u32::try_from(self.data.len()).context(ctx!(crate::error::ErrorType::StringTooLong))?;
w.write_all(&Vlq::new(length).to_bytes()).context(wr!())?;
w.write_all(&self.data).context(wr!())?;
Ok(())
}
}
fn write_text<W: Write>(w: &mut Scribe<W>, text_type: u8, text: &Text) -> Result<()> {
w.write_all(&text_type.to_be_bytes()).context(wr!())?;
let bytes = text.as_bytes();
let size_u32 =
u32::try_from(bytes.len()).context(ctx!(crate::error::ErrorType::StringTooLong))?;
let size = Vlq::new(size_u32).to_bytes();
w.write_all(&size).context(wr!())?;
w.write_all(bytes).context(wr!())?;
Ok(())
}
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub struct SmpteOffsetValue {
pub(crate) hr: u8,
pub(crate) mn: u8,
pub(crate) se: u8,
pub(crate) fr: u8,
pub(crate) ff: u8,
}
impl SmpteOffsetValue {
pub fn new(hr: u8, mn: u8, se: u8, fr: u8, ff: u8) -> Self {
Self { hr, mn, se, fr, ff }
}
pub fn hr(&self) -> u8 {
self.hr
}
pub fn mn(&self) -> u8 {
self.mn
}
pub fn se(&self) -> u8 {
self.se
}
pub fn fr(&self) -> u8 {
self.fr
}
pub fn ff(&self) -> u8 {
self.ff
}
pub(crate) fn parse<R: Read>(iter: &mut ByteIter<R>) -> Result<Self> {
Ok(Self {
hr: iter.read_or_die().context(io!())?,
mn: iter.read_or_die().context(io!())?,
se: iter.read_or_die().context(io!())?,
fr: iter.read_or_die().context(io!())?,
ff: iter.read_or_die().context(io!())?,
})
}
pub(crate) fn write<W: Write>(&self, w: &mut Scribe<W>) -> Result<()> {
write_u8!(w, META_SMTPE_OFFSET)?;
write_u8!(w, LEN_META_SMTPE_OFFSET)?;
write_u8!(w, self.hr)?;
write_u8!(w, self.mn)?;
write_u8!(w, self.se)?;
write_u8!(w, self.fr)?;
write_u8!(w, self.ff)?;
Ok(())
}
}
pub(crate) const META_SEQUENCE_NUM: u8 = 0x00;
pub(crate) const META_TEXT: u8 = 0x01;
pub(crate) const META_COPYRIGHT: u8 = 0x02;
pub(crate) const META_TRACK_NAME: u8 = 0x03;
pub(crate) const META_INSTR_NAME: u8 = 0x04;
pub(crate) const META_LYRIC: u8 = 0x05;
pub(crate) const META_MARKER: u8 = 0x06;
pub(crate) const META_CUE_POINT: u8 = 0x07;
pub(crate) const META_PROG_NAME: u8 = 0x08;
pub(crate) const META_DEVICE_NAME: u8 = 0x09;
pub(crate) const META_CHAN_PREFIX: u8 = 0x20;
pub(crate) const META_END_OF_TRACK: u8 = 0x2f;
pub(crate) const META_SET_TEMPO: u8 = 0x51;
pub(crate) const META_SMTPE_OFFSET: u8 = 0x54;
pub(crate) const META_TIME_SIG: u8 = 0x58;
pub(crate) const META_KEY_SIG: u8 = 0x59;
pub(crate) const META_SEQ_SPECIFIC: u8 = 0x7f;
pub(crate) const META_PORT: u8 = 0x21;
pub(crate) const LEN_META_SEQUENCE_NUM: u8 = 2;
pub(crate) const LEN_META_CHAN_PREFIX: u8 = 1;
pub(crate) const LEN_META_END_OF_TRACK: u8 = 0;
pub(crate) const LEN_META_SET_TEMPO: u8 = 3;
pub(crate) const LEN_META_SMTPE_OFFSET: u8 = 5;
pub(crate) const LEN_META_TIME_SIG: u8 = 4;
pub(crate) const LEN_META_KEY_SIG: u8 = 2;
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub struct TimeSignatureValue {
numerator: u8,
denominator: DurationName,
click: Clocks,
tpq: u8,
}
impl TimeSignatureValue {
pub fn new(numerator: u8, denominator: DurationName, click: Clocks) -> Result<Self> {
ensure!(numerator > 0, ctx!(crate::error::ErrorType::Other));
Ok(Self {
numerator,
denominator,
click,
..Self::default()
})
}
pub fn numerator(&self) -> u8 {
self.numerator
}
pub fn denominator(&self) -> DurationName {
self.denominator
}
pub fn click(&self) -> Clocks {
self.click
}
pub(crate) fn parse<R: Read>(iter: &mut ByteIter<R>) -> Result<Self> {
Ok(Self {
numerator: iter.read_or_die().context(io!())?,
denominator: DurationName::from_u8(iter.read_or_die().context(io!())?)?,
click: Clocks::from_u8(iter.read_or_die().context(io!())?),
tpq: iter.read_or_die().context(io!())?,
})
}
pub(crate) fn write<W: Write>(&self, w: &mut Scribe<W>) -> Result<()> {
write_u8!(w, META_TIME_SIG)?;
write_u8!(w, LEN_META_TIME_SIG)?;
write_u8!(w, self.numerator)?;
write_u8!(w, self.denominator as u8)?;
write_u8!(w, self.click.to_u8())?;
write_u8!(w, self.tpq)?;
Ok(())
}
}
clamp!(
KeyAccidentals,
i8,
-7,
7,
0,
pub
);
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, Default)]
pub enum KeyMode {
#[default]
Major,
Minor,
}
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub struct KeySignatureValue {
accidentals: KeyAccidentals,
mode: KeyMode,
}
impl KeySignatureValue {
pub fn new(accidentals: KeyAccidentals, mode: KeyMode) -> Self {
Self { accidentals, mode }
}
pub fn accidentals(&self) -> KeyAccidentals {
self.accidentals
}
pub fn mode(&self) -> KeyMode {
self.mode
}
pub(crate) fn parse<R: Read>(iter: &mut ByteIter<R>) -> Result<Self> {
let raw_accidentals_byte = iter.read_or_die().context(io!())?;
let casted_accidentals = raw_accidentals_byte as i8;
Ok(Self {
accidentals: casted_accidentals.into(),
mode: match iter.read_or_die().context(io!())? {
1 => KeyMode::Minor,
_ => KeyMode::Major,
},
})
}
pub(crate) fn write<W: Write>(&self, w: &mut Scribe<W>) -> Result<()> {
write_u8!(w, META_KEY_SIG)?;
write_u8!(w, LEN_META_KEY_SIG)?;
write_u8!(w, self.accidentals.get() as u8)?;
write_u8!(w, self.mode as u8)?;
Ok(())
}
}
pub(crate) const DEFAULT_MICROSECONDS_PER_QUARTER: u32 = 500_000;
pub(crate) const MAX_24BIT_UINT_VALUE: u32 = 16_777_215;
clamp!(
MicrosecondsPerQuarter,
u32,
1,
MAX_24BIT_UINT_VALUE,
DEFAULT_MICROSECONDS_PER_QUARTER,
pub
);
impl MicrosecondsPerQuarter {
pub(crate) fn parse<R: Read>(iter: &mut ByteIter<R>) -> Result<Self> {
let bytes = iter.read_n(LEN_META_SET_TEMPO as usize).context(io!())?;
let beu32 = [0u8, bytes[0], bytes[1], bytes[2]];
let parsed_number = u32::from_be_bytes(beu32);
Ok(MicrosecondsPerQuarter::new(parsed_number))
}
}
clamp!(
QuartersPerMinute,
u8,
1,
u8::MAX,
120,
pub
);