#![doc = r#"
Contains types that deal with file ['MetaMessage']s
"#]
mod tempo;
use num_enum::TryFromPrimitive;
pub use tempo::*;
mod time_signature;
pub use time_signature::*;
mod key_signature;
pub use key_signature::*;
mod text;
pub use text::*;
use crate::prelude::*;
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum MetaMessage<'a> {
TrackNumber(Bytes<'a>),
Text(BytesText<'a>),
Copyright(BytesText<'a>),
TrackName(BytesText<'a>),
InstrumentName(BytesText<'a>),
Lyric(BytesText<'a>),
Marker(BytesText<'a>),
CuePoint(Bytes<'a>),
ProgramName(BytesText<'a>),
DeviceName(BytesText<'a>),
MidiChannel(Channel),
MidiPort(u8),
EndOfTrack,
Tempo(Tempo),
SmpteOffset(&'a [u8]),
TimeSignature(TimeSignature<'a>),
KeySignature(KeySignature<'a>),
SequencerSpecific(Bytes<'a>),
Unknown(u8, Bytes<'a>),
}
impl<'a> MetaMessage<'a> {
pub(crate) fn read<'slc, 'r, R>(reader: &'r mut Reader<R>) -> ReadResult<Self>
where
R: MidiSource<'slc>,
'slc: 'a,
{
let type_byte = reader.read_next()?;
let data = reader.read_varlen_slice()?;
Ok(match type_byte {
0x00 => MetaMessage::TrackNumber(data),
0x01 => MetaMessage::Text(BytesText::new_from_bytes(data)?),
0x02 => MetaMessage::Copyright(BytesText::new_from_bytes(data)?),
0x03 => MetaMessage::TrackName(BytesText::new_from_bytes(data)?),
0x04 => MetaMessage::InstrumentName(BytesText::new_from_bytes(data)?),
0x05 => MetaMessage::Lyric(BytesText::new_from_bytes(data)?),
0x06 => MetaMessage::Marker(BytesText::new_from_bytes(data)?),
0x07 => MetaMessage::CuePoint(data),
0x08 => MetaMessage::ProgramName(BytesText::new_from_bytes(data)?),
0x09 => MetaMessage::DeviceName(BytesText::new_from_bytes(data)?),
0x20 => {
if data.len() != 1 {
return Err(inv_data(
reader,
format!(
"Varlen is invalid for this channel (should be 1, is {}",
data.len()
),
));
}
let c = data.first().unwrap();
MetaMessage::MidiChannel(Channel::try_from_primitive(*c)?)
}
0x21 => {
if data.len() != 1 {
return Err(inv_data(
reader,
format!("Varlen is invalid for port (should be 1, is {}", data.len()),
));
}
let port = reader.read_next()?;
MetaMessage::MidiPort(port)
}
0x2F => MetaMessage::EndOfTrack,
0x51 => {
MetaMessage::Tempo(Tempo::new_from_bytes(data))
}
0x54 => {
todo!("implement SMTPE")
}
0x58 if data.len() >= 4 => {
if data.len() != 4 {
return Err(inv_data(
reader,
format!(
"Varlen is invalid for time signature (should be 4, is {}",
data.len()
),
));
}
MetaMessage::TimeSignature(TimeSignature::new_from_bytes(data.try_into().unwrap()))
}
0x59 => {
if data.len() != 2 {
return Err(inv_data(
reader,
format!(
"Varlen is invalid for key signature (should be 2, is {}",
data.len()
),
));
}
MetaMessage::KeySignature(KeySignature::new_from_bytes(data.try_into().unwrap()))
}
0x7F => MetaMessage::SequencerSpecific(data),
_ => MetaMessage::Unknown(type_byte, data),
})
}
pub fn adjust_track_info(self, info: &mut TrackInfo<'a>) {
use MetaMessage::*;
match self {
TrackName(name) => {
info.name = Some(name);
}
DeviceName(device) => info.device = Some(device),
MidiChannel(channel) => info.channel = Some(channel),
Tempo(tempo) => info.tempo = tempo,
_ => {}
}
}
}