use crate::{
build_status_byte, extract_type_from_status_byte, Channel, ControllerNumber,
FuzzyMessageSuperType, KeyNumber, ShortMessage, ShortMessageType, TimeCodeQuarterFrame, U14,
U7,
};
use derive_more::Display;
#[derive(Clone, Eq, PartialEq, Debug, Display)]
#[display(fmt = "invalid MIDI message bytes")]
pub struct FromBytesError(pub(crate) ());
impl core_error::Error for FromBytesError {}
pub trait ShortMessageFactory: ShortMessage + Sized {
unsafe fn from_bytes_unchecked(bytes: (u8, U7, U7)) -> Self;
fn from_bytes(bytes: (u8, U7, U7)) -> Result<Self, FromBytesError> {
extract_type_from_status_byte(bytes.0).map_err(|_| FromBytesError(()))?;
Ok(unsafe { Self::from_bytes_unchecked(bytes) })
}
fn from_other(msg: &impl ShortMessage) -> Self {
msg.to_other()
}
fn channel_message(r#type: ShortMessageType, channel: Channel, data_1: U7, data_2: U7) -> Self {
assert_eq!(r#type.super_type(), FuzzyMessageSuperType::Channel);
unsafe {
Self::from_bytes_unchecked((build_status_byte(r#type.into(), channel), data_1, data_2))
}
}
fn system_common_message(r#type: ShortMessageType, data_1: U7, data_2: U7) -> Self {
assert_eq!(r#type.super_type(), FuzzyMessageSuperType::SystemCommon);
unsafe { Self::from_bytes_unchecked((r#type.into(), data_1, data_2)) }
}
fn system_real_time_message(r#type: ShortMessageType) -> Self {
assert_eq!(r#type.super_type(), FuzzyMessageSuperType::SystemRealTime);
unsafe { Self::from_bytes_unchecked((r#type.into(), U7::MIN, U7::MIN)) }
}
fn note_on(channel: Channel, key_number: KeyNumber, velocity: U7) -> Self {
unsafe {
Self::from_bytes_unchecked((
build_status_byte(ShortMessageType::NoteOn.into(), channel),
key_number.into(),
velocity,
))
}
}
fn note_off(channel: Channel, key_number: KeyNumber, velocity: U7) -> Self {
unsafe {
Self::from_bytes_unchecked((
build_status_byte(ShortMessageType::NoteOff.into(), channel),
key_number.into(),
velocity,
))
}
}
fn control_change(
channel: Channel,
controller_number: ControllerNumber,
control_value: U7,
) -> Self {
unsafe {
Self::from_bytes_unchecked((
build_status_byte(ShortMessageType::ControlChange.into(), channel),
controller_number.into(),
control_value,
))
}
}
fn program_change(channel: Channel, program_number: U7) -> Self {
unsafe {
Self::from_bytes_unchecked((
build_status_byte(ShortMessageType::ProgramChange.into(), channel),
program_number,
U7::MIN,
))
}
}
fn polyphonic_key_pressure(
channel: Channel,
key_number: KeyNumber,
pressure_amount: U7,
) -> Self {
unsafe {
Self::from_bytes_unchecked((
build_status_byte(ShortMessageType::PolyphonicKeyPressure.into(), channel),
key_number.into(),
pressure_amount,
))
}
}
fn channel_pressure(channel: Channel, pressure_amount: U7) -> Self {
unsafe {
Self::from_bytes_unchecked((
build_status_byte(ShortMessageType::ChannelPressure.into(), channel),
pressure_amount,
U7::MIN,
))
}
}
fn pitch_bend_change(channel: Channel, pitch_bend_value: U14) -> Self {
unsafe {
Self::from_bytes_unchecked((
build_status_byte(ShortMessageType::PitchBendChange.into(), channel),
U7((pitch_bend_value.get() & 0x7f) as u8),
U7((pitch_bend_value.get() >> 7) as u8),
))
}
}
fn system_exclusive_start() -> Self {
unsafe {
Self::from_bytes_unchecked((
ShortMessageType::SystemExclusiveStart.into(),
U7::MIN,
U7::MIN,
))
}
}
fn time_code_quarter_frame(frame: TimeCodeQuarterFrame) -> Self {
unsafe {
Self::from_bytes_unchecked((
ShortMessageType::TimeCodeQuarterFrame.into(),
frame.into(),
U7::MIN,
))
}
}
fn song_position_pointer(position: U14) -> Self {
unsafe {
Self::from_bytes_unchecked((
ShortMessageType::SongPositionPointer.into(),
U7((position.get() & 0x7f) as u8),
U7((position.get() >> 7) as u8),
))
}
}
fn song_select(song_number: U7) -> Self {
unsafe {
Self::from_bytes_unchecked((ShortMessageType::SongSelect.into(), song_number, U7::MIN))
}
}
fn tune_request() -> Self {
unsafe {
Self::from_bytes_unchecked((ShortMessageType::TuneRequest.into(), U7::MIN, U7::MIN))
}
}
fn system_exclusive_end() -> Self {
unsafe {
Self::from_bytes_unchecked((
ShortMessageType::SystemExclusiveEnd.into(),
U7::MIN,
U7::MIN,
))
}
}
fn timing_clock() -> Self {
unsafe {
Self::from_bytes_unchecked((ShortMessageType::TimingClock.into(), U7::MIN, U7::MIN))
}
}
fn start() -> Self {
unsafe { Self::from_bytes_unchecked((ShortMessageType::Start.into(), U7::MIN, U7::MIN)) }
}
fn r#continue() -> Self {
unsafe { Self::from_bytes_unchecked((ShortMessageType::Continue.into(), U7::MIN, U7::MIN)) }
}
fn stop() -> Self {
unsafe { Self::from_bytes_unchecked((ShortMessageType::Stop.into(), U7::MIN, U7::MIN)) }
}
fn active_sensing() -> Self {
unsafe {
Self::from_bytes_unchecked((ShortMessageType::ActiveSensing.into(), U7::MIN, U7::MIN))
}
}
fn system_reset() -> Self {
unsafe {
Self::from_bytes_unchecked((ShortMessageType::SystemReset.into(), U7::MIN, U7::MIN))
}
}
}