1#![forbid(unsafe_code)]
22#![cfg_attr(not(feature = "std"), no_std)]
23extern crate alloc;
24
25use alloc::{string::String, vec::Vec};
26
27mod parser;
28mod player;
29mod timing;
30mod writer;
31
32pub use parser::parse;
33pub use player::SmfPlayer;
34pub use timing::{TempoMap, ticks_to_seconds};
35pub use writer::write as write_smf;
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
40pub enum SmfFormat {
41 SingleTrack = 0,
42 MultiTrack = 1,
43 MultiSong = 2,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
49pub enum Division {
50 TicksPerBeat(u16),
51 Smpte { fps: u8, subframes: u8 },
52}
53
54#[derive(Debug, Clone)]
56#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
57pub struct SmfFile {
58 pub format: SmfFormat,
59 pub division: Division,
60 pub tracks: Vec<SmfTrack>,
61}
62
63#[derive(Debug, Clone)]
65#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
66pub struct SmfTrack {
67 pub name: Option<String>,
68 pub events: Vec<TrackEvent>,
69}
70
71#[derive(Debug, Clone)]
73#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
74pub struct TrackEvent {
75 pub delta_ticks: u32,
76 pub event: SmfEvent,
77}
78
79#[derive(Debug, Clone)]
81#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82pub enum SmfEvent {
83 Midi(oxisound_core::MidiMessage),
85 Tempo(u32),
87 TimeSignature {
88 numerator: u8,
89 denominator_pow2: u8,
91 clocks_per_click: u8,
92 notated_32nds_per_beat: u8,
93 },
94 KeySignature {
95 sharps_flats: i8,
97 is_minor: bool,
98 },
99 TrackName(String),
100 EndOfTrack,
101 UnknownMeta {
103 meta_type: u8,
104 data: Vec<u8>,
105 },
106}
107
108#[derive(Debug, Clone, PartialEq, Eq)]
110#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
111pub struct SmfError(pub String);
112
113impl core::fmt::Display for SmfError {
114 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115 write!(f, "SMF parse error: {}", self.0)
116 }
117}
118
119#[cfg(feature = "std")]
120impl std::error::Error for SmfError {}