#![forbid(unsafe_code)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
use alloc::{string::String, vec::Vec};
mod parser;
mod player;
mod timing;
mod writer;
pub use parser::parse;
pub use player::SmfPlayer;
pub use timing::{TempoMap, ticks_to_seconds};
pub use writer::write as write_smf;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SmfFormat {
SingleTrack = 0,
MultiTrack = 1,
MultiSong = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Division {
TicksPerBeat(u16),
Smpte { fps: u8, subframes: u8 },
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SmfFile {
pub format: SmfFormat,
pub division: Division,
pub tracks: Vec<SmfTrack>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SmfTrack {
pub name: Option<String>,
pub events: Vec<TrackEvent>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TrackEvent {
pub delta_ticks: u32,
pub event: SmfEvent,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SmfEvent {
Midi(oxisound_core::MidiMessage),
Tempo(u32),
TimeSignature {
numerator: u8,
denominator_pow2: u8,
clocks_per_click: u8,
notated_32nds_per_beat: u8,
},
KeySignature {
sharps_flats: i8,
is_minor: bool,
},
TrackName(String),
EndOfTrack,
UnknownMeta {
meta_type: u8,
data: Vec<u8>,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SmfError(pub String);
impl core::fmt::Display for SmfError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "SMF parse error: {}", self.0)
}
}
#[cfg(feature = "std")]
impl std::error::Error for SmfError {}